~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.1.0/pjmedia/src/pjmedia/transport_loop.c

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2015-01-07 14:51:16 UTC
  • mfrom: (4.3.5 sid)
  • Revision ID: package-import@ubuntu.com-20150107145116-yxnafinf4lrdvrmx
Tags: 1.4.1-0.1ubuntu1
* Merge with Debian, remaining changes:
 - Drop soprano, nepomuk build-dep
* Drop ubuntu patches, now upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: transport_loop.c 3553 2011-05-05 06:14:19Z nanang $ */
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