~noskcaj/ubuntu/saucy/sflphone/merge-1.2.3-2

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.0.1/pjmedia/src/pjmedia/endpoint.c

  • Committer: Jackson Doak
  • Date: 2013-07-10 21:04:46 UTC
  • mfrom: (20.1.3 sid)
  • Revision ID: noskcaj@ubuntu.com-20130710210446-y8f587vza807icr9
Properly merged from upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: endpoint.c 3999 2012-03-30 07:10:13Z bennylp $ */
 
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/endpoint.h>
 
21
#include <pjmedia/errno.h>
 
22
#include <pjmedia/sdp.h>
 
23
#include <pjmedia/vid_codec.h>
 
24
#include <pjmedia-audiodev/audiodev.h>
 
25
#include <pj/assert.h>
 
26
#include <pj/ioqueue.h>
 
27
#include <pj/lock.h>
 
28
#include <pj/log.h>
 
29
#include <pj/os.h>
 
30
#include <pj/pool.h>
 
31
#include <pj/sock.h>
 
32
#include <pj/string.h>
 
33
 
 
34
 
 
35
#define THIS_FILE   "endpoint.c"
 
36
 
 
37
static const pj_str_t STR_AUDIO = { "audio", 5};
 
38
static const pj_str_t STR_VIDEO = { "video", 5};
 
39
static const pj_str_t STR_IN = { "IN", 2 };
 
40
static const pj_str_t STR_IP4 = { "IP4", 3};
 
41
static const pj_str_t STR_IP6 = { "IP6", 3};
 
42
static const pj_str_t STR_RTP_AVP = { "RTP/AVP", 7 };
 
43
static const pj_str_t STR_SDP_NAME = { "pjmedia", 7 };
 
44
static const pj_str_t STR_SENDRECV = { "sendrecv", 8 };
 
45
 
 
46
 
 
47
 
 
48
/* Config to control rtpmap inclusion for static payload types */
 
49
pj_bool_t pjmedia_add_rtpmap_for_static_pt =
 
50
            PJMEDIA_ADD_RTPMAP_FOR_STATIC_PT;
 
51
 
 
52
 
 
53
 
 
54
/* Worker thread proc. */
 
55
static int PJ_THREAD_FUNC worker_proc(void*);
 
56
 
 
57
 
 
58
#define MAX_THREADS     16
 
59
 
 
60
 
 
61
/* List of media endpoint exit callback. */
 
62
typedef struct exit_cb
 
63
{
 
64
    PJ_DECL_LIST_MEMBER             (struct exit_cb);
 
65
    pjmedia_endpt_exit_callback     func;
 
66
} exit_cb;
 
67
 
 
68
 
 
69
/** Concrete declaration of media endpoint. */
 
70
struct pjmedia_endpt
 
71
{
 
72
    /** Pool. */
 
73
    pj_pool_t            *pool;
 
74
 
 
75
    /** Pool factory. */
 
76
    pj_pool_factory      *pf;
 
77
 
 
78
    /** Codec manager. */
 
79
    pjmedia_codec_mgr     codec_mgr;
 
80
 
 
81
    /** IOqueue instance. */
 
82
    pj_ioqueue_t         *ioqueue;
 
83
 
 
84
    /** Do we own the ioqueue? */
 
85
    pj_bool_t             own_ioqueue;
 
86
 
 
87
    /** Number of threads. */
 
88
    unsigned              thread_cnt;
 
89
 
 
90
    /** IOqueue polling thread, if any. */
 
91
    pj_thread_t          *thread[MAX_THREADS];
 
92
 
 
93
    /** To signal polling thread to quit. */
 
94
    pj_bool_t             quit_flag;
 
95
 
 
96
    /** Is telephone-event enable */
 
97
    pj_bool_t             has_telephone_event;
 
98
 
 
99
    /** List of exit callback. */
 
100
    exit_cb               exit_cb_list;
 
101
};
 
102
 
 
103
/**
 
104
 * Initialize and get the instance of media endpoint.
 
105
 */
 
106
PJ_DEF(pj_status_t) pjmedia_endpt_create(pj_pool_factory *pf,
 
107
                                         pj_ioqueue_t *ioqueue,
 
108
                                         unsigned worker_cnt,
 
109
                                         pjmedia_endpt **p_endpt)
 
110
{
 
111
    pj_pool_t *pool;
 
112
    pjmedia_endpt *endpt;
 
113
    unsigned i;
 
114
    pj_status_t status;
 
115
 
 
116
    status = pj_register_strerror(PJMEDIA_ERRNO_START, PJ_ERRNO_SPACE_SIZE,
 
117
                                  &pjmedia_strerror);
 
118
    pj_assert(status == PJ_SUCCESS);
 
119
 
 
120
    PJ_ASSERT_RETURN(pf && p_endpt, PJ_EINVAL);
 
121
    PJ_ASSERT_RETURN(worker_cnt <= MAX_THREADS, PJ_EINVAL);
 
122
 
 
123
    pool = pj_pool_create(pf, "med-ept", 512, 512, NULL);
 
124
    if (!pool)
 
125
        return PJ_ENOMEM;
 
126
 
 
127
    endpt = PJ_POOL_ZALLOC_T(pool, struct pjmedia_endpt);
 
128
    endpt->pool = pool;
 
129
    endpt->pf = pf;
 
130
    endpt->ioqueue = ioqueue;
 
131
    endpt->thread_cnt = worker_cnt;
 
132
    endpt->has_telephone_event = PJ_TRUE;
 
133
 
 
134
    /* Sound */
 
135
    status = pjmedia_aud_subsys_init(pf);
 
136
    if (status != PJ_SUCCESS)
 
137
        goto on_error;
 
138
 
 
139
    /* Init codec manager. */
 
140
    status = pjmedia_codec_mgr_init(&endpt->codec_mgr, endpt->pf);
 
141
    if (status != PJ_SUCCESS)
 
142
        goto on_error;
 
143
 
 
144
    /* Initialize exit callback list. */
 
145
    pj_list_init(&endpt->exit_cb_list);
 
146
 
 
147
    /* Create ioqueue if none is specified. */
 
148
    if (endpt->ioqueue == NULL) {
 
149
 
 
150
        endpt->own_ioqueue = PJ_TRUE;
 
151
 
 
152
        status = pj_ioqueue_create( endpt->pool, PJ_IOQUEUE_MAX_HANDLES,
 
153
                                    &endpt->ioqueue);
 
154
        if (status != PJ_SUCCESS)
 
155
            goto on_error;
 
156
 
 
157
        if (worker_cnt == 0) {
 
158
            PJ_LOG(4,(THIS_FILE, "Warning: no worker thread is created in"
 
159
                                 "media endpoint for internal ioqueue"));
 
160
        }
 
161
    }
 
162
 
 
163
    /* Create worker threads if asked. */
 
164
    for (i=0; i<worker_cnt; ++i) {
 
165
        status = pj_thread_create( endpt->pool, "media", &worker_proc,
 
166
                                   endpt, 0, 0, &endpt->thread[i]);
 
167
        if (status != PJ_SUCCESS)
 
168
            goto on_error;
 
169
    }
 
170
 
 
171
 
 
172
    *p_endpt = endpt;
 
173
    return PJ_SUCCESS;
 
174
 
 
175
on_error:
 
176
 
 
177
    /* Destroy threads */
 
178
    for (i=0; i<endpt->thread_cnt; ++i) {
 
179
        if (endpt->thread[i]) {
 
180
            pj_thread_destroy(endpt->thread[i]);
 
181
        }
 
182
    }
 
183
 
 
184
    /* Destroy internal ioqueue */
 
185
    if (endpt->ioqueue && endpt->own_ioqueue)
 
186
        pj_ioqueue_destroy(endpt->ioqueue);
 
187
 
 
188
    pjmedia_codec_mgr_destroy(&endpt->codec_mgr);
 
189
    pjmedia_aud_subsys_shutdown();
 
190
    pj_pool_release(pool);
 
191
    return status;
 
192
}
 
193
 
 
194
/**
 
195
 * Get the codec manager instance.
 
196
 */
 
197
PJ_DEF(pjmedia_codec_mgr*) pjmedia_endpt_get_codec_mgr(pjmedia_endpt *endpt)
 
198
{
 
199
    return &endpt->codec_mgr;
 
200
}
 
201
 
 
202
/**
 
203
 * Deinitialize media endpoint.
 
204
 */
 
205
PJ_DEF(pj_status_t) pjmedia_endpt_destroy (pjmedia_endpt *endpt)
 
206
{
 
207
    exit_cb *ecb;
 
208
    unsigned i;
 
209
 
 
210
    PJ_ASSERT_RETURN(endpt, PJ_EINVAL);
 
211
 
 
212
    endpt->quit_flag = 1;
 
213
 
 
214
    /* Destroy threads */
 
215
    for (i=0; i<endpt->thread_cnt; ++i) {
 
216
        if (endpt->thread[i]) {
 
217
            pj_thread_join(endpt->thread[i]);
 
218
            pj_thread_destroy(endpt->thread[i]);
 
219
            endpt->thread[i] = NULL;
 
220
        }
 
221
    }
 
222
 
 
223
    /* Destroy internal ioqueue */
 
224
    if (endpt->ioqueue && endpt->own_ioqueue) {
 
225
        pj_ioqueue_destroy(endpt->ioqueue);
 
226
        endpt->ioqueue = NULL;
 
227
    }
 
228
 
 
229
    endpt->pf = NULL;
 
230
 
 
231
    pjmedia_codec_mgr_destroy(&endpt->codec_mgr);
 
232
    pjmedia_aud_subsys_shutdown();
 
233
 
 
234
    /* Call all registered exit callbacks */
 
235
    ecb = endpt->exit_cb_list.next;
 
236
    while (ecb != &endpt->exit_cb_list) {
 
237
        (*ecb->func)(endpt);
 
238
        ecb = ecb->next;
 
239
    }
 
240
 
 
241
    pj_pool_release (endpt->pool);
 
242
 
 
243
    return PJ_SUCCESS;
 
244
}
 
245
 
 
246
PJ_DEF(pj_status_t) pjmedia_endpt_set_flag( pjmedia_endpt *endpt,
 
247
                                            pjmedia_endpt_flag flag,
 
248
                                            const void *value)
 
249
{
 
250
    PJ_ASSERT_RETURN(endpt, PJ_EINVAL);
 
251
 
 
252
    switch (flag) {
 
253
    case PJMEDIA_ENDPT_HAS_TELEPHONE_EVENT_FLAG:
 
254
        endpt->has_telephone_event = *(pj_bool_t*)value;
 
255
        break;
 
256
    default:
 
257
        return PJ_EINVAL;
 
258
    }
 
259
 
 
260
    return PJ_SUCCESS;
 
261
}
 
262
 
 
263
PJ_DEF(pj_status_t) pjmedia_endpt_get_flag( pjmedia_endpt *endpt,
 
264
                                            pjmedia_endpt_flag flag,
 
265
                                            void *value)
 
266
{
 
267
    PJ_ASSERT_RETURN(endpt, PJ_EINVAL);
 
268
 
 
269
    switch (flag) {
 
270
    case PJMEDIA_ENDPT_HAS_TELEPHONE_EVENT_FLAG:
 
271
        *(pj_bool_t*)value = endpt->has_telephone_event;
 
272
        break;
 
273
    default:
 
274
        return PJ_EINVAL;
 
275
    }
 
276
 
 
277
    return PJ_SUCCESS;
 
278
}
 
279
 
 
280
/**
 
281
 * Get the ioqueue instance of the media endpoint.
 
282
 */
 
283
PJ_DEF(pj_ioqueue_t*) pjmedia_endpt_get_ioqueue(pjmedia_endpt *endpt)
 
284
{
 
285
    PJ_ASSERT_RETURN(endpt, NULL);
 
286
    return endpt->ioqueue;
 
287
}
 
288
 
 
289
/**
 
290
 * Get the number of worker threads in media endpoint.
 
291
 */
 
292
PJ_DEF(unsigned) pjmedia_endpt_get_thread_count(pjmedia_endpt *endpt)
 
293
{
 
294
    PJ_ASSERT_RETURN(endpt, 0);
 
295
    return endpt->thread_cnt;
 
296
}
 
297
 
 
298
/**
 
299
 * Get a reference to one of the worker threads of the media endpoint
 
300
 */
 
301
PJ_DEF(pj_thread_t*) pjmedia_endpt_get_thread(pjmedia_endpt *endpt,
 
302
                                              unsigned index)
 
303
{
 
304
    PJ_ASSERT_RETURN(endpt, NULL);
 
305
    PJ_ASSERT_RETURN(index < endpt->thread_cnt, NULL);
 
306
 
 
307
    /* here should be an assert on index >= 0 < endpt->thread_cnt */
 
308
 
 
309
    return endpt->thread[index];
 
310
}
 
311
 
 
312
/**
 
313
 * Worker thread proc.
 
314
 */
 
315
static int PJ_THREAD_FUNC worker_proc(void *arg)
 
316
{
 
317
    pjmedia_endpt *endpt = (pjmedia_endpt*) arg;
 
318
 
 
319
    while (!endpt->quit_flag) {
 
320
        pj_time_val timeout = { 0, 500 };
 
321
        pj_ioqueue_poll(endpt->ioqueue, &timeout);
 
322
    }
 
323
 
 
324
    return 0;
 
325
}
 
326
 
 
327
/**
 
328
 * Create pool.
 
329
 */
 
330
PJ_DEF(pj_pool_t*) pjmedia_endpt_create_pool( pjmedia_endpt *endpt,
 
331
                                              const char *name,
 
332
                                              pj_size_t initial,
 
333
                                              pj_size_t increment)
 
334
{
 
335
    pj_assert(endpt != NULL);
 
336
 
 
337
    return pj_pool_create(endpt->pf, name, initial, increment, NULL);
 
338
}
 
339
 
 
340
/* Common initialization for both audio and video SDP media line */
 
341
static pj_status_t init_sdp_media(pjmedia_sdp_media *m,
 
342
                                  pj_pool_t *pool,
 
343
                                  const pj_str_t *media_type,
 
344
                                  const pjmedia_sock_info *sock_info)
 
345
{
 
346
    char tmp_addr[PJ_INET6_ADDRSTRLEN];
 
347
    pjmedia_sdp_attr *attr;
 
348
    const pj_sockaddr *addr;
 
349
 
 
350
    pj_strdup(pool, &m->desc.media, media_type);
 
351
 
 
352
    addr = &sock_info->rtp_addr_name;
 
353
 
 
354
    /* Validate address family */
 
355
    PJ_ASSERT_RETURN(addr->addr.sa_family == pj_AF_INET() ||
 
356
                     addr->addr.sa_family == pj_AF_INET6(),
 
357
                     PJ_EAFNOTSUP);
 
358
 
 
359
    /* SDP connection line */
 
360
    m->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
 
361
    m->conn->net_type = STR_IN;
 
362
    m->conn->addr_type = (addr->addr.sa_family==pj_AF_INET())? STR_IP4:STR_IP6;
 
363
    pj_sockaddr_print(addr, tmp_addr, sizeof(tmp_addr), 0);
 
364
    pj_strdup2(pool, &m->conn->addr, tmp_addr);
 
365
 
 
366
    /* Port and transport in media description */
 
367
    m->desc.port = pj_sockaddr_get_port(addr);
 
368
    m->desc.port_count = 1;
 
369
    pj_strdup (pool, &m->desc.transport, &STR_RTP_AVP);
 
370
 
 
371
    /* Add "rtcp" attribute */
 
372
#if defined(PJMEDIA_HAS_RTCP_IN_SDP) && PJMEDIA_HAS_RTCP_IN_SDP!=0
 
373
    if (sock_info->rtcp_addr_name.addr.sa_family != 0) {
 
374
        attr = pjmedia_sdp_attr_create_rtcp(pool, &sock_info->rtcp_addr_name);
 
375
        if (attr)
 
376
            pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
 
377
    }
 
378
#endif
 
379
 
 
380
    /* Add sendrecv attribute. */
 
381
    attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
 
382
    attr->name = STR_SENDRECV;
 
383
    m->attr[m->attr_count++] = attr;
 
384
 
 
385
    return PJ_SUCCESS;
 
386
}
 
387
 
 
388
/* Create m=audio SDP media line */
 
389
PJ_DEF(pj_status_t) pjmedia_endpt_create_audio_sdp(pjmedia_endpt *endpt,
 
390
                                                   pj_pool_t *pool,
 
391
                                                   const pjmedia_sock_info *si,
 
392
                                                   unsigned options,
 
393
                                                   pjmedia_sdp_media **p_m)
 
394
{
 
395
    const pj_str_t STR_AUDIO = { "audio", 5 };
 
396
    pjmedia_sdp_media *m;
 
397
    pjmedia_sdp_attr *attr;
 
398
    unsigned i;
 
399
    unsigned max_bitrate = 0;
 
400
    pj_status_t status;
 
401
 
 
402
    PJ_UNUSED_ARG(options);
 
403
 
 
404
    /* Check that there are not too many codecs */
 
405
    PJ_ASSERT_RETURN(endpt->codec_mgr.codec_cnt <= PJMEDIA_MAX_SDP_FMT,
 
406
                     PJ_ETOOMANY);
 
407
 
 
408
    /* Create and init basic SDP media */
 
409
    m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media);
 
410
    status = init_sdp_media(m, pool, &STR_AUDIO, si);
 
411
    if (status != PJ_SUCCESS)
 
412
        return status;
 
413
 
 
414
    /* Add format, rtpmap, and fmtp (when applicable) for each codec */
 
415
    for (i=0; i<endpt->codec_mgr.codec_cnt; ++i) {
 
416
 
 
417
        pjmedia_codec_info *codec_info;
 
418
        pjmedia_sdp_rtpmap rtpmap;
 
419
        char tmp_param[3];
 
420
        pjmedia_codec_param codec_param;
 
421
        pj_str_t *fmt;
 
422
 
 
423
        if (endpt->codec_mgr.codec_desc[i].prio == PJMEDIA_CODEC_PRIO_DISABLED)
 
424
            break;
 
425
 
 
426
        codec_info = &endpt->codec_mgr.codec_desc[i].info;
 
427
        pjmedia_codec_mgr_get_default_param(&endpt->codec_mgr, codec_info,
 
428
                                            &codec_param);
 
429
        fmt = &m->desc.fmt[m->desc.fmt_count++];
 
430
 
 
431
        fmt->ptr = (char*) pj_pool_alloc(pool, 8);
 
432
        fmt->slen = pj_utoa(codec_info->pt, fmt->ptr);
 
433
 
 
434
        rtpmap.pt = *fmt;
 
435
        rtpmap.enc_name = codec_info->encoding_name;
 
436
 
 
437
#if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG != 0)
 
438
        if (codec_info->pt == PJMEDIA_RTP_PT_G722)
 
439
            rtpmap.clock_rate = 8000;
 
440
        else
 
441
            rtpmap.clock_rate = codec_info->clock_rate;
 
442
#else
 
443
        rtpmap.clock_rate = codec_info->clock_rate;
 
444
#endif
 
445
 
 
446
        /* For audio codecs, rtpmap parameters denotes the number
 
447
         * of channels, which can be omited if the value is 1.
 
448
         */
 
449
        if (codec_info->type == PJMEDIA_TYPE_AUDIO &&
 
450
            codec_info->channel_cnt > 1)
 
451
        {
 
452
            /* Can only support one digit channel count */
 
453
            pj_assert(codec_info->channel_cnt < 10);
 
454
 
 
455
            tmp_param[0] = (char)('0' + codec_info->channel_cnt);
 
456
 
 
457
            rtpmap.param.ptr = tmp_param;
 
458
            rtpmap.param.slen = 1;
 
459
 
 
460
        } else {
 
461
            rtpmap.param.ptr = "";
 
462
            rtpmap.param.slen = 0;
 
463
        }
 
464
 
 
465
        if (codec_info->pt >= 96 || pjmedia_add_rtpmap_for_static_pt) {
 
466
            pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);
 
467
            m->attr[m->attr_count++] = attr;
 
468
        }
 
469
 
 
470
        /* Add fmtp params */
 
471
        if (codec_param.setting.dec_fmtp.cnt > 0) {
 
472
            enum { MAX_FMTP_STR_LEN = 160 };
 
473
            char buf[MAX_FMTP_STR_LEN];
 
474
            unsigned buf_len = 0, i;
 
475
            pjmedia_codec_fmtp *dec_fmtp = &codec_param.setting.dec_fmtp;
 
476
 
 
477
            /* Print codec PT */
 
478
            buf_len += pj_ansi_snprintf(buf,
 
479
                                        MAX_FMTP_STR_LEN - buf_len,
 
480
                                        "%d",
 
481
                                        codec_info->pt);
 
482
 
 
483
            for (i = 0; i < dec_fmtp->cnt; ++i) {
 
484
                unsigned test_len = 2;
 
485
 
 
486
                /* Check if buf still available */
 
487
                test_len = dec_fmtp->param[i].val.slen +
 
488
                           dec_fmtp->param[i].name.slen;
 
489
                if (test_len + buf_len >= MAX_FMTP_STR_LEN)
 
490
                    return PJ_ETOOBIG;
 
491
 
 
492
                /* Print delimiter */
 
493
                buf_len += pj_ansi_snprintf(&buf[buf_len],
 
494
                                            MAX_FMTP_STR_LEN - buf_len,
 
495
                                            (i == 0?" ":";"));
 
496
 
 
497
                /* Print an fmtp param */
 
498
                if (dec_fmtp->param[i].name.slen)
 
499
                    buf_len += pj_ansi_snprintf(
 
500
                                            &buf[buf_len],
 
501
                                            MAX_FMTP_STR_LEN - buf_len,
 
502
                                            "%.*s=%.*s",
 
503
                                            (int)dec_fmtp->param[i].name.slen,
 
504
                                            dec_fmtp->param[i].name.ptr,
 
505
                                            (int)dec_fmtp->param[i].val.slen,
 
506
                                            dec_fmtp->param[i].val.ptr);
 
507
                else
 
508
                    buf_len += pj_ansi_snprintf(&buf[buf_len],
 
509
                                            MAX_FMTP_STR_LEN - buf_len,
 
510
                                            "%.*s",
 
511
                                            (int)dec_fmtp->param[i].val.slen,
 
512
                                            dec_fmtp->param[i].val.ptr);
 
513
            }
 
514
 
 
515
            attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
 
516
 
 
517
            attr->name = pj_str("fmtp");
 
518
            attr->value = pj_strdup3(pool, buf);
 
519
            m->attr[m->attr_count++] = attr;
 
520
        }
 
521
 
 
522
        /* Find maximum bitrate in this media */
 
523
        if (max_bitrate < codec_param.info.max_bps)
 
524
            max_bitrate = codec_param.info.max_bps;
 
525
    }
 
526
 
 
527
#if defined(PJMEDIA_RTP_PT_TELEPHONE_EVENTS) && \
 
528
    PJMEDIA_RTP_PT_TELEPHONE_EVENTS != 0
 
529
    /*
 
530
     * Add support telephony event
 
531
     */
 
532
    if (endpt->has_telephone_event) {
 
533
        m->desc.fmt[m->desc.fmt_count++] =
 
534
            pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR);
 
535
 
 
536
        /* Add rtpmap. */
 
537
        attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
 
538
        attr->name = pj_str("rtpmap");
 
539
        attr->value = pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR
 
540
                             " telephone-event/8000");
 
541
        m->attr[m->attr_count++] = attr;
 
542
 
 
543
        /* Add fmtp */
 
544
        attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
 
545
        attr->name = pj_str("fmtp");
 
546
        attr->value = pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR " 0-15");
 
547
        m->attr[m->attr_count++] = attr;
 
548
    }
 
549
#endif
 
550
 
 
551
    /* Put bandwidth info in media level using bandwidth modifier "TIAS"
 
552
     * (RFC3890).
 
553
     */
 
554
    if (max_bitrate) {
 
555
        const pj_str_t STR_BANDW_MODIFIER = { "TIAS", 4 };
 
556
        pjmedia_sdp_bandw *b;
 
557
 
 
558
        b = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_bandw);
 
559
        b->modifier = STR_BANDW_MODIFIER;
 
560
        b->value = max_bitrate;
 
561
        m->bandw[m->bandw_count++] = b;
 
562
    }
 
563
 
 
564
    *p_m = m;
 
565
    return PJ_SUCCESS;
 
566
}
 
567
 
 
568
 
 
569
#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
 
570
 
 
571
/* Create m=video SDP media line */
 
572
PJ_DEF(pj_status_t) pjmedia_endpt_create_video_sdp(pjmedia_endpt *endpt,
 
573
                                                   pj_pool_t *pool,
 
574
                                                   const pjmedia_sock_info *si,
 
575
                                                   unsigned options,
 
576
                                                   pjmedia_sdp_media **p_m)
 
577
{
 
578
 
 
579
 
 
580
    const pj_str_t STR_VIDEO = { "video", 5 };
 
581
    pjmedia_sdp_media *m;
 
582
    pjmedia_vid_codec_info codec_info[PJMEDIA_VID_CODEC_MGR_MAX_CODECS];
 
583
    unsigned codec_prio[PJMEDIA_VID_CODEC_MGR_MAX_CODECS];
 
584
    pjmedia_sdp_attr *attr;
 
585
    unsigned cnt, i;
 
586
    unsigned max_bitrate = 0;
 
587
    pj_status_t status;
 
588
 
 
589
    PJ_UNUSED_ARG(options);
 
590
 
 
591
    /* Make sure video codec manager is instantiated */
 
592
    if (!pjmedia_vid_codec_mgr_instance())
 
593
        pjmedia_vid_codec_mgr_create(endpt->pool, NULL);
 
594
 
 
595
    /* Create and init basic SDP media */
 
596
    m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media);
 
597
    status = init_sdp_media(m, pool, &STR_VIDEO, si);
 
598
    if (status != PJ_SUCCESS)
 
599
        return status;
 
600
 
 
601
    cnt = PJ_ARRAY_SIZE(codec_info);
 
602
    status = pjmedia_vid_codec_mgr_enum_codecs(NULL, &cnt,
 
603
                                               codec_info, codec_prio);
 
604
 
 
605
    /* Check that there are not too many codecs */
 
606
    PJ_ASSERT_RETURN(0 <= PJMEDIA_MAX_SDP_FMT,
 
607
                     PJ_ETOOMANY);
 
608
 
 
609
    /* Add format, rtpmap, and fmtp (when applicable) for each codec */
 
610
    for (i=0; i<cnt; ++i) {
 
611
        pjmedia_sdp_rtpmap rtpmap;
 
612
        pjmedia_vid_codec_param codec_param;
 
613
        pj_str_t *fmt;
 
614
        pjmedia_video_format_detail *vfd;
 
615
 
 
616
        pj_bzero(&rtpmap, sizeof(rtpmap));
 
617
 
 
618
        if (codec_prio[i] == PJMEDIA_CODEC_PRIO_DISABLED)
 
619
            break;
 
620
 
 
621
        if (i > PJMEDIA_MAX_SDP_FMT) {
 
622
            /* Too many codecs, perhaps it is better to tell application by
 
623
             * returning appropriate status code.
 
624
             */
 
625
            PJ_PERROR(3,(THIS_FILE, PJ_ETOOMANY,
 
626
                        "Skipping some video codecs"));
 
627
            break;
 
628
        }
 
629
 
 
630
        /* Must support RTP packetization and bidirectional */
 
631
        if ((codec_info[i].packings & PJMEDIA_VID_PACKING_PACKETS) == 0 ||
 
632
            codec_info[i].dir != PJMEDIA_DIR_ENCODING_DECODING)
 
633
        {
 
634
            continue;
 
635
        }
 
636
 
 
637
        pjmedia_vid_codec_mgr_get_default_param(NULL, &codec_info[i],
 
638
                                                &codec_param);
 
639
 
 
640
        fmt = &m->desc.fmt[m->desc.fmt_count++];
 
641
        fmt->ptr = (char*) pj_pool_alloc(pool, 8);
 
642
        fmt->slen = pj_utoa(codec_info[i].pt, fmt->ptr);
 
643
        rtpmap.pt = *fmt;
 
644
 
 
645
        /* Encoding name */
 
646
        rtpmap.enc_name = codec_info[i].encoding_name;
 
647
 
 
648
        /* Clock rate */
 
649
        rtpmap.clock_rate = codec_info[i].clock_rate;
 
650
 
 
651
        if (codec_info[i].pt >= 96 || pjmedia_add_rtpmap_for_static_pt) {
 
652
            pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);
 
653
            m->attr[m->attr_count++] = attr;
 
654
        }
 
655
 
 
656
        /* Add fmtp params */
 
657
        if (codec_param.dec_fmtp.cnt > 0) {
 
658
            enum { MAX_FMTP_STR_LEN = 160 };
 
659
            char buf[MAX_FMTP_STR_LEN];
 
660
            unsigned buf_len = 0, j;
 
661
            pjmedia_codec_fmtp *dec_fmtp = &codec_param.dec_fmtp;
 
662
 
 
663
            /* Print codec PT */
 
664
            buf_len += pj_ansi_snprintf(buf,
 
665
                                        MAX_FMTP_STR_LEN - buf_len,
 
666
                                        "%d",
 
667
                                        codec_info[i].pt);
 
668
 
 
669
            for (j = 0; j < dec_fmtp->cnt; ++j) {
 
670
                unsigned test_len = 2;
 
671
 
 
672
                /* Check if buf still available */
 
673
                test_len = dec_fmtp->param[j].val.slen +
 
674
                           dec_fmtp->param[j].name.slen;
 
675
                if (test_len + buf_len >= MAX_FMTP_STR_LEN)
 
676
                    return PJ_ETOOBIG;
 
677
 
 
678
                /* Print delimiter */
 
679
                buf_len += pj_ansi_snprintf(&buf[buf_len],
 
680
                                            MAX_FMTP_STR_LEN - buf_len,
 
681
                                            (j == 0?" ":";"));
 
682
 
 
683
                /* Print an fmtp param */
 
684
                if (dec_fmtp->param[j].name.slen)
 
685
                    buf_len += pj_ansi_snprintf(
 
686
                                            &buf[buf_len],
 
687
                                            MAX_FMTP_STR_LEN - buf_len,
 
688
                                            "%.*s=%.*s",
 
689
                                            (int)dec_fmtp->param[j].name.slen,
 
690
                                            dec_fmtp->param[j].name.ptr,
 
691
                                            (int)dec_fmtp->param[j].val.slen,
 
692
                                            dec_fmtp->param[j].val.ptr);
 
693
                else
 
694
                    buf_len += pj_ansi_snprintf(&buf[buf_len],
 
695
                                            MAX_FMTP_STR_LEN - buf_len,
 
696
                                            "%.*s",
 
697
                                            (int)dec_fmtp->param[j].val.slen,
 
698
                                            dec_fmtp->param[j].val.ptr);
 
699
            }
 
700
 
 
701
            attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
 
702
 
 
703
            attr->name = pj_str("fmtp");
 
704
            attr->value = pj_strdup3(pool, buf);
 
705
            m->attr[m->attr_count++] = attr;
 
706
        }
 
707
 
 
708
        /* Find maximum bitrate in this media */
 
709
        vfd = pjmedia_format_get_video_format_detail(&codec_param.enc_fmt,
 
710
                                                     PJ_TRUE);
 
711
        if (vfd && max_bitrate < vfd->max_bps)
 
712
            max_bitrate = vfd->max_bps;
 
713
    }
 
714
 
 
715
    /* Put bandwidth info in media level using bandwidth modifier "TIAS"
 
716
     * (RFC3890).
 
717
     */
 
718
    if (max_bitrate) {
 
719
        const pj_str_t STR_BANDW_MODIFIER = { "TIAS", 4 };
 
720
        pjmedia_sdp_bandw *b;
 
721
 
 
722
        b = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_bandw);
 
723
        b->modifier = STR_BANDW_MODIFIER;
 
724
        b->value = max_bitrate;
 
725
        m->bandw[m->bandw_count++] = b;
 
726
    }
 
727
 
 
728
    *p_m = m;
 
729
    return PJ_SUCCESS;
 
730
}
 
731
 
 
732
#endif /* PJMEDIA_HAS_VIDEO */
 
733
 
 
734
 
 
735
/**
 
736
 * Create a "blank" SDP session description. The SDP will contain basic SDP
 
737
 * fields such as origin, time, and name, but without any media lines.
 
738
 */
 
739
PJ_DEF(pj_status_t) pjmedia_endpt_create_base_sdp( pjmedia_endpt *endpt,
 
740
                                                   pj_pool_t *pool,
 
741
                                                   const pj_str_t *sess_name,
 
742
                                                   const pj_sockaddr *origin,
 
743
                                                   pjmedia_sdp_session **p_sdp)
 
744
{
 
745
    pj_time_val tv;
 
746
    pjmedia_sdp_session *sdp;
 
747
 
 
748
    /* Sanity check arguments */
 
749
    PJ_ASSERT_RETURN(endpt && pool && p_sdp, PJ_EINVAL);
 
750
 
 
751
    sdp = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_session);
 
752
 
 
753
    pj_gettimeofday(&tv);
 
754
    sdp->origin.user = pj_str("-");
 
755
    sdp->origin.version = sdp->origin.id = tv.sec + 2208988800UL;
 
756
    sdp->origin.net_type = STR_IN;
 
757
 
 
758
    if (origin->addr.sa_family == pj_AF_INET()) {
 
759
        sdp->origin.addr_type = STR_IP4;
 
760
        pj_strdup2(pool, &sdp->origin.addr,
 
761
                   pj_inet_ntoa(origin->ipv4.sin_addr));
 
762
    } else if (origin->addr.sa_family == pj_AF_INET6()) {
 
763
        char tmp_addr[PJ_INET6_ADDRSTRLEN];
 
764
 
 
765
        sdp->origin.addr_type = STR_IP6;
 
766
        pj_strdup2(pool, &sdp->origin.addr,
 
767
                   pj_sockaddr_print(origin, tmp_addr, sizeof(tmp_addr), 0));
 
768
 
 
769
    } else {
 
770
        pj_assert(!"Invalid address family");
 
771
        return PJ_EAFNOTSUP;
 
772
    }
 
773
 
 
774
    if (sess_name)
 
775
        pj_strdup(pool, &sdp->name, sess_name);
 
776
    else
 
777
        sdp->name = STR_SDP_NAME;
 
778
 
 
779
    /* SDP time and attributes. */
 
780
    sdp->time.start = sdp->time.stop = 0;
 
781
    sdp->attr_count = 0;
 
782
 
 
783
    /* Done */
 
784
    *p_sdp = sdp;
 
785
 
 
786
    return PJ_SUCCESS;
 
787
}
 
788
 
 
789
/**
 
790
 * Create a SDP session description that describes the endpoint
 
791
 * capability.
 
792
 */
 
793
PJ_DEF(pj_status_t) pjmedia_endpt_create_sdp( pjmedia_endpt *endpt,
 
794
                                              pj_pool_t *pool,
 
795
                                              unsigned stream_cnt,
 
796
                                              const pjmedia_sock_info sock_info[],
 
797
                                              pjmedia_sdp_session **p_sdp )
 
798
{
 
799
    const pj_sockaddr *addr0;
 
800
    pjmedia_sdp_session *sdp;
 
801
    pjmedia_sdp_media *m;
 
802
    pj_status_t status;
 
803
 
 
804
    /* Sanity check arguments */
 
805
    PJ_ASSERT_RETURN(endpt && pool && p_sdp && stream_cnt, PJ_EINVAL);
 
806
    PJ_ASSERT_RETURN(stream_cnt < PJMEDIA_MAX_SDP_MEDIA, PJ_ETOOMANY);
 
807
 
 
808
    addr0 = &sock_info[0].rtp_addr_name;
 
809
 
 
810
    /* Create and initialize basic SDP session */
 
811
    status = pjmedia_endpt_create_base_sdp(endpt, pool, NULL, addr0, &sdp);
 
812
    if (status != PJ_SUCCESS)
 
813
        return status;
 
814
 
 
815
    /* Audio is first, by convention */
 
816
    status = pjmedia_endpt_create_audio_sdp(endpt, pool,
 
817
                                            &sock_info[0], 0, &m);
 
818
    if (status != PJ_SUCCESS)
 
819
        return status;
 
820
    sdp->media[sdp->media_count++] = m;
 
821
 
 
822
#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
 
823
    {
 
824
        unsigned i;
 
825
 
 
826
        /* The remaining stream, if any, are videos (by convention as well) */
 
827
        for (i=1; i<stream_cnt; ++i) {
 
828
            status = pjmedia_endpt_create_video_sdp(endpt, pool,
 
829
                                                    &sock_info[i], 0, &m);
 
830
            if (status != PJ_SUCCESS)
 
831
                return status;
 
832
            sdp->media[sdp->media_count++] = m;
 
833
        }
 
834
    }
 
835
#endif
 
836
 
 
837
    /* Done */
 
838
    *p_sdp = sdp;
 
839
 
 
840
    return PJ_SUCCESS;
 
841
}
 
842
 
 
843
 
 
844
 
 
845
#if PJ_LOG_MAX_LEVEL >= 3
 
846
static const char *good_number(char *buf, pj_int32_t val)
 
847
{
 
848
    if (val < 1000) {
 
849
        pj_ansi_sprintf(buf, "%d", val);
 
850
    } else if (val < 1000000) {
 
851
        pj_ansi_sprintf(buf, "%d.%dK",
 
852
                        val / 1000,
 
853
                        (val % 1000) / 100);
 
854
    } else {
 
855
        pj_ansi_sprintf(buf, "%d.%02dM",
 
856
                        val / 1000000,
 
857
                        (val % 1000000) / 10000);
 
858
    }
 
859
 
 
860
    return buf;
 
861
}
 
862
#endif
 
863
 
 
864
PJ_DEF(pj_status_t) pjmedia_endpt_dump(pjmedia_endpt *endpt)
 
865
{
 
866
 
 
867
#if PJ_LOG_MAX_LEVEL >= 3
 
868
    unsigned i, count;
 
869
    pjmedia_codec_info codec_info[32];
 
870
    unsigned prio[32];
 
871
 
 
872
    PJ_LOG(3,(THIS_FILE, "Dumping PJMEDIA capabilities:"));
 
873
 
 
874
    count = PJ_ARRAY_SIZE(codec_info);
 
875
    if (pjmedia_codec_mgr_enum_codecs(&endpt->codec_mgr,
 
876
                                      &count, codec_info, prio) != PJ_SUCCESS)
 
877
    {
 
878
        PJ_LOG(3,(THIS_FILE, " -error: failed to enum codecs"));
 
879
        return PJ_SUCCESS;
 
880
    }
 
881
 
 
882
    PJ_LOG(3,(THIS_FILE, "  Total number of installed codecs: %d", count));
 
883
    for (i=0; i<count; ++i) {
 
884
        const char *type;
 
885
        pjmedia_codec_param param;
 
886
        char bps[32];
 
887
 
 
888
        switch (codec_info[i].type) {
 
889
        case PJMEDIA_TYPE_AUDIO:
 
890
            type = "Audio"; break;
 
891
        case PJMEDIA_TYPE_VIDEO:
 
892
            type = "Video"; break;
 
893
        default:
 
894
            type = "Unknown type"; break;
 
895
        }
 
896
 
 
897
        if (pjmedia_codec_mgr_get_default_param(&endpt->codec_mgr,
 
898
                                                &codec_info[i],
 
899
                                                &param) != PJ_SUCCESS)
 
900
        {
 
901
            pj_bzero(&param, sizeof(pjmedia_codec_param));
 
902
        }
 
903
 
 
904
        PJ_LOG(3,(THIS_FILE,
 
905
                  "   %s codec #%2d: pt=%d (%.*s @%dKHz/%d, %sbps, %dms%s%s%s%s%s)",
 
906
                  type, i, codec_info[i].pt,
 
907
                  (int)codec_info[i].encoding_name.slen,
 
908
                  codec_info[i].encoding_name.ptr,
 
909
                  codec_info[i].clock_rate/1000,
 
910
                  codec_info[i].channel_cnt,
 
911
                  good_number(bps, param.info.avg_bps),
 
912
                  param.info.frm_ptime * param.setting.frm_per_pkt,
 
913
                  (param.setting.vad ? " vad" : ""),
 
914
                  (param.setting.cng ? " cng" : ""),
 
915
                  (param.setting.plc ? " plc" : ""),
 
916
                  (param.setting.penh ? " penh" : ""),
 
917
                  (prio[i]==PJMEDIA_CODEC_PRIO_DISABLED?" disabled":"")));
 
918
    }
 
919
#endif
 
920
 
 
921
    return PJ_SUCCESS;
 
922
}
 
923
 
 
924
PJ_DEF(pj_status_t) pjmedia_endpt_atexit( pjmedia_endpt *endpt,
 
925
                                          pjmedia_endpt_exit_callback func)
 
926
{
 
927
    exit_cb *new_cb;
 
928
 
 
929
    PJ_ASSERT_RETURN(endpt && func, PJ_EINVAL);
 
930
 
 
931
    if (endpt->quit_flag)
 
932
        return PJ_EINVALIDOP;
 
933
 
 
934
    new_cb = PJ_POOL_ZALLOC_T(endpt->pool, exit_cb);
 
935
    new_cb->func = func;
 
936
 
 
937
    pj_enter_critical_section();
 
938
    pj_list_push_back(&endpt->exit_cb_list, new_cb);
 
939
    pj_leave_critical_section();
 
940
 
 
941
    return PJ_SUCCESS;
 
942
}