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

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.1.0/pjmedia/src/pjmedia/stream_info.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: stream_info.c 3982 2012-03-22 09:56:52Z 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/stream.h>
 
21
#include <pjmedia/stream_common.h>
 
22
#include <pj/ctype.h>
 
23
#include <pj/rand.h>
 
24
 
 
25
static const pj_str_t ID_AUDIO = { "audio", 5};
 
26
static const pj_str_t ID_IN = { "IN", 2 };
 
27
static const pj_str_t ID_IP4 = { "IP4", 3};
 
28
static const pj_str_t ID_IP6 = { "IP6", 3};
 
29
static const pj_str_t ID_RTP_AVP = { "RTP/AVP", 7 };
 
30
static const pj_str_t ID_RTP_SAVP = { "RTP/SAVP", 8 };
 
31
//static const pj_str_t ID_SDP_NAME = { "pjmedia", 7 };
 
32
static const pj_str_t ID_RTPMAP = { "rtpmap", 6 };
 
33
static const pj_str_t ID_TELEPHONE_EVENT = { "telephone-event", 15 };
 
34
 
 
35
static const pj_str_t STR_INACTIVE = { "inactive", 8 };
 
36
static const pj_str_t STR_SENDRECV = { "sendrecv", 8 };
 
37
static const pj_str_t STR_SENDONLY = { "sendonly", 8 };
 
38
static const pj_str_t STR_RECVONLY = { "recvonly", 8 };
 
39
 
 
40
 
 
41
/*
 
42
 * Internal function for collecting codec info and param from the SDP media.
 
43
 */
 
44
static pj_status_t get_audio_codec_info_param(pjmedia_stream_info *si,
 
45
                                              pj_pool_t *pool,
 
46
                                              pjmedia_codec_mgr *mgr,
 
47
                                              const pjmedia_sdp_media *local_m,
 
48
                                              const pjmedia_sdp_media *rem_m)
 
49
{
 
50
    const pjmedia_sdp_attr *attr;
 
51
    pjmedia_sdp_rtpmap *rtpmap;
 
52
    unsigned i, fmti, pt = 0;
 
53
    pj_status_t status;
 
54
 
 
55
    /* Find the first codec which is not telephone-event */
 
56
    for ( fmti = 0; fmti < local_m->desc.fmt_count; ++fmti ) {
 
57
        pjmedia_sdp_rtpmap r;
 
58
 
 
59
        if ( !pj_isdigit(*local_m->desc.fmt[fmti].ptr) )
 
60
            return PJMEDIA_EINVALIDPT;
 
61
        pt = pj_strtoul(&local_m->desc.fmt[fmti]);
 
62
 
 
63
        if (pt < 96) {
 
64
            /* This is known static PT. Skip rtpmap checking because it is
 
65
             * optional. */
 
66
            break;
 
67
        }
 
68
 
 
69
        attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP,
 
70
                                           &local_m->desc.fmt[fmti]);
 
71
        if (attr == NULL)
 
72
            continue;
 
73
 
 
74
        status = pjmedia_sdp_attr_get_rtpmap(attr, &r);
 
75
        if (status != PJ_SUCCESS)
 
76
            continue;
 
77
 
 
78
        if (pj_strcmp(&r.enc_name, &ID_TELEPHONE_EVENT) != 0)
 
79
            break;
 
80
    }
 
81
    if ( fmti >= local_m->desc.fmt_count )
 
82
        return PJMEDIA_EINVALIDPT;
 
83
 
 
84
    /* Get payload type for receiving direction */
 
85
    si->rx_pt = pt;
 
86
 
 
87
    /* Get codec info.
 
88
     * For static payload types, get the info from codec manager.
 
89
     * For dynamic payload types, MUST get the rtpmap.
 
90
     */
 
91
    if (pt < 96) {
 
92
        pj_bool_t has_rtpmap;
 
93
 
 
94
        rtpmap = NULL;
 
95
        has_rtpmap = PJ_TRUE;
 
96
 
 
97
        attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP,
 
98
                                           &local_m->desc.fmt[fmti]);
 
99
        if (attr == NULL) {
 
100
            has_rtpmap = PJ_FALSE;
 
101
        }
 
102
        if (attr != NULL) {
 
103
            status = pjmedia_sdp_attr_to_rtpmap(pool, attr, &rtpmap);
 
104
            if (status != PJ_SUCCESS)
 
105
                has_rtpmap = PJ_FALSE;
 
106
        }
 
107
 
 
108
        /* Build codec format info: */
 
109
        if (has_rtpmap) {
 
110
            si->fmt.type = si->type;
 
111
            si->fmt.pt = pj_strtoul(&local_m->desc.fmt[fmti]);
 
112
            pj_strdup(pool, &si->fmt.encoding_name, &rtpmap->enc_name);
 
113
            si->fmt.clock_rate = rtpmap->clock_rate;
 
114
 
 
115
#if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG != 0)
 
116
            /* The session info should have the actual clock rate, because
 
117
             * this info is used for calculationg buffer size, etc in stream
 
118
             */
 
119
            if (si->fmt.pt == PJMEDIA_RTP_PT_G722)
 
120
                si->fmt.clock_rate = 16000;
 
121
#endif
 
122
 
 
123
            /* For audio codecs, rtpmap parameters denotes the number of
 
124
             * channels.
 
125
             */
 
126
            if (si->type == PJMEDIA_TYPE_AUDIO && rtpmap->param.slen) {
 
127
                si->fmt.channel_cnt = (unsigned) pj_strtoul(&rtpmap->param);
 
128
            } else {
 
129
                si->fmt.channel_cnt = 1;
 
130
            }
 
131
 
 
132
        } else {
 
133
            const pjmedia_codec_info *p_info;
 
134
 
 
135
            status = pjmedia_codec_mgr_get_codec_info( mgr, pt, &p_info);
 
136
            if (status != PJ_SUCCESS)
 
137
                return status;
 
138
 
 
139
            pj_memcpy(&si->fmt, p_info, sizeof(pjmedia_codec_info));
 
140
        }
 
141
 
 
142
        /* For static payload type, pt's are symetric */
 
143
        si->tx_pt = pt;
 
144
 
 
145
    } else {
 
146
        pjmedia_codec_id codec_id;
 
147
        pj_str_t codec_id_st;
 
148
        const pjmedia_codec_info *p_info;
 
149
 
 
150
        attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP,
 
151
                                           &local_m->desc.fmt[fmti]);
 
152
        if (attr == NULL)
 
153
            return PJMEDIA_EMISSINGRTPMAP;
 
154
 
 
155
        status = pjmedia_sdp_attr_to_rtpmap(pool, attr, &rtpmap);
 
156
        if (status != PJ_SUCCESS)
 
157
            return status;
 
158
 
 
159
        /* Build codec format info: */
 
160
 
 
161
        si->fmt.type = si->type;
 
162
        si->fmt.pt = pj_strtoul(&local_m->desc.fmt[fmti]);
 
163
        si->fmt.encoding_name = rtpmap->enc_name;
 
164
        si->fmt.clock_rate = rtpmap->clock_rate;
 
165
 
 
166
        /* For audio codecs, rtpmap parameters denotes the number of
 
167
         * channels.
 
168
         */
 
169
        if (si->type == PJMEDIA_TYPE_AUDIO && rtpmap->param.slen) {
 
170
            si->fmt.channel_cnt = (unsigned) pj_strtoul(&rtpmap->param);
 
171
        } else {
 
172
            si->fmt.channel_cnt = 1;
 
173
        }
 
174
 
 
175
        /* Normalize the codec info from codec manager. Note that the
 
176
         * payload type will be resetted to its default (it might have
 
177
         * been rewritten by the SDP negotiator to match to the remote
 
178
         * offer), this is intentional as currently some components may
 
179
         * prefer (or even require) the default PT in codec info.
 
180
         */
 
181
        pjmedia_codec_info_to_id(&si->fmt, codec_id, sizeof(codec_id));
 
182
 
 
183
        i = 1;
 
184
        codec_id_st = pj_str(codec_id);
 
185
        status = pjmedia_codec_mgr_find_codecs_by_id(mgr, &codec_id_st,
 
186
                                                     &i, &p_info, NULL);
 
187
        if (status != PJ_SUCCESS)
 
188
            return status;
 
189
 
 
190
        pj_memcpy(&si->fmt, p_info, sizeof(pjmedia_codec_info));
 
191
 
 
192
        /* Determine payload type for outgoing channel, by finding
 
193
         * dynamic payload type in remote SDP that matches the answer.
 
194
         */
 
195
        si->tx_pt = 0xFFFF;
 
196
        for (i=0; i<rem_m->desc.fmt_count; ++i) {
 
197
            unsigned rpt;
 
198
            pjmedia_sdp_attr *r_attr;
 
199
            pjmedia_sdp_rtpmap r_rtpmap;
 
200
 
 
201
            rpt = pj_strtoul(&rem_m->desc.fmt[i]);
 
202
            if (rpt < 96)
 
203
                continue;
 
204
 
 
205
            r_attr = pjmedia_sdp_media_find_attr(rem_m, &ID_RTPMAP,
 
206
                                                 &rem_m->desc.fmt[i]);
 
207
            if (!r_attr)
 
208
                continue;
 
209
 
 
210
            if (pjmedia_sdp_attr_get_rtpmap(r_attr, &r_rtpmap) != PJ_SUCCESS)
 
211
                continue;
 
212
 
 
213
            if (!pj_stricmp(&rtpmap->enc_name, &r_rtpmap.enc_name) &&
 
214
                rtpmap->clock_rate == r_rtpmap.clock_rate)
 
215
            {
 
216
                /* Found matched codec. */
 
217
                si->tx_pt = rpt;
 
218
 
 
219
                break;
 
220
            }
 
221
        }
 
222
 
 
223
        if (si->tx_pt == 0xFFFF)
 
224
            return PJMEDIA_EMISSINGRTPMAP;
 
225
    }
 
226
 
 
227
 
 
228
    /* Now that we have codec info, get the codec param. */
 
229
    si->param = PJ_POOL_ALLOC_T(pool, pjmedia_codec_param);
 
230
    status = pjmedia_codec_mgr_get_default_param(mgr, &si->fmt,
 
231
                                                 si->param);
 
232
 
 
233
    /* Get remote fmtp for our encoder. */
 
234
    pjmedia_stream_info_parse_fmtp(pool, rem_m, si->tx_pt,
 
235
                                   &si->param->setting.enc_fmtp);
 
236
 
 
237
    /* Get local fmtp for our decoder. */
 
238
    pjmedia_stream_info_parse_fmtp(pool, local_m, si->rx_pt,
 
239
                                   &si->param->setting.dec_fmtp);
 
240
 
 
241
    /* Get the remote ptime for our encoder. */
 
242
    attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr,
 
243
                                  "ptime", NULL);
 
244
    if (attr) {
 
245
        pj_str_t tmp_val = attr->value;
 
246
        unsigned frm_per_pkt;
 
247
 
 
248
        pj_strltrim(&tmp_val);
 
249
 
 
250
        /* Round up ptime when the specified is not multiple of frm_ptime */
 
251
        frm_per_pkt = (pj_strtoul(&tmp_val) +
 
252
                      si->param->info.frm_ptime/2) /
 
253
                      si->param->info.frm_ptime;
 
254
        if (frm_per_pkt != 0) {
 
255
            si->param->setting.frm_per_pkt = (pj_uint8_t)frm_per_pkt;
 
256
        }
 
257
    }
 
258
 
 
259
    /* Get remote maxptime for our encoder. */
 
260
    attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr,
 
261
                                  "maxptime", NULL);
 
262
    if (attr) {
 
263
        pj_str_t tmp_val = attr->value;
 
264
 
 
265
        pj_strltrim(&tmp_val);
 
266
        si->tx_maxptime = pj_strtoul(&tmp_val);
 
267
    }
 
268
 
 
269
    /* When direction is NONE (it means SDP negotiation has failed) we don't
 
270
     * need to return a failure here, as returning failure will cause
 
271
     * the whole SDP to be rejected. See ticket #:
 
272
     *  http://
 
273
     *
 
274
     * Thanks Alain Totouom
 
275
     */
 
276
    if (status != PJ_SUCCESS && si->dir != PJMEDIA_DIR_NONE)
 
277
        return status;
 
278
 
 
279
 
 
280
    /* Get incomming payload type for telephone-events */
 
281
    si->rx_event_pt = -1;
 
282
    for (i=0; i<local_m->attr_count; ++i) {
 
283
        pjmedia_sdp_rtpmap r;
 
284
 
 
285
        attr = local_m->attr[i];
 
286
        if (pj_strcmp(&attr->name, &ID_RTPMAP) != 0)
 
287
            continue;
 
288
        if (pjmedia_sdp_attr_get_rtpmap(attr, &r) != PJ_SUCCESS)
 
289
            continue;
 
290
        if (pj_strcmp(&r.enc_name, &ID_TELEPHONE_EVENT) == 0) {
 
291
            si->rx_event_pt = pj_strtoul(&r.pt);
 
292
            break;
 
293
        }
 
294
    }
 
295
 
 
296
    /* Get outgoing payload type for telephone-events */
 
297
    si->tx_event_pt = -1;
 
298
    for (i=0; i<rem_m->attr_count; ++i) {
 
299
        pjmedia_sdp_rtpmap r;
 
300
 
 
301
        attr = rem_m->attr[i];
 
302
        if (pj_strcmp(&attr->name, &ID_RTPMAP) != 0)
 
303
            continue;
 
304
        if (pjmedia_sdp_attr_get_rtpmap(attr, &r) != PJ_SUCCESS)
 
305
            continue;
 
306
        if (pj_strcmp(&r.enc_name, &ID_TELEPHONE_EVENT) == 0) {
 
307
            si->tx_event_pt = pj_strtoul(&r.pt);
 
308
            break;
 
309
        }
 
310
    }
 
311
 
 
312
    return PJ_SUCCESS;
 
313
}
 
314
 
 
315
 
 
316
 
 
317
/*
 
318
 * Create stream info from SDP media line.
 
319
 */
 
320
PJ_DEF(pj_status_t) pjmedia_stream_info_from_sdp(
 
321
                                           pjmedia_stream_info *si,
 
322
                                           pj_pool_t *pool,
 
323
                                           pjmedia_endpt *endpt,
 
324
                                           const pjmedia_sdp_session *local,
 
325
                                           const pjmedia_sdp_session *remote,
 
326
                                           unsigned stream_idx)
 
327
{
 
328
    pjmedia_codec_mgr *mgr;
 
329
    const pjmedia_sdp_attr *attr;
 
330
    const pjmedia_sdp_media *local_m;
 
331
    const pjmedia_sdp_media *rem_m;
 
332
    const pjmedia_sdp_conn *local_conn;
 
333
    const pjmedia_sdp_conn *rem_conn;
 
334
    int rem_af, local_af;
 
335
    pj_sockaddr local_addr;
 
336
    pj_status_t status;
 
337
 
 
338
 
 
339
    /* Validate arguments: */
 
340
    PJ_ASSERT_RETURN(pool && si && local && remote, PJ_EINVAL);
 
341
    PJ_ASSERT_RETURN(stream_idx < local->media_count, PJ_EINVAL);
 
342
    PJ_ASSERT_RETURN(stream_idx < remote->media_count, PJ_EINVAL);
 
343
 
 
344
    /* Keep SDP shortcuts */
 
345
    local_m = local->media[stream_idx];
 
346
    rem_m = remote->media[stream_idx];
 
347
 
 
348
    local_conn = local_m->conn ? local_m->conn : local->conn;
 
349
    if (local_conn == NULL)
 
350
        return PJMEDIA_SDP_EMISSINGCONN;
 
351
 
 
352
    rem_conn = rem_m->conn ? rem_m->conn : remote->conn;
 
353
    if (rem_conn == NULL)
 
354
        return PJMEDIA_SDP_EMISSINGCONN;
 
355
 
 
356
    /* Media type must be audio */
 
357
    if (pj_stricmp(&local_m->desc.media, &ID_AUDIO) != 0)
 
358
        return PJMEDIA_EINVALIMEDIATYPE;
 
359
 
 
360
    /* Get codec manager. */
 
361
    mgr = pjmedia_endpt_get_codec_mgr(endpt);
 
362
 
 
363
    /* Reset: */
 
364
 
 
365
    pj_bzero(si, sizeof(*si));
 
366
 
 
367
#if PJMEDIA_HAS_RTCP_XR && PJMEDIA_STREAM_ENABLE_XR
 
368
    /* Set default RTCP XR enabled/disabled */
 
369
    si->rtcp_xr_enabled = PJ_TRUE;
 
370
#endif
 
371
 
 
372
    /* Media type: */
 
373
    si->type = PJMEDIA_TYPE_AUDIO;
 
374
 
 
375
    /* Transport protocol */
 
376
 
 
377
    /* At this point, transport type must be compatible,
 
378
     * the transport instance will do more validation later.
 
379
     */
 
380
    status = pjmedia_sdp_transport_cmp(&rem_m->desc.transport,
 
381
                                       &local_m->desc.transport);
 
382
    if (status != PJ_SUCCESS)
 
383
        return PJMEDIA_SDPNEG_EINVANSTP;
 
384
 
 
385
    if (pj_stricmp(&local_m->desc.transport, &ID_RTP_AVP) == 0) {
 
386
 
 
387
        si->proto = PJMEDIA_TP_PROTO_RTP_AVP;
 
388
 
 
389
    } else if (pj_stricmp(&local_m->desc.transport, &ID_RTP_SAVP) == 0) {
 
390
 
 
391
        si->proto = PJMEDIA_TP_PROTO_RTP_SAVP;
 
392
 
 
393
    } else {
 
394
 
 
395
        si->proto = PJMEDIA_TP_PROTO_UNKNOWN;
 
396
        return PJ_SUCCESS;
 
397
    }
 
398
 
 
399
 
 
400
    /* Check address family in remote SDP */
 
401
    rem_af = pj_AF_UNSPEC();
 
402
    if (pj_stricmp(&rem_conn->net_type, &ID_IN)==0) {
 
403
        if (pj_stricmp(&rem_conn->addr_type, &ID_IP4)==0) {
 
404
            rem_af = pj_AF_INET();
 
405
        } else if (pj_stricmp(&rem_conn->addr_type, &ID_IP6)==0) {
 
406
            rem_af = pj_AF_INET6();
 
407
        }
 
408
    }
 
409
 
 
410
    if (rem_af==pj_AF_UNSPEC()) {
 
411
        /* Unsupported address family */
 
412
        return PJ_EAFNOTSUP;
 
413
    }
 
414
 
 
415
    /* Set remote address: */
 
416
    status = pj_sockaddr_init(rem_af, &si->rem_addr, &rem_conn->addr,
 
417
                              rem_m->desc.port);
 
418
    if (status != PJ_SUCCESS) {
 
419
        /* Invalid IP address. */
 
420
        return PJMEDIA_EINVALIDIP;
 
421
    }
 
422
 
 
423
    /* Check address family of local info */
 
424
    local_af = pj_AF_UNSPEC();
 
425
    if (pj_stricmp(&local_conn->net_type, &ID_IN)==0) {
 
426
        if (pj_stricmp(&local_conn->addr_type, &ID_IP4)==0) {
 
427
            local_af = pj_AF_INET();
 
428
        } else if (pj_stricmp(&local_conn->addr_type, &ID_IP6)==0) {
 
429
            local_af = pj_AF_INET6();
 
430
        }
 
431
    }
 
432
 
 
433
    if (local_af==pj_AF_UNSPEC()) {
 
434
        /* Unsupported address family */
 
435
        return PJ_SUCCESS;
 
436
    }
 
437
 
 
438
    /* Set remote address: */
 
439
    status = pj_sockaddr_init(local_af, &local_addr, &local_conn->addr,
 
440
                              local_m->desc.port);
 
441
    if (status != PJ_SUCCESS) {
 
442
        /* Invalid IP address. */
 
443
        return PJMEDIA_EINVALIDIP;
 
444
    }
 
445
 
 
446
    /* Local and remote address family must match */
 
447
    if (local_af != rem_af)
 
448
        return PJ_EAFNOTSUP;
 
449
 
 
450
    /* Media direction: */
 
451
 
 
452
    if (local_m->desc.port == 0 ||
 
453
        pj_sockaddr_has_addr(&local_addr)==PJ_FALSE ||
 
454
        pj_sockaddr_has_addr(&si->rem_addr)==PJ_FALSE ||
 
455
        pjmedia_sdp_media_find_attr(local_m, &STR_INACTIVE, NULL)!=NULL)
 
456
    {
 
457
        /* Inactive stream. */
 
458
 
 
459
        si->dir = PJMEDIA_DIR_NONE;
 
460
 
 
461
    } else if (pjmedia_sdp_media_find_attr(local_m, &STR_SENDONLY, NULL)!=NULL) {
 
462
 
 
463
        /* Send only stream. */
 
464
 
 
465
        si->dir = PJMEDIA_DIR_ENCODING;
 
466
 
 
467
    } else if (pjmedia_sdp_media_find_attr(local_m, &STR_RECVONLY, NULL)!=NULL) {
 
468
 
 
469
        /* Recv only stream. */
 
470
 
 
471
        si->dir = PJMEDIA_DIR_DECODING;
 
472
 
 
473
    } else {
 
474
 
 
475
        /* Send and receive stream. */
 
476
 
 
477
        si->dir = PJMEDIA_DIR_ENCODING_DECODING;
 
478
 
 
479
    }
 
480
 
 
481
    /* No need to do anything else if stream is rejected */
 
482
    if (local_m->desc.port == 0) {
 
483
        return PJ_SUCCESS;
 
484
    }
 
485
 
 
486
    /* If "rtcp" attribute is present in the SDP, set the RTCP address
 
487
     * from that attribute. Otherwise, calculate from RTP address.
 
488
     */
 
489
    attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr,
 
490
                                  "rtcp", NULL);
 
491
    if (attr) {
 
492
        pjmedia_sdp_rtcp_attr rtcp;
 
493
        status = pjmedia_sdp_attr_get_rtcp(attr, &rtcp);
 
494
        if (status == PJ_SUCCESS) {
 
495
            if (rtcp.addr.slen) {
 
496
                status = pj_sockaddr_init(rem_af, &si->rem_rtcp, &rtcp.addr,
 
497
                                          (pj_uint16_t)rtcp.port);
 
498
            } else {
 
499
                pj_sockaddr_init(rem_af, &si->rem_rtcp, NULL,
 
500
                                 (pj_uint16_t)rtcp.port);
 
501
                pj_memcpy(pj_sockaddr_get_addr(&si->rem_rtcp),
 
502
                          pj_sockaddr_get_addr(&si->rem_addr),
 
503
                          pj_sockaddr_get_addr_len(&si->rem_addr));
 
504
            }
 
505
        }
 
506
    }
 
507
 
 
508
    if (!pj_sockaddr_has_addr(&si->rem_rtcp)) {
 
509
        int rtcp_port;
 
510
 
 
511
        pj_memcpy(&si->rem_rtcp, &si->rem_addr, sizeof(pj_sockaddr));
 
512
        rtcp_port = pj_sockaddr_get_port(&si->rem_addr) + 1;
 
513
        pj_sockaddr_set_port(&si->rem_rtcp, (pj_uint16_t)rtcp_port);
 
514
    }
 
515
 
 
516
 
 
517
    /* Get the payload number for receive channel. */
 
518
    /*
 
519
       Previously we used to rely on fmt[0] being the selected codec,
 
520
       but some UA sends telephone-event as fmt[0] and this would
 
521
       cause assert failure below.
 
522
 
 
523
       Thanks Chris Hamilton <chamilton .at. cs.dal.ca> for this patch.
 
524
 
 
525
    // And codec must be numeric!
 
526
    if (!pj_isdigit(*local_m->desc.fmt[0].ptr) ||
 
527
        !pj_isdigit(*rem_m->desc.fmt[0].ptr))
 
528
    {
 
529
        return PJMEDIA_EINVALIDPT;
 
530
    }
 
531
 
 
532
    pt = pj_strtoul(&local_m->desc.fmt[0]);
 
533
    pj_assert(PJMEDIA_RTP_PT_TELEPHONE_EVENTS==0 ||
 
534
              pt != PJMEDIA_RTP_PT_TELEPHONE_EVENTS);
 
535
    */
 
536
 
 
537
    /* Get codec info and param */
 
538
    status = get_audio_codec_info_param(si, pool, mgr, local_m, rem_m);
 
539
 
 
540
    /* Leave SSRC to random. */
 
541
    si->ssrc = pj_rand();
 
542
 
 
543
    /* Set default jitter buffer parameter. */
 
544
    si->jb_init = si->jb_max = si->jb_min_pre = si->jb_max_pre = -1;
 
545
 
 
546
    return status;
 
547
}
 
548