Add support for ICE/STUN/TURN in res_rtp_asterisk and chan_sip.
[asterisk/asterisk.git] / res / pjproject / pjmedia / src / pjmedia / transport_loop.c
1 /* $Id$ */
2 /* 
3  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5  *
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.
10  *
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.
15  *
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 
19  */
20 #include <pjmedia/transport_loop.h>
21 #include <pj/array.h>
22 #include <pj/assert.h>
23 #include <pj/errno.h>
24 #include <pj/ioqueue.h>
25 #include <pj/log.h>
26 #include <pj/pool.h>
27 #include <pj/rand.h>
28 #include <pj/string.h>
29
30
31 struct user
32 {
33     pj_bool_t           rx_disabled;    /**< Doesn't want to receive pkt?   */
34     void               *user_data;      /**< Only valid when attached       */
35     void  (*rtp_cb)(    void*,          /**< To report incoming RTP.        */
36                         void*,
37                         pj_ssize_t);
38     void  (*rtcp_cb)(   void*,          /**< To report incoming RTCP.       */
39                         void*,
40                         pj_ssize_t);
41 };
42
43 struct transport_loop
44 {
45     pjmedia_transport   base;           /**< Base transport.                */
46
47     pj_pool_t          *pool;           /**< Memory pool                    */
48     unsigned            user_cnt;       /**< Number of attachments          */
49     struct user         users[4];       /**< Array of users.                */
50
51     unsigned            tx_drop_pct;    /**< Percent of tx pkts to drop.    */
52     unsigned            rx_drop_pct;    /**< Percent of rx pkts to drop.    */
53
54 };
55
56
57
58 /*
59  * These are media transport operations.
60  */
61 static pj_status_t transport_get_info (pjmedia_transport *tp,
62                                        pjmedia_transport_info *info);
63 static pj_status_t transport_attach   (pjmedia_transport *tp,
64                                        void *user_data,
65                                        const pj_sockaddr_t *rem_addr,
66                                        const pj_sockaddr_t *rem_rtcp,
67                                        unsigned addr_len,
68                                        void (*rtp_cb)(void*,
69                                                       void*,
70                                                       pj_ssize_t),
71                                        void (*rtcp_cb)(void*,
72                                                        void*,
73                                                        pj_ssize_t));
74 static void        transport_detach   (pjmedia_transport *tp,
75                                        void *strm);
76 static pj_status_t transport_send_rtp( pjmedia_transport *tp,
77                                        const void *pkt,
78                                        pj_size_t size);
79 static pj_status_t transport_send_rtcp(pjmedia_transport *tp,
80                                        const void *pkt,
81                                        pj_size_t size);
82 static pj_status_t transport_send_rtcp2(pjmedia_transport *tp,
83                                        const pj_sockaddr_t *addr,
84                                        unsigned addr_len,
85                                        const void *pkt,
86                                        pj_size_t size);
87 static pj_status_t transport_media_create(pjmedia_transport *tp,
88                                        pj_pool_t *pool,
89                                        unsigned options,
90                                        const pjmedia_sdp_session *sdp_remote,
91                                        unsigned media_index);
92 static pj_status_t transport_encode_sdp(pjmedia_transport *tp,
93                                         pj_pool_t *pool,
94                                         pjmedia_sdp_session *sdp_local,
95                                         const pjmedia_sdp_session *rem_sdp,
96                                         unsigned media_index);
97 static pj_status_t transport_media_start (pjmedia_transport *tp,
98                                        pj_pool_t *pool,
99                                        const pjmedia_sdp_session *sdp_local,
100                                        const pjmedia_sdp_session *sdp_remote,
101                                        unsigned media_index);
102 static pj_status_t transport_media_stop(pjmedia_transport *tp);
103 static pj_status_t transport_simulate_lost(pjmedia_transport *tp,
104                                        pjmedia_dir dir,
105                                        unsigned pct_lost);
106 static pj_status_t transport_destroy  (pjmedia_transport *tp);
107
108
109 static pjmedia_transport_op transport_udp_op = 
110 {
111     &transport_get_info,
112     &transport_attach,
113     &transport_detach,
114     &transport_send_rtp,
115     &transport_send_rtcp,
116     &transport_send_rtcp2,
117     &transport_media_create,
118     &transport_encode_sdp,
119     &transport_media_start,
120     &transport_media_stop,
121     &transport_simulate_lost,
122     &transport_destroy
123 };
124
125
126 /**
127  * Create loopback transport.
128  */
129 PJ_DEF(pj_status_t) pjmedia_transport_loop_create(pjmedia_endpt *endpt,
130                                                   pjmedia_transport **p_tp)
131 {
132     struct transport_loop *tp;
133     pj_pool_t *pool;
134
135     /* Sanity check */
136     PJ_ASSERT_RETURN(endpt && p_tp, PJ_EINVAL);
137
138     /* Create transport structure */
139     pool = pjmedia_endpt_create_pool(endpt, "tploop", 512, 512);
140     if (!pool)
141         return PJ_ENOMEM;
142
143     tp = PJ_POOL_ZALLOC_T(pool, struct transport_loop);
144     tp->pool = pool;
145     pj_ansi_strncpy(tp->base.name, tp->pool->obj_name, PJ_MAX_OBJ_NAME-1);
146     tp->base.op = &transport_udp_op;
147     tp->base.type = PJMEDIA_TRANSPORT_TYPE_UDP;
148
149     /* Done */
150     *p_tp = &tp->base;
151     return PJ_SUCCESS;
152 }
153
154
155 PJ_DEF(pj_status_t) pjmedia_transport_loop_disable_rx( pjmedia_transport *tp,
156                                                        void *user,
157                                                        pj_bool_t disabled)
158 {
159     struct transport_loop *loop = (struct transport_loop*) tp;
160     unsigned i;
161
162     for (i=0; i<loop->user_cnt; ++i) {
163         if (loop->users[i].user_data == user) {
164             loop->users[i].rx_disabled = disabled;
165             return PJ_SUCCESS;
166         }
167     }
168     pj_assert(!"Invalid stream user");
169     return PJ_ENOTFOUND;
170 }
171
172 /**
173  * Close loopback transport.
174  */
175 static pj_status_t transport_destroy(pjmedia_transport *tp)
176 {
177     struct transport_loop *loop = (struct transport_loop*) tp;
178
179     /* Sanity check */
180     PJ_ASSERT_RETURN(tp, PJ_EINVAL);
181
182     pj_pool_release(loop->pool);
183
184     return PJ_SUCCESS;
185 }
186
187
188 /* Called to get the transport info */
189 static pj_status_t transport_get_info(pjmedia_transport *tp,
190                                       pjmedia_transport_info *info)
191 {
192     PJ_ASSERT_RETURN(tp && info, PJ_EINVAL);
193
194     info->sock_info.rtp_sock = 1;
195     pj_sockaddr_in_init(&info->sock_info.rtp_addr_name.ipv4, 0, 0);
196     info->sock_info.rtcp_sock = 2;
197     pj_sockaddr_in_init(&info->sock_info.rtcp_addr_name.ipv4, 0, 0);
198
199     return PJ_SUCCESS;
200 }
201
202
203 /* Called by application to initialize the transport */
204 static pj_status_t transport_attach(   pjmedia_transport *tp,
205                                        void *user_data,
206                                        const pj_sockaddr_t *rem_addr,
207                                        const pj_sockaddr_t *rem_rtcp,
208                                        unsigned addr_len,
209                                        void (*rtp_cb)(void*,
210                                                       void*,
211                                                       pj_ssize_t),
212                                        void (*rtcp_cb)(void*,
213                                                        void*,
214                                                        pj_ssize_t))
215 {
216     struct transport_loop *loop = (struct transport_loop*) tp;
217     unsigned i;
218     const pj_sockaddr *rtcp_addr;
219
220     /* Validate arguments */
221     PJ_ASSERT_RETURN(tp && rem_addr && addr_len, PJ_EINVAL);
222
223     /* Must not be "attached" to same user */
224     for (i=0; i<loop->user_cnt; ++i) {
225         PJ_ASSERT_RETURN(loop->users[i].user_data != user_data,
226                          PJ_EINVALIDOP);
227     }
228     PJ_ASSERT_RETURN(loop->user_cnt != PJ_ARRAY_SIZE(loop->users), 
229                      PJ_ETOOMANY);
230
231     PJ_UNUSED_ARG(rem_rtcp);
232     PJ_UNUSED_ARG(rtcp_addr);
233
234     /* "Attach" the application: */
235
236     /* Save the new user */
237     loop->users[loop->user_cnt].rtp_cb = rtp_cb;
238     loop->users[loop->user_cnt].rtcp_cb = rtcp_cb;
239     loop->users[loop->user_cnt].user_data = user_data;
240     ++loop->user_cnt;
241
242     return PJ_SUCCESS;
243 }
244
245
246 /* Called by application when it no longer needs the transport */
247 static void transport_detach( pjmedia_transport *tp,
248                               void *user_data)
249 {
250     struct transport_loop *loop = (struct transport_loop*) tp;
251     unsigned i;
252
253     pj_assert(tp);
254
255     for (i=0; i<loop->user_cnt; ++i) {
256         if (loop->users[i].user_data == user_data)
257             break;
258     }
259
260     /* Remove this user */
261     if (i != loop->user_cnt) {
262         pj_array_erase(loop->users, sizeof(loop->users[0]),
263                        loop->user_cnt, i);
264         --loop->user_cnt;
265     }
266 }
267
268
269 /* Called by application to send RTP packet */
270 static pj_status_t transport_send_rtp( pjmedia_transport *tp,
271                                        const void *pkt,
272                                        pj_size_t size)
273 {
274     struct transport_loop *loop = (struct transport_loop*)tp;
275     unsigned i;
276
277     /* Simulate packet lost on TX direction */
278     if (loop->tx_drop_pct) {
279         if ((pj_rand() % 100) <= (int)loop->tx_drop_pct) {
280             PJ_LOG(5,(loop->base.name, 
281                       "TX RTP packet dropped because of pkt lost "
282                       "simulation"));
283             return PJ_SUCCESS;
284         }
285     }
286
287     /* Simulate packet lost on RX direction */
288     if (loop->rx_drop_pct) {
289         if ((pj_rand() % 100) <= (int)loop->rx_drop_pct) {
290             PJ_LOG(5,(loop->base.name, 
291                       "RX RTP packet dropped because of pkt lost "
292                       "simulation"));
293             return PJ_SUCCESS;
294         }
295     }
296
297     /* Distribute to users */
298     for (i=0; i<loop->user_cnt; ++i) {
299         if (!loop->users[i].rx_disabled && loop->users[i].rtp_cb)
300             (*loop->users[i].rtp_cb)(loop->users[i].user_data, (void*)pkt, 
301                                      size);
302     }
303
304     return PJ_SUCCESS;
305 }
306
307 /* Called by application to send RTCP packet */
308 static pj_status_t transport_send_rtcp(pjmedia_transport *tp,
309                                        const void *pkt,
310                                        pj_size_t size)
311 {
312     return transport_send_rtcp2(tp, NULL, 0, pkt, size);
313 }
314
315
316 /* Called by application to send RTCP packet */
317 static pj_status_t transport_send_rtcp2(pjmedia_transport *tp,
318                                         const pj_sockaddr_t *addr,
319                                         unsigned addr_len,
320                                         const void *pkt,
321                                         pj_size_t size)
322 {
323     struct transport_loop *loop = (struct transport_loop*)tp;
324     unsigned i;
325
326     PJ_UNUSED_ARG(addr_len);
327     PJ_UNUSED_ARG(addr);
328
329     /* Distribute to users */
330     for (i=0; i<loop->user_cnt; ++i) {
331         if (!loop->users[i].rx_disabled && loop->users[i].rtcp_cb)
332             (*loop->users[i].rtcp_cb)(loop->users[i].user_data, (void*)pkt,
333                                       size);
334     }
335
336     return PJ_SUCCESS;
337 }
338
339
340 static pj_status_t transport_media_create(pjmedia_transport *tp,
341                                   pj_pool_t *pool,
342                                   unsigned options,
343                                   const pjmedia_sdp_session *sdp_remote,
344                                   unsigned media_index)
345 {
346     PJ_UNUSED_ARG(tp);
347     PJ_UNUSED_ARG(pool);
348     PJ_UNUSED_ARG(options);
349     PJ_UNUSED_ARG(sdp_remote);
350     PJ_UNUSED_ARG(media_index);
351     return PJ_SUCCESS;
352 }
353
354 static pj_status_t transport_encode_sdp(pjmedia_transport *tp,
355                                         pj_pool_t *pool,
356                                         pjmedia_sdp_session *sdp_local,
357                                         const pjmedia_sdp_session *rem_sdp,
358                                         unsigned media_index)
359 {
360     PJ_UNUSED_ARG(tp);
361     PJ_UNUSED_ARG(pool);
362     PJ_UNUSED_ARG(sdp_local);
363     PJ_UNUSED_ARG(rem_sdp);
364     PJ_UNUSED_ARG(media_index);
365     return PJ_SUCCESS;
366 }
367
368 static pj_status_t transport_media_start(pjmedia_transport *tp,
369                                   pj_pool_t *pool,
370                                   const pjmedia_sdp_session *sdp_local,
371                                   const pjmedia_sdp_session *sdp_remote,
372                                   unsigned media_index)
373 {
374     PJ_UNUSED_ARG(tp);
375     PJ_UNUSED_ARG(pool);
376     PJ_UNUSED_ARG(sdp_local);
377     PJ_UNUSED_ARG(sdp_remote);
378     PJ_UNUSED_ARG(media_index);
379     return PJ_SUCCESS;
380 }
381
382 static pj_status_t transport_media_stop(pjmedia_transport *tp)
383 {
384     PJ_UNUSED_ARG(tp);
385     return PJ_SUCCESS;
386 }
387
388 static pj_status_t transport_simulate_lost(pjmedia_transport *tp,
389                                            pjmedia_dir dir,
390                                            unsigned pct_lost)
391 {
392     struct transport_loop *loop = (struct transport_loop*)tp;
393
394     PJ_ASSERT_RETURN(tp && pct_lost <= 100, PJ_EINVAL);
395
396     if (dir & PJMEDIA_DIR_ENCODING)
397         loop->tx_drop_pct = pct_lost;
398     
399     if (dir & PJMEDIA_DIR_DECODING)
400         loop->rx_drop_pct = pct_lost;
401
402     return PJ_SUCCESS;
403 }
404