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

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* 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 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
 
}