1
/* $Id: transport.h 3553 2011-05-05 06:14:19Z nanang $ */
3
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
#ifndef __PJMEDIA_TRANSPORT_H__
21
#define __PJMEDIA_TRANSPORT_H__
25
* @file transport.h Media Transport Interface
26
* @brief Transport interface.
29
#include <pjmedia/types.h>
30
#include <pjmedia/errno.h>
33
* @defgroup PJMEDIA_TRANSPORT Media Transport
36
* The media transport (#pjmedia_transport) is the object to send and
37
* receive media packets over the network. The media transport interface
38
* allows the library to be extended to support different types of
39
* transports to send and receive packets.
41
* The media transport is declared as #pjmedia_transport "class", which
42
* declares "interfaces" to use the class in #pjmedia_transport_op
43
* structure. For the user of the media transport (normally the user of
44
* media transport is media stream, see \ref PJMED_STRM), these transport
45
* "methods" are wrapped with API such as #pjmedia_transport_attach(),
46
* so it should not need to call the function pointer inside
47
* #pjmedia_transport_op directly.
49
* The connection between \ref PJMED_STRM and media transport is shown in
52
\image html media-transport.PNG
55
* \section PJMEDIA_TRANSPORT_H_USING Basic Media Transport Usage
57
* The media transport's life-cycle normally follows the following stages.
59
* \subsection PJMEDIA_TRANSPORT_H_CREATE Creating the Media Transport
61
* Application creates the media transport when it needs to establish
62
* media session to remote peer. The media transport is created using
63
* specific function to create that particular transport; for example,
64
* for UDP media transport, it is created with #pjmedia_transport_udp_create()
65
* or #pjmedia_transport_udp_create2() functions. Different media
66
* transports will provide different API to create those transports.
68
* Alternatively, application may create pool of media transports when
69
* it is first started up. Using this approach probably is better, since
70
* application has to specify the RTP port when sending the initial
71
* session establishment request (e.g. SIP INVITE request), thus if
72
* application only creates the media transport later when media is to be
73
* established (normally when 200/OK is received, or when 18x is received
74
* for early media), there is a possibility that the particular RTP
75
* port might have been occupied by other programs. Also it is more
76
* efficient since sockets don't need to be closed and re-opened between
80
* \subsection PJMEDIA_TRANSPORT_H_ATTACH Attaching and Using the Media Transport.
82
* Application specifies the media transport instance when creating
83
* the media session (#pjmedia_session_create()). Alternatively, it
84
* may create the media stream directly with #pjmedia_stream_create()
85
* and specify the transport instance in the argument. (Note: media
86
* session is a high-level abstraction for media communications between
87
* two endpoints, and it may contain more than one media streams, for
88
* example, an audio stream and a video stream).
90
* When stream is created, it will "attach" itself to the media
91
* transport by calling #pjmedia_transport_attach(), which is a thin
92
* wrapper which calls "attach()" method of the media transport's
93
* "virtual function pointer" (#pjmedia_transport_op). Among other things,
94
* the stream specifies two callback functions to the transport: one
95
* callback function will be called by transport when it receives RTP
96
* packet, and another callback for incoming RTCP packet. The
97
* #pjmedia_transport_attach() function also establish the destination
98
* of the outgoing RTP and RTCP packets.
100
* When the stream needs to send outgoing RTP/RTCP packets, it will
101
* call #pjmedia_transport_send_rtp() and #pjmedia_transport_send_rtcp()
102
* of the media transport API, which is a thin wrapper to call send_rtp()
103
* and send_rtcp() methods in the media transport's "virtual function
104
* pointer" (#pjmedia_transport_op).
106
* When the stream is destroyed, it will "detach" itself from
107
* the media transport by calling #pjmedia_transport_detach(), which is
108
* a thin wrapper which calls "detach()" method of the media transport's
109
* "virtual function pointer" (#pjmedia_transport_op). After the transport
110
* is detached from its user (the stream), it will no longer report
111
* incoming RTP/RTCP packets to the stream, and it will refuse to send
112
* outgoing packets since the destination has been cleared.
115
* \subsection PJMEDIA_TRANSPORT_H_REUSE Reusing the Media Transport.
117
* After transport has been detached, application may re-attach the
118
* transport to another stream if it wants to. Detaching and re-attaching
119
* media transport may be preferable than closing and re-opening the
120
* transport, since it is more efficient (sockets don't need to be
121
* closed and re-opened). However it is up to the application to choose
122
* which method is most suitable for its uses.
125
* \subsection PJMEDIA_TRANSPORT_H_DESTROY Destroying the Media Transport.
127
* Finally if application no longer needs the media transport, it will
128
* call #pjmedia_transport_close() function, which is thin wrapper which
129
* calls "destroy()" method of the media transport's "virtual function
130
* pointer" (#pjmedia_transport_op). This function releases
131
* all resources used by the transport, such as sockets and memory.
134
* \section offer_answer Interaction with SDP Offer/Answer
136
For basic UDP transport, the \ref PJMEDIA_TRANSPORT_H_USING above is
137
sufficient to use the media transport. However, more complex media
138
transports such as \ref PJMEDIA_TRANSPORT_SRTP and \ref
139
PJMEDIA_TRANSPORT_ICE requires closer interactions with SDP offer and
142
The media transports can interact with the SDP offer/answer via
144
- #pjmedia_transport_media_create(), to initialize the media transport
145
for new media session,
146
- #pjmedia_transport_encode_sdp(), to encode SDP offer or answer,
147
- #pjmedia_transport_media_start(), to activate the settings that
148
have been negotiated by SDP offer answer, and
149
- #pjmedia_transport_media_stop(), to deinitialize the media transport
150
and reset the transport to its idle state.
152
The usage of these API in the context of SDP offer answer will be
155
\subsection media_create Initializing Transport for New Session
157
Application must call #pjmedia_transport_media_create() before using
158
the transport for a new session.
160
\subsection creat_oa Creating SDP Offer and Answer
162
The #pjmedia_transport_encode_sdp() is used to put additional information
163
from the transport to the local SDP, before the SDP is sent and negotiated
166
When creating an offer, call #pjmedia_transport_encode_sdp() with
167
local SDP (and NULL as \a rem_sdp). The media transport will add the
168
relevant attributes in the local SDP. Application then gives the local
169
SDP to the invite session to be sent to remote agent.
171
When creating an answer, also call #pjmedia_transport_encode_sdp(),
172
but this time specify both local and remote SDP to the function. The
173
media transport will once again modify the local SDP and add relevant
174
attributes to the local SDP, if the appropriate attributes related to
175
the transport functionality are present in remote offer. The remote
176
SDP does not contain the relevant attributes, then the specific transport
177
functionality will not be activated for the session.
179
The #pjmedia_transport_encode_sdp() should also be called when application
180
sends subsequent SDP offer or answer. The media transport will encode
181
the appropriate attributes based on the state of the session.
183
\subsection media_start Offer/Answer Completion
185
Once both local and remote SDP have been negotiated by the
186
\ref PJMEDIA_SDP_NEG (normally this is part of PJSIP invite session),
187
application should give both local and remote SDP to
188
#pjmedia_transport_media_start() so that the settings are activated
189
for the session. This function should be called for both initial and
190
subsequent SDP negotiation.
192
\subsection media_stop Stopping Transport
194
Once session is stop application must call #pjmedia_transport_media_stop()
195
to deactivate the transport feature. Application may reuse the transport
196
for subsequent media session by repeating the #pjmedia_transport_media_create(),
197
#pjmedia_transport_encode_sdp(), #pjmedia_transport_media_start(), and
198
#pjmedia_transport_media_stop() above.
200
* \section PJMEDIA_TRANSPORT_H_IMPL Implementing Media Transport
202
* To implement a new type of media transport, one needs to "subclass" the
203
* media transport "class" (#pjmedia_transport) by providing the "methods"
204
* in the media transport "interface" (#pjmedia_transport_op), and provides
205
* a function to create this new type of transport (similar to
206
* #pjmedia_transport_udp_create() function).
208
* The media transport is expected to run indepently, that is there should
209
* be no polling like function to poll the transport for incoming RTP/RTCP
210
* packets. This normally can be done by registering the media sockets to
211
* the media endpoint's IOQueue, which allows the transport to be notified
212
* when incoming packet has arrived.
214
* Alternatively, media transport may utilize thread(s) internally to wait
215
* for incoming packets. The thread then will call the appropriate RTP or
216
* RTCP callback provided by its user (stream) whenever packet is received.
217
* If the transport's user is a stream, then the callbacks provided by the
218
* stream will be thread-safe, so the transport may call these callbacks
219
* without having to serialize the access with some mutex protection. But
220
* the media transport may still have to protect its internal data with
221
* mutex protection, since it may be called by application's thread (for
222
* example, to send RTP/RTCP packets).
227
#include <pjmedia/sdp.h>
233
* Forward declaration for media transport.
235
typedef struct pjmedia_transport pjmedia_transport;
238
* Forward declaration for media transport info.
240
typedef struct pjmedia_transport_info pjmedia_transport_info;
243
* This enumeration specifies the general behaviour of media processing
245
typedef enum pjmedia_tranport_media_option
248
* When this flag is specified, the transport will not perform media
249
* transport validation, this is useful when transport is stacked with
250
* other transport, for example when transport UDP is stacked under
251
* transport SRTP, media transport validation only need to be done by
254
PJMEDIA_TPMED_NO_TRANSPORT_CHECKING = 1
256
} pjmedia_tranport_media_option;
260
* This structure describes the operations for the stream transport.
262
struct pjmedia_transport_op
265
* Get media socket info from the specified transport.
267
* Application should call #pjmedia_transport_get_info() instead
269
pj_status_t (*get_info)(pjmedia_transport *tp,
270
pjmedia_transport_info *info);
273
* This function is called by the stream when the transport is about
274
* to be used by the stream for the first time, and it tells the transport
275
* about remote RTP address to send the packet and some callbacks to be
276
* called for incoming packets.
278
* Application should call #pjmedia_transport_attach() instead of
279
* calling this function directly.
281
pj_status_t (*attach)(pjmedia_transport *tp,
283
const pj_sockaddr_t *rem_addr,
284
const pj_sockaddr_t *rem_rtcp,
286
void (*rtp_cb)(void *user_data,
289
void (*rtcp_cb)(void *user_data,
294
* This function is called by the stream when the stream no longer
295
* needs the transport (normally when the stream is about to be closed).
296
* After the transport is detached, it will ignore incoming
297
* RTP/RTCP packets, and will refuse to send outgoing RTP/RTCP packets.
298
* Application may re-attach the media transport to another transport
299
* user (e.g. stream) after the transport has been detached.
301
* Application should call #pjmedia_transport_detach() instead of
302
* calling this function directly.
304
void (*detach)(pjmedia_transport *tp,
308
* This function is called by the stream to send RTP packet using the
311
* Application should call #pjmedia_transport_send_rtp() instead of
312
* calling this function directly.
314
pj_status_t (*send_rtp)(pjmedia_transport *tp,
319
* This function is called by the stream to send RTCP packet using the
322
* Application should call #pjmedia_transport_send_rtcp() instead of
323
* calling this function directly.
325
pj_status_t (*send_rtcp)(pjmedia_transport *tp,
330
* This function is called by the stream to send RTCP packet using the
331
* transport with destination address other than default specified in
332
* #pjmedia_transport_attach().
334
* Application should call #pjmedia_transport_send_rtcp2() instead of
335
* calling this function directly.
337
pj_status_t (*send_rtcp2)(pjmedia_transport *tp,
338
const pj_sockaddr_t *addr,
344
* Prepare the transport for a new media session.
346
* Application should call #pjmedia_transport_media_create() instead of
347
* calling this function directly.
349
pj_status_t (*media_create)(pjmedia_transport *tp,
352
const pjmedia_sdp_session *remote_sdp,
353
unsigned media_index);
356
* This function is called by application to generate the SDP parts
357
* related to transport type, e.g: ICE, SRTP.
359
* Application should call #pjmedia_transport_encode_sdp() instead of
360
* calling this function directly.
362
pj_status_t (*encode_sdp)(pjmedia_transport *tp,
364
pjmedia_sdp_session *sdp_local,
365
const pjmedia_sdp_session *rem_sdp,
366
unsigned media_index);
369
* This function is called by application to start the transport
370
* based on local and remote SDP.
372
* Application should call #pjmedia_transport_media_start() instead of
373
* calling this function directly.
375
pj_status_t (*media_start) (pjmedia_transport *tp,
377
const pjmedia_sdp_session *sdp_local,
378
const pjmedia_sdp_session *sdp_remote,
379
unsigned media_index);
382
* This function is called by application to stop the transport.
384
* Application should call #pjmedia_transport_media_stop() instead of
385
* calling this function directly.
387
pj_status_t (*media_stop) (pjmedia_transport *tp);
390
* This function can be called to simulate packet lost.
392
* Application should call #pjmedia_transport_simulate_lost() instead of
393
* calling this function directly.
395
pj_status_t (*simulate_lost)(pjmedia_transport *tp,
400
* This function can be called to destroy this transport.
402
* Application should call #pjmedia_transport_close() instead of
403
* calling this function directly.
405
pj_status_t (*destroy)(pjmedia_transport *tp);
410
* @see pjmedia_transport_op.
412
typedef struct pjmedia_transport_op pjmedia_transport_op;
416
* Media transport type.
418
typedef enum pjmedia_transport_type
420
/** Media transport using standard UDP */
421
PJMEDIA_TRANSPORT_TYPE_UDP,
423
/** Media transport using ICE */
424
PJMEDIA_TRANSPORT_TYPE_ICE,
427
* Media transport SRTP, this transport is actually security adapter to be
428
* stacked with other transport to enable encryption on the underlying
431
PJMEDIA_TRANSPORT_TYPE_SRTP,
434
* Start of user defined transport.
436
PJMEDIA_TRANSPORT_TYPE_USER
438
} pjmedia_transport_type;
442
* This structure declares media transport. A media transport is called
443
* by the stream to transmit a packet, and will notify stream when
444
* incoming packet is arrived.
446
struct pjmedia_transport
448
/** Transport name (for logging purpose). */
449
char name[PJ_MAX_OBJ_NAME];
451
/** Transport type. */
452
pjmedia_transport_type type;
454
/** Transport's "virtual" function table. */
455
pjmedia_transport_op *op;
459
* This structure describes storage buffer of transport specific info.
460
* The actual transport specific info contents will be defined by transport
461
* implementation. Note that some transport implementations do not need to
462
* provide specific info, since the general socket info is enough.
464
typedef struct pjmedia_transport_specific_info
467
* Specify media transport type.
469
pjmedia_transport_type type;
472
* Specify storage buffer size of transport specific info.
477
* Storage buffer of transport specific info.
479
char buffer[PJMEDIA_TRANSPORT_SPECIFIC_INFO_MAXSIZE];
481
} pjmedia_transport_specific_info;
485
* This structure describes transport informations, including general
486
* socket information and specific information of single transport or
487
* stacked transports (e.g: SRTP stacked on top of UDP)
489
struct pjmedia_transport_info
492
* General socket info.
494
pjmedia_sock_info sock_info;
497
* Remote address where RTP/RTCP originated from. In case this transport
498
* hasn't ever received packet, the
500
pj_sockaddr src_rtp_name;
501
pj_sockaddr src_rtcp_name;
504
* Specifies number of transport specific info included.
506
unsigned specific_info_cnt;
509
* Buffer storage of transport specific info.
511
pjmedia_transport_specific_info spc_info[PJMEDIA_TRANSPORT_SPECIFIC_INFO_MAXCNT];
517
* Initialize transport info.
519
* @param info Transport info to be initialized.
521
PJ_INLINE(void) pjmedia_transport_info_init(pjmedia_transport_info *info)
523
pj_bzero(&info->sock_info, sizeof(pjmedia_sock_info));
524
info->sock_info.rtp_sock = info->sock_info.rtcp_sock = PJ_INVALID_SOCKET;
525
info->specific_info_cnt = 0;
530
* Get media transport info from the specified transport and all underlying
531
* transports if any. The transport also contains information about socket info
532
* which describes the local address of the transport, and would be needed
533
* for example to fill in the "c=" and "m=" line of local SDP.
535
* @param tp The transport.
536
* @param info Media socket info to be initialized.
538
* @return PJ_SUCCESS on success.
540
PJ_INLINE(pj_status_t) pjmedia_transport_get_info(pjmedia_transport *tp,
541
pjmedia_transport_info *info)
543
if (tp && tp->op && tp->op->get_info)
544
return (*tp->op->get_info)(tp, info);
551
* Attach callbacks to be called on receipt of incoming RTP/RTCP packets.
552
* This is just a simple wrapper which calls <tt>attach()</tt> member of
555
* @param tp The media transport.
556
* @param user_data Arbitrary user data to be set when the callbacks are
558
* @param rem_addr Remote RTP address to send RTP packet to.
559
* @param rem_rtcp Optional remote RTCP address. If the argument is NULL
560
* or if the address is zero, the RTCP address will be
561
* calculated from the RTP address (which is RTP port
563
* @param addr_len Length of the remote address.
564
* @param rtp_cb Callback to be called when RTP packet is received on
566
* @param rtcp_cb Callback to be called when RTCP packet is received on
569
* @return PJ_SUCCESS on success, or the appropriate error code.
571
PJ_INLINE(pj_status_t) pjmedia_transport_attach(pjmedia_transport *tp,
573
const pj_sockaddr_t *rem_addr,
574
const pj_sockaddr_t *rem_rtcp,
576
void (*rtp_cb)(void *user_data,
579
void (*rtcp_cb)(void *usr_data,
583
return tp->op->attach(tp, user_data, rem_addr, rem_rtcp, addr_len,
589
* Detach callbacks from the transport.
590
* This is just a simple wrapper which calls <tt>detach()</tt> member of
591
* the transport. After the transport is detached, it will ignore incoming
592
* RTP/RTCP packets, and will refuse to send outgoing RTP/RTCP packets.
593
* Application may re-attach the media transport to another transport user
594
* (e.g. stream) after the transport has been detached.
596
* @param tp The media transport.
597
* @param user_data User data which must match the previously set value
600
PJ_INLINE(void) pjmedia_transport_detach(pjmedia_transport *tp,
603
tp->op->detach(tp, user_data);
608
* Send RTP packet with the specified media transport. This is just a simple
609
* wrapper which calls <tt>send_rtp()</tt> member of the transport. The
610
* RTP packet will be delivered to the destination address specified in
611
* #pjmedia_transport_attach() function.
613
* @param tp The media transport.
614
* @param pkt The packet to send.
615
* @param size Size of the packet.
617
* @return PJ_SUCCESS on success, or the appropriate error code.
619
PJ_INLINE(pj_status_t) pjmedia_transport_send_rtp(pjmedia_transport *tp,
623
return (*tp->op->send_rtp)(tp, pkt, size);
628
* Send RTCP packet with the specified media transport. This is just a simple
629
* wrapper which calls <tt>send_rtcp()</tt> member of the transport. The
630
* RTCP packet will be delivered to the destination address specified in
631
* #pjmedia_transport_attach() function.
633
* @param tp The media transport.
634
* @param pkt The packet to send.
635
* @param size Size of the packet.
637
* @return PJ_SUCCESS on success, or the appropriate error code.
639
PJ_INLINE(pj_status_t) pjmedia_transport_send_rtcp(pjmedia_transport *tp,
643
return (*tp->op->send_rtcp)(tp, pkt, size);
648
* Send RTCP packet with the specified media transport. This is just a simple
649
* wrapper which calls <tt>send_rtcp2()</tt> member of the transport. The
650
* RTCP packet will be delivered to the destination address specified in
651
* param addr, if addr is NULL, RTCP packet will be delivered to destination
652
* address specified in #pjmedia_transport_attach() function.
654
* @param tp The media transport.
655
* @param addr The destination address.
656
* @param addr_len Length of destination address.
657
* @param pkt The packet to send.
658
* @param size Size of the packet.
660
* @return PJ_SUCCESS on success, or the appropriate error code.
662
PJ_INLINE(pj_status_t) pjmedia_transport_send_rtcp2(pjmedia_transport *tp,
663
const pj_sockaddr_t *addr,
668
return (*tp->op->send_rtcp2)(tp, addr, addr_len, pkt, size);
673
* Prepare the media transport for a new media session, Application must
674
* call this function before starting a new media session using this
677
* This is just a simple wrapper which calls <tt>media_create()</tt> member
680
* @param tp The media transport.
681
* @param sdp_pool Pool object to allocate memory related to SDP
682
* messaging components.
683
* @param options Option flags, from #pjmedia_tranport_media_option
684
* @param rem_sdp Remote SDP if local SDP is an answer, otherwise
685
* specify NULL if SDP is an offer.
686
* @param media_index Media index in SDP.
688
* @return PJ_SUCCESS on success, or the appropriate error code.
690
PJ_INLINE(pj_status_t) pjmedia_transport_media_create(pjmedia_transport *tp,
693
const pjmedia_sdp_session *rem_sdp,
694
unsigned media_index)
696
return (*tp->op->media_create)(tp, sdp_pool, options, rem_sdp,
702
* Put transport specific information into the SDP. This function can be
703
* called to put transport specific information in the initial or
704
* subsequent SDP offer or answer.
706
* This is just a simple wrapper which calls <tt>encode_sdp()</tt> member
709
* @param tp The media transport.
710
* @param sdp_pool Pool object to allocate memory related to SDP
711
* messaging components.
712
* @param sdp The local SDP to be filled in information from the
714
* @param rem_sdp Remote SDP if local SDP is an answer, otherwise
715
* specify NULL if SDP is an offer.
716
* @param media_index Media index in SDP.
718
* @return PJ_SUCCESS on success, or the appropriate error code.
720
PJ_INLINE(pj_status_t) pjmedia_transport_encode_sdp(pjmedia_transport *tp,
722
pjmedia_sdp_session *sdp,
723
const pjmedia_sdp_session *rem_sdp,
724
unsigned media_index)
726
return (*tp->op->encode_sdp)(tp, sdp_pool, sdp, rem_sdp, media_index);
731
* Start the transport session with the settings in both local and remote
732
* SDP. The actual work that is done by this function depends on the
733
* underlying transport type. For SRTP, this will activate the encryption
734
* and decryption based on the keys found the SDPs. For ICE, this will
735
* start ICE negotiation according to the information found in the SDPs.
737
* This is just a simple wrapper which calls <tt>media_start()</tt> member
740
* @param tp The media transport.
741
* @param tmp_pool The memory pool for allocating temporary objects.
742
* @param sdp_local Local SDP.
743
* @param sdp_remote Remote SDP.
744
* @param media_index Media index in the SDP.
746
* @return PJ_SUCCESS on success, or the appropriate error code.
748
PJ_INLINE(pj_status_t) pjmedia_transport_media_start(pjmedia_transport *tp,
750
const pjmedia_sdp_session *sdp_local,
751
const pjmedia_sdp_session *sdp_remote,
752
unsigned media_index)
754
return (*tp->op->media_start)(tp, tmp_pool, sdp_local, sdp_remote,
760
* This API should be called when the session is stopped, to allow the media
761
* transport to release its resources used for the session.
763
* This is just a simple wrapper which calls <tt>media_stop()</tt> member
766
* @param tp The media transport.
768
* @return PJ_SUCCESS on success, or the appropriate error code.
770
PJ_INLINE(pj_status_t) pjmedia_transport_media_stop(pjmedia_transport *tp)
772
return (*tp->op->media_stop)(tp);
776
* Close media transport. This is just a simple wrapper which calls
777
* <tt>destroy()</tt> member of the transport. This function will free
778
* all resources created by this transport (such as sockets, memory, etc.).
780
* @param tp The media transport.
782
* @return PJ_SUCCESS on success, or the appropriate error code.
784
PJ_INLINE(pj_status_t) pjmedia_transport_close(pjmedia_transport *tp)
787
return (*tp->op->destroy)(tp);
793
* Simulate packet lost in the specified direction (for testing purposes).
794
* When enabled, the transport will randomly drop packets to the specified
797
* @param tp The media transport.
798
* @param dir Media direction to which packets will be randomly dropped.
799
* @param pct_lost Percent lost (0-100). Set to zero to disable packet
802
* @return PJ_SUCCESS on success.
804
PJ_INLINE(pj_status_t) pjmedia_transport_simulate_lost(pjmedia_transport *tp,
808
return (*tp->op->simulate_lost)(tp, dir, pct_lost);
819
#endif /* __PJMEDIA_TRANSPORT_H__ */