~ubuntu-branches/ubuntu/trusty/sflphone/trusty

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (4.3.4 sid)
  • Revision ID: package-import@ubuntu.com-20140128182336-jrsv0k9u6cawc068
Tags: 1.3.0-1
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

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