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

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.0.1/pjsip/src/pjsua-lib/pjsua_media.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: pjsua_media.c 4182 2012-06-27 07:12:23Z 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 <pjsua-lib/pjsua.h>
21
 
#include <pjsua-lib/pjsua_internal.h>
22
 
 
23
 
 
24
 
#define THIS_FILE               "pjsua_media.c"
25
 
 
26
 
#define DEFAULT_RTP_PORT        4000
27
 
 
28
 
#ifndef PJSUA_REQUIRE_CONSECUTIVE_RTCP_PORT
29
 
#   define PJSUA_REQUIRE_CONSECUTIVE_RTCP_PORT  0
30
 
#endif
31
 
 
32
 
/* Next RTP port to be used */
33
 
static pj_uint16_t next_rtp_port;
34
 
 
35
 
static void pjsua_media_config_dup(pj_pool_t *pool,
36
 
                                   pjsua_media_config *dst,
37
 
                                   const pjsua_media_config *src)
38
 
{
39
 
    pj_memcpy(dst, src, sizeof(*src));
40
 
    pj_strdup(pool, &dst->turn_server, &src->turn_server);
41
 
    pj_stun_auth_cred_dup(pool, &dst->turn_auth_cred, &src->turn_auth_cred);
42
 
}
43
 
 
44
 
 
45
 
/**
46
 
 * Init media subsystems.
47
 
 */
48
 
pj_status_t pjsua_media_subsys_init(const pjsua_media_config *cfg)
49
 
{
50
 
    pj_status_t status;
51
 
 
52
 
    pj_log_push_indent();
53
 
 
54
 
    /* Specify which audio device settings are save-able */
55
 
    pjsua_var.aud_svmask = 0xFFFFFFFF;
56
 
    /* These are not-settable */
57
 
    pjsua_var.aud_svmask &= ~(PJMEDIA_AUD_DEV_CAP_EXT_FORMAT |
58
 
                              PJMEDIA_AUD_DEV_CAP_INPUT_SIGNAL_METER |
59
 
                              PJMEDIA_AUD_DEV_CAP_OUTPUT_SIGNAL_METER);
60
 
    /* EC settings use different API */
61
 
    pjsua_var.aud_svmask &= ~(PJMEDIA_AUD_DEV_CAP_EC |
62
 
                              PJMEDIA_AUD_DEV_CAP_EC_TAIL);
63
 
 
64
 
    /* Copy configuration */
65
 
    pjsua_media_config_dup(pjsua_var.pool, &pjsua_var.media_cfg, cfg);
66
 
 
67
 
    /* Normalize configuration */
68
 
    if (pjsua_var.media_cfg.snd_clock_rate == 0) {
69
 
        pjsua_var.media_cfg.snd_clock_rate = pjsua_var.media_cfg.clock_rate;
70
 
    }
71
 
 
72
 
    if (pjsua_var.media_cfg.has_ioqueue &&
73
 
        pjsua_var.media_cfg.thread_cnt == 0)
74
 
    {
75
 
        pjsua_var.media_cfg.thread_cnt = 1;
76
 
    }
77
 
 
78
 
    if (pjsua_var.media_cfg.max_media_ports < pjsua_var.ua_cfg.max_calls) {
79
 
        pjsua_var.media_cfg.max_media_ports = pjsua_var.ua_cfg.max_calls + 2;
80
 
    }
81
 
 
82
 
    /* Create media endpoint. */
83
 
    status = pjmedia_endpt_create(&pjsua_var.cp.factory,
84
 
                                  pjsua_var.media_cfg.has_ioqueue? NULL :
85
 
                                     pjsip_endpt_get_ioqueue(pjsua_var.endpt),
86
 
                                  pjsua_var.media_cfg.thread_cnt,
87
 
                                  &pjsua_var.med_endpt);
88
 
    if (status != PJ_SUCCESS) {
89
 
        pjsua_perror(THIS_FILE,
90
 
                     "Media stack initialization has returned error",
91
 
                     status);
92
 
        goto on_error;
93
 
    }
94
 
 
95
 
    status = pjsua_aud_subsys_init();
96
 
    if (status != PJ_SUCCESS)
97
 
        goto on_error;
98
 
 
99
 
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
100
 
    /* Initialize SRTP library (ticket #788). */
101
 
    status = pjmedia_srtp_init_lib(pjsua_var.med_endpt);
102
 
    if (status != PJ_SUCCESS) {
103
 
        pjsua_perror(THIS_FILE, "Error initializing SRTP library",
104
 
                     status);
105
 
        goto on_error;
106
 
    }
107
 
#endif
108
 
 
109
 
    /* Video */
110
 
#if PJMEDIA_HAS_VIDEO
111
 
    status = pjsua_vid_subsys_init();
112
 
    if (status != PJ_SUCCESS)
113
 
        goto on_error;
114
 
#endif
115
 
 
116
 
    pj_log_pop_indent();
117
 
    return PJ_SUCCESS;
118
 
 
119
 
on_error:
120
 
    pj_log_pop_indent();
121
 
    return status;
122
 
}
123
 
 
124
 
/*
125
 
 * Start pjsua media subsystem.
126
 
 */
127
 
pj_status_t pjsua_media_subsys_start(void)
128
 
{
129
 
    pj_status_t status;
130
 
 
131
 
    pj_log_push_indent();
132
 
 
133
 
#if DISABLED_FOR_TICKET_1185
134
 
    /* Create media for calls, if none is specified */
135
 
    if (pjsua_var.calls[0].media[0].tp == NULL) {
136
 
        pjsua_transport_config transport_cfg;
137
 
 
138
 
        /* Create default transport config */
139
 
        pjsua_transport_config_default(&transport_cfg);
140
 
        transport_cfg.port = DEFAULT_RTP_PORT;
141
 
 
142
 
        status = pjsua_media_transports_create(&transport_cfg);
143
 
        if (status != PJ_SUCCESS) {
144
 
            pj_log_pop_indent();
145
 
            return status;
146
 
        }
147
 
    }
148
 
#endif
149
 
 
150
 
    /* Audio */
151
 
    status = pjsua_aud_subsys_start();
152
 
    if (status != PJ_SUCCESS) {
153
 
        pj_log_pop_indent();
154
 
        return status;
155
 
    }
156
 
 
157
 
    /* Video */
158
 
#if PJMEDIA_HAS_VIDEO
159
 
    status = pjsua_vid_subsys_start();
160
 
    if (status != PJ_SUCCESS) {
161
 
        pjsua_aud_subsys_destroy();
162
 
        pj_log_pop_indent();
163
 
        return status;
164
 
    }
165
 
#endif
166
 
 
167
 
    /* Perform NAT detection */
168
 
    status = pjsua_detect_nat_type();
169
 
    if (status != PJ_SUCCESS) {
170
 
        PJ_PERROR(1,(THIS_FILE, status, "NAT type detection failed"));
171
 
    }
172
 
 
173
 
    pj_log_pop_indent();
174
 
    return PJ_SUCCESS;
175
 
}
176
 
 
177
 
 
178
 
/*
179
 
 * Destroy pjsua media subsystem.
180
 
 */
181
 
pj_status_t pjsua_media_subsys_destroy(unsigned flags)
182
 
{
183
 
    unsigned i;
184
 
 
185
 
    PJ_LOG(4,(THIS_FILE, "Shutting down media.."));
186
 
    pj_log_push_indent();
187
 
 
188
 
    if (pjsua_var.med_endpt) {
189
 
        pjsua_aud_subsys_destroy();
190
 
    }
191
 
 
192
 
    /* Close media transports */
193
 
    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
194
 
        /* TODO: check if we're not allowed to send to network in the
195
 
         *       "flags", and if so do not do TURN allocation...
196
 
         */
197
 
        PJ_UNUSED_ARG(flags);
198
 
        pjsua_media_channel_deinit(i);
199
 
    }
200
 
 
201
 
    /* Destroy media endpoint. */
202
 
    if (pjsua_var.med_endpt) {
203
 
 
204
 
#       if PJMEDIA_HAS_VIDEO
205
 
            pjsua_vid_subsys_destroy();
206
 
#       endif
207
 
 
208
 
        pjmedia_endpt_destroy(pjsua_var.med_endpt);
209
 
        pjsua_var.med_endpt = NULL;
210
 
 
211
 
        /* Deinitialize sound subsystem */
212
 
        // Not necessary, as pjmedia_snd_deinit() should have been called
213
 
        // in pjmedia_endpt_destroy().
214
 
        //pjmedia_snd_deinit();
215
 
    }
216
 
 
217
 
    /* Reset RTP port */
218
 
    next_rtp_port = 0;
219
 
 
220
 
    pj_log_pop_indent();
221
 
 
222
 
    return PJ_SUCCESS;
223
 
}
224
 
 
225
 
/*
226
 
 * Create RTP and RTCP socket pair, and possibly resolve their public
227
 
 * address via STUN.
228
 
 */
229
 
static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg,
230
 
                                        pjmedia_sock_info *skinfo)
231
 
{
232
 
    enum {
233
 
        RTP_RETRY = 100
234
 
    };
235
 
    int i;
236
 
    pj_sockaddr_in bound_addr;
237
 
    pj_sockaddr_in mapped_addr[2];
238
 
    pj_status_t status = PJ_SUCCESS;
239
 
    char addr_buf[PJ_INET6_ADDRSTRLEN+2];
240
 
    pj_sock_t sock[2];
241
 
 
242
 
    /* Make sure STUN server resolution has completed */
243
 
    status = resolve_stun_server(PJ_TRUE);
244
 
    if (status != PJ_SUCCESS) {
245
 
        pjsua_perror(THIS_FILE, "Error resolving STUN server", status);
246
 
        return status;
247
 
    }
248
 
 
249
 
    if (next_rtp_port == 0)
250
 
        next_rtp_port = (pj_uint16_t)cfg->port;
251
 
 
252
 
    if (next_rtp_port == 0)
253
 
        next_rtp_port = (pj_uint16_t)40000;
254
 
 
255
 
    for (i=0; i<2; ++i)
256
 
        sock[i] = PJ_INVALID_SOCKET;
257
 
 
258
 
    bound_addr.sin_addr.s_addr = PJ_INADDR_ANY;
259
 
    if (cfg->bound_addr.slen) {
260
 
        status = pj_sockaddr_in_set_str_addr(&bound_addr, &cfg->bound_addr);
261
 
        if (status != PJ_SUCCESS) {
262
 
            pjsua_perror(THIS_FILE, "Unable to resolve transport bind address",
263
 
                         status);
264
 
            return status;
265
 
        }
266
 
    }
267
 
 
268
 
    /* Loop retry to bind RTP and RTCP sockets. */
269
 
    for (i=0; i<RTP_RETRY; ++i, next_rtp_port += 2) {
270
 
 
271
 
        /* Create RTP socket. */
272
 
        status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[0]);
273
 
        if (status != PJ_SUCCESS) {
274
 
            pjsua_perror(THIS_FILE, "socket() error", status);
275
 
            return status;
276
 
        }
277
 
 
278
 
        /* Apply QoS to RTP socket, if specified */
279
 
        status = pj_sock_apply_qos2(sock[0], cfg->qos_type,
280
 
                                    &cfg->qos_params,
281
 
                                    2, THIS_FILE, "RTP socket");
282
 
 
283
 
        /* Bind RTP socket */
284
 
        status=pj_sock_bind_in(sock[0], pj_ntohl(bound_addr.sin_addr.s_addr),
285
 
                               next_rtp_port);
286
 
        if (status != PJ_SUCCESS) {
287
 
            pj_sock_close(sock[0]);
288
 
            sock[0] = PJ_INVALID_SOCKET;
289
 
            continue;
290
 
        }
291
 
 
292
 
        /* Create RTCP socket. */
293
 
        status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[1]);
294
 
        if (status != PJ_SUCCESS) {
295
 
            pjsua_perror(THIS_FILE, "socket() error", status);
296
 
            pj_sock_close(sock[0]);
297
 
            return status;
298
 
        }
299
 
 
300
 
        /* Apply QoS to RTCP socket, if specified */
301
 
        status = pj_sock_apply_qos2(sock[1], cfg->qos_type,
302
 
                                    &cfg->qos_params,
303
 
                                    2, THIS_FILE, "RTCP socket");
304
 
 
305
 
        /* Bind RTCP socket */
306
 
        status=pj_sock_bind_in(sock[1], pj_ntohl(bound_addr.sin_addr.s_addr),
307
 
                               (pj_uint16_t)(next_rtp_port+1));
308
 
        if (status != PJ_SUCCESS) {
309
 
            pj_sock_close(sock[0]);
310
 
            sock[0] = PJ_INVALID_SOCKET;
311
 
 
312
 
            pj_sock_close(sock[1]);
313
 
            sock[1] = PJ_INVALID_SOCKET;
314
 
            continue;
315
 
        }
316
 
 
317
 
        /*
318
 
         * If we're configured to use STUN, then find out the mapped address,
319
 
         * and make sure that the mapped RTCP port is adjacent with the RTP.
320
 
         */
321
 
        if (pjsua_var.stun_srv.addr.sa_family != 0) {
322
 
            char ip_addr[32];
323
 
            pj_str_t stun_srv;
324
 
 
325
 
            pj_ansi_strcpy(ip_addr,
326
 
                           pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr));
327
 
            stun_srv = pj_str(ip_addr);
328
 
 
329
 
            status=pjstun_get_mapped_addr(&pjsua_var.cp.factory, 2, sock,
330
 
                                           &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port),
331
 
                                           &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port),
332
 
                                           mapped_addr);
333
 
            if (status != PJ_SUCCESS) {
334
 
                pjsua_perror(THIS_FILE, "STUN resolve error", status);
335
 
                goto on_error;
336
 
            }
337
 
 
338
 
#if PJSUA_REQUIRE_CONSECUTIVE_RTCP_PORT
339
 
            if (pj_ntohs(mapped_addr[1].sin_port) ==
340
 
                pj_ntohs(mapped_addr[0].sin_port)+1)
341
 
            {
342
 
                /* Success! */
343
 
                break;
344
 
            }
345
 
 
346
 
            pj_sock_close(sock[0]);
347
 
            sock[0] = PJ_INVALID_SOCKET;
348
 
 
349
 
            pj_sock_close(sock[1]);
350
 
            sock[1] = PJ_INVALID_SOCKET;
351
 
#else
352
 
            if (pj_ntohs(mapped_addr[1].sin_port) !=
353
 
                pj_ntohs(mapped_addr[0].sin_port)+1)
354
 
            {
355
 
                PJ_LOG(4,(THIS_FILE,
356
 
                          "Note: STUN mapped RTCP port %d is not adjacent"
357
 
                          " to RTP port %d",
358
 
                          pj_ntohs(mapped_addr[1].sin_port),
359
 
                          pj_ntohs(mapped_addr[0].sin_port)));
360
 
            }
361
 
            /* Success! */
362
 
            break;
363
 
#endif
364
 
 
365
 
        } else if (cfg->public_addr.slen) {
366
 
 
367
 
            status = pj_sockaddr_in_init(&mapped_addr[0], &cfg->public_addr,
368
 
                                         (pj_uint16_t)next_rtp_port);
369
 
            if (status != PJ_SUCCESS)
370
 
                goto on_error;
371
 
 
372
 
            status = pj_sockaddr_in_init(&mapped_addr[1], &cfg->public_addr,
373
 
                                         (pj_uint16_t)(next_rtp_port+1));
374
 
            if (status != PJ_SUCCESS)
375
 
                goto on_error;
376
 
 
377
 
            break;
378
 
 
379
 
        } else {
380
 
 
381
 
            if (bound_addr.sin_addr.s_addr == 0) {
382
 
                pj_sockaddr addr;
383
 
 
384
 
                /* Get local IP address. */
385
 
                status = pj_gethostip(pj_AF_INET(), &addr);
386
 
                if (status != PJ_SUCCESS)
387
 
                    goto on_error;
388
 
 
389
 
                bound_addr.sin_addr.s_addr = addr.ipv4.sin_addr.s_addr;
390
 
            }
391
 
 
392
 
            for (i=0; i<2; ++i) {
393
 
                pj_sockaddr_in_init(&mapped_addr[i], NULL, 0);
394
 
                mapped_addr[i].sin_addr.s_addr = bound_addr.sin_addr.s_addr;
395
 
            }
396
 
 
397
 
            mapped_addr[0].sin_port=pj_htons((pj_uint16_t)next_rtp_port);
398
 
            mapped_addr[1].sin_port=pj_htons((pj_uint16_t)(next_rtp_port+1));
399
 
            break;
400
 
        }
401
 
    }
402
 
 
403
 
    if (sock[0] == PJ_INVALID_SOCKET) {
404
 
        PJ_LOG(1,(THIS_FILE,
405
 
                  "Unable to find appropriate RTP/RTCP ports combination"));
406
 
        goto on_error;
407
 
    }
408
 
 
409
 
 
410
 
    skinfo->rtp_sock = sock[0];
411
 
    pj_memcpy(&skinfo->rtp_addr_name,
412
 
              &mapped_addr[0], sizeof(pj_sockaddr_in));
413
 
 
414
 
    skinfo->rtcp_sock = sock[1];
415
 
    pj_memcpy(&skinfo->rtcp_addr_name,
416
 
              &mapped_addr[1], sizeof(pj_sockaddr_in));
417
 
 
418
 
    PJ_LOG(4,(THIS_FILE, "RTP socket reachable at %s",
419
 
              pj_sockaddr_print(&skinfo->rtp_addr_name, addr_buf,
420
 
                                sizeof(addr_buf), 3)));
421
 
    PJ_LOG(4,(THIS_FILE, "RTCP socket reachable at %s",
422
 
              pj_sockaddr_print(&skinfo->rtcp_addr_name, addr_buf,
423
 
                                sizeof(addr_buf), 3)));
424
 
 
425
 
    next_rtp_port += 2;
426
 
    return PJ_SUCCESS;
427
 
 
428
 
on_error:
429
 
    for (i=0; i<2; ++i) {
430
 
        if (sock[i] != PJ_INVALID_SOCKET)
431
 
            pj_sock_close(sock[i]);
432
 
    }
433
 
    return status;
434
 
}
435
 
 
436
 
/* Create normal UDP media transports */
437
 
static pj_status_t create_udp_media_transport(const pjsua_transport_config *cfg,
438
 
                                              pjsua_call_media *call_med)
439
 
{
440
 
    pjmedia_sock_info skinfo;
441
 
    pj_status_t status;
442
 
 
443
 
    status = create_rtp_rtcp_sock(cfg, &skinfo);
444
 
    if (status != PJ_SUCCESS) {
445
 
        pjsua_perror(THIS_FILE, "Unable to create RTP/RTCP socket",
446
 
                     status);
447
 
        goto on_error;
448
 
    }
449
 
 
450
 
    status = pjmedia_transport_udp_attach(pjsua_var.med_endpt, NULL,
451
 
                                          &skinfo, 0, &call_med->tp);
452
 
    if (status != PJ_SUCCESS) {
453
 
        pjsua_perror(THIS_FILE, "Unable to create media transport",
454
 
                     status);
455
 
        goto on_error;
456
 
    }
457
 
 
458
 
    pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_ENCODING,
459
 
                                    pjsua_var.media_cfg.tx_drop_pct);
460
 
 
461
 
    pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_DECODING,
462
 
                                    pjsua_var.media_cfg.rx_drop_pct);
463
 
 
464
 
    call_med->tp_ready = PJ_SUCCESS;
465
 
 
466
 
    return PJ_SUCCESS;
467
 
 
468
 
on_error:
469
 
    if (call_med->tp)
470
 
        pjmedia_transport_close(call_med->tp);
471
 
 
472
 
    return status;
473
 
}
474
 
 
475
 
#if DISABLED_FOR_TICKET_1185
476
 
/* Create normal UDP media transports */
477
 
static pj_status_t create_udp_media_transports(pjsua_transport_config *cfg)
478
 
{
479
 
    unsigned i;
480
 
    pj_status_t status;
481
 
 
482
 
    for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) {
483
 
        pjsua_call *call = &pjsua_var.calls[i];
484
 
        unsigned strm_idx;
485
 
 
486
 
        for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) {
487
 
            pjsua_call_media *call_med = &call->media[strm_idx];
488
 
 
489
 
            status = create_udp_media_transport(cfg, &call_med->tp);
490
 
            if (status != PJ_SUCCESS)
491
 
                goto on_error;
492
 
        }
493
 
    }
494
 
 
495
 
    return PJ_SUCCESS;
496
 
 
497
 
on_error:
498
 
    for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) {
499
 
        pjsua_call *call = &pjsua_var.calls[i];
500
 
        unsigned strm_idx;
501
 
 
502
 
        for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) {
503
 
            pjsua_call_media *call_med = &call->media[strm_idx];
504
 
 
505
 
            if (call_med->tp) {
506
 
                pjmedia_transport_close(call_med->tp);
507
 
                call_med->tp = NULL;
508
 
            }
509
 
        }
510
 
    }
511
 
    return status;
512
 
}
513
 
#endif
514
 
 
515
 
static void med_tp_timer_cb(void *user_data)
516
 
{
517
 
    pjsua_call_media *call_med = (pjsua_call_media*)user_data;
518
 
    pjsua_call *call = NULL;
519
 
    pjsip_dialog *dlg = NULL;
520
 
 
521
 
    acquire_call("med_tp_timer_cb", call_med->call->index, &call, &dlg);
522
 
 
523
 
    call_med->tp_ready = call_med->tp_result;
524
 
    if (call_med->med_create_cb)
525
 
        (*call_med->med_create_cb)(call_med, call_med->tp_ready,
526
 
                                   call_med->call->secure_level, NULL);
527
 
 
528
 
    if (dlg)
529
 
        pjsip_dlg_dec_lock(dlg);
530
 
}
531
 
 
532
 
/* This callback is called when ICE negotiation completes */
533
 
static void on_ice_complete(pjmedia_transport *tp,
534
 
                            pj_ice_strans_op op,
535
 
                            pj_status_t result)
536
 
{
537
 
    pjsua_call_media *call_med = (pjsua_call_media*)tp->user_data;
538
 
 
539
 
    if (!call_med)
540
 
        return;
541
 
 
542
 
    switch (op) {
543
 
    case PJ_ICE_STRANS_OP_INIT:
544
 
        call_med->tp_result = result;
545
 
        pjsua_schedule_timer2(&med_tp_timer_cb, call_med, 1);
546
 
        break;
547
 
    case PJ_ICE_STRANS_OP_NEGOTIATION:
548
 
        if (result != PJ_SUCCESS) {
549
 
            call_med->state = PJSUA_CALL_MEDIA_ERROR;
550
 
            call_med->dir = PJMEDIA_DIR_NONE;
551
 
 
552
 
            if (call_med->call && pjsua_var.ua_cfg.cb.on_call_media_state) {
553
 
                pjsua_var.ua_cfg.cb.on_call_media_state(call_med->call->index);
554
 
            }
555
 
        } else if (call_med->call) {
556
 
            /* Send UPDATE if default transport address is different than
557
 
             * what was advertised (ticket #881)
558
 
             */
559
 
            pjmedia_transport_info tpinfo;
560
 
            pjmedia_ice_transport_info *ii = NULL;
561
 
            unsigned i;
562
 
 
563
 
            pjmedia_transport_info_init(&tpinfo);
564
 
            pjmedia_transport_get_info(tp, &tpinfo);
565
 
            for (i=0; i<tpinfo.specific_info_cnt; ++i) {
566
 
                if (tpinfo.spc_info[i].type==PJMEDIA_TRANSPORT_TYPE_ICE) {
567
 
                    ii = (pjmedia_ice_transport_info*)
568
 
                         tpinfo.spc_info[i].buffer;
569
 
                    break;
570
 
                }
571
 
            }
572
 
 
573
 
            if (ii && ii->role==PJ_ICE_SESS_ROLE_CONTROLLING &&
574
 
                pj_sockaddr_cmp(&tpinfo.sock_info.rtp_addr_name,
575
 
                                &call_med->rtp_addr))
576
 
            {
577
 
                pj_bool_t use_update;
578
 
                const pj_str_t STR_UPDATE = { "UPDATE", 6 };
579
 
                pjsip_dialog_cap_status support_update;
580
 
                pjsip_dialog *dlg;
581
 
 
582
 
                dlg = call_med->call->inv->dlg;
583
 
                support_update = pjsip_dlg_remote_has_cap(dlg, PJSIP_H_ALLOW,
584
 
                                                          NULL, &STR_UPDATE);
585
 
                use_update = (support_update == PJSIP_DIALOG_CAP_SUPPORTED);
586
 
 
587
 
                PJ_LOG(4,(THIS_FILE,
588
 
                          "ICE default transport address has changed for "
589
 
                          "call %d, sending %s",
590
 
                          call_med->call->index,
591
 
                          (use_update ? "UPDATE" : "re-INVITE")));
592
 
 
593
 
                if (use_update)
594
 
                    pjsua_call_update(call_med->call->index, 0, NULL);
595
 
                else
596
 
                    pjsua_call_reinvite(call_med->call->index, 0, NULL);
597
 
            }
598
 
        }
599
 
        break;
600
 
    case PJ_ICE_STRANS_OP_KEEP_ALIVE:
601
 
        if (result != PJ_SUCCESS) {
602
 
            PJ_PERROR(4,(THIS_FILE, result,
603
 
                         "ICE keep alive failure for transport %d:%d",
604
 
                         call_med->call->index, call_med->idx));
605
 
        }
606
 
        if (pjsua_var.ua_cfg.cb.on_call_media_transport_state) {
607
 
            pjsua_med_tp_state_info info;
608
 
 
609
 
            pj_bzero(&info, sizeof(info));
610
 
            info.med_idx = call_med->idx;
611
 
            info.state = call_med->tp_st;
612
 
            info.status = result;
613
 
            info.ext_info = &op;
614
 
            (*pjsua_var.ua_cfg.cb.on_call_media_transport_state)(
615
 
                call_med->call->index, &info);
616
 
        }
617
 
        if (pjsua_var.ua_cfg.cb.on_ice_transport_error) {
618
 
            pjsua_call_id id = call_med->call->index;
619
 
            (*pjsua_var.ua_cfg.cb.on_ice_transport_error)(id, op, result,
620
 
                                                          NULL);
621
 
        }
622
 
        break;
623
 
    }
624
 
}
625
 
 
626
 
 
627
 
/* Parse "HOST:PORT" format */
628
 
static pj_status_t parse_host_port(const pj_str_t *host_port,
629
 
                                   pj_str_t *host, pj_uint16_t *port)
630
 
{
631
 
    pj_str_t str_port;
632
 
 
633
 
    str_port.ptr = pj_strchr(host_port, ':');
634
 
    if (str_port.ptr != NULL) {
635
 
        int iport;
636
 
 
637
 
        host->ptr = host_port->ptr;
638
 
        host->slen = (str_port.ptr - host->ptr);
639
 
        str_port.ptr++;
640
 
        str_port.slen = host_port->slen - host->slen - 1;
641
 
        iport = (int)pj_strtoul(&str_port);
642
 
        if (iport < 1 || iport > 65535)
643
 
            return PJ_EINVAL;
644
 
        *port = (pj_uint16_t)iport;
645
 
    } else {
646
 
        *host = *host_port;
647
 
        *port = 0;
648
 
    }
649
 
 
650
 
    return PJ_SUCCESS;
651
 
}
652
 
 
653
 
/* Create ICE media transports (when ice is enabled) */
654
 
static pj_status_t create_ice_media_transport(
655
 
                                const pjsua_transport_config *cfg,
656
 
                                pjsua_call_media *call_med,
657
 
                                pj_bool_t async)
658
 
{
659
 
    char stunip[PJ_INET6_ADDRSTRLEN];
660
 
    pj_ice_strans_cfg ice_cfg;
661
 
    pjmedia_ice_cb ice_cb;
662
 
    char name[32];
663
 
    unsigned comp_cnt;
664
 
    pj_status_t status;
665
 
 
666
 
    /* Make sure STUN server resolution has completed */
667
 
    status = resolve_stun_server(PJ_TRUE);
668
 
    if (status != PJ_SUCCESS) {
669
 
        pjsua_perror(THIS_FILE, "Error resolving STUN server", status);
670
 
        return status;
671
 
    }
672
 
 
673
 
    /* Create ICE stream transport configuration */
674
 
    pj_ice_strans_cfg_default(&ice_cfg);
675
 
    pj_stun_config_init(&ice_cfg.stun_cfg, &pjsua_var.cp.factory, 0,
676
 
                        pjsip_endpt_get_ioqueue(pjsua_var.endpt),
677
 
                        pjsip_endpt_get_timer_heap(pjsua_var.endpt));
678
 
 
679
 
    ice_cfg.af = pj_AF_INET();
680
 
    ice_cfg.resolver = pjsua_var.resolver;
681
 
 
682
 
    ice_cfg.opt = pjsua_var.media_cfg.ice_opt;
683
 
 
684
 
    /* Configure STUN settings */
685
 
    if (pj_sockaddr_has_addr(&pjsua_var.stun_srv)) {
686
 
        pj_sockaddr_print(&pjsua_var.stun_srv, stunip, sizeof(stunip), 0);
687
 
        ice_cfg.stun.server = pj_str(stunip);
688
 
        ice_cfg.stun.port = pj_sockaddr_get_port(&pjsua_var.stun_srv);
689
 
    }
690
 
    if (pjsua_var.media_cfg.ice_max_host_cands >= 0)
691
 
        ice_cfg.stun.max_host_cands = pjsua_var.media_cfg.ice_max_host_cands;
692
 
 
693
 
    /* Copy QoS setting to STUN setting */
694
 
    ice_cfg.stun.cfg.qos_type = cfg->qos_type;
695
 
    pj_memcpy(&ice_cfg.stun.cfg.qos_params, &cfg->qos_params,
696
 
              sizeof(cfg->qos_params));
697
 
 
698
 
    /* Configure TURN settings */
699
 
    if (pjsua_var.media_cfg.enable_turn) {
700
 
        status = parse_host_port(&pjsua_var.media_cfg.turn_server,
701
 
                                 &ice_cfg.turn.server,
702
 
                                 &ice_cfg.turn.port);
703
 
        if (status != PJ_SUCCESS || ice_cfg.turn.server.slen == 0) {
704
 
            PJ_LOG(1,(THIS_FILE, "Invalid TURN server setting"));
705
 
            return PJ_EINVAL;
706
 
        }
707
 
        if (ice_cfg.turn.port == 0)
708
 
            ice_cfg.turn.port = 3479;
709
 
        ice_cfg.turn.conn_type = pjsua_var.media_cfg.turn_conn_type;
710
 
        pj_memcpy(&ice_cfg.turn.auth_cred,
711
 
                  &pjsua_var.media_cfg.turn_auth_cred,
712
 
                  sizeof(ice_cfg.turn.auth_cred));
713
 
 
714
 
        /* Copy QoS setting to TURN setting */
715
 
        ice_cfg.turn.cfg.qos_type = cfg->qos_type;
716
 
        pj_memcpy(&ice_cfg.turn.cfg.qos_params, &cfg->qos_params,
717
 
                  sizeof(cfg->qos_params));
718
 
    }
719
 
 
720
 
    pj_bzero(&ice_cb, sizeof(pjmedia_ice_cb));
721
 
    ice_cb.on_ice_complete = &on_ice_complete;
722
 
    pj_ansi_snprintf(name, sizeof(name), "icetp%02d", call_med->idx);
723
 
    call_med->tp_ready = PJ_EPENDING;
724
 
 
725
 
    comp_cnt = 1;
726
 
    if (PJMEDIA_ADVERTISE_RTCP && !pjsua_var.media_cfg.ice_no_rtcp)
727
 
        ++comp_cnt;
728
 
 
729
 
    status = pjmedia_ice_create3(pjsua_var.med_endpt, name, comp_cnt,
730
 
                                 &ice_cfg, &ice_cb, 0, call_med,
731
 
                                 &call_med->tp);
732
 
    if (status != PJ_SUCCESS) {
733
 
        pjsua_perror(THIS_FILE, "Unable to create ICE media transport",
734
 
                     status);
735
 
        goto on_error;
736
 
    }
737
 
 
738
 
    /* Wait until transport is initialized, or time out */
739
 
    if (!async) {
740
 
        pj_bool_t has_pjsua_lock = PJSUA_LOCK_IS_LOCKED();
741
 
        if (has_pjsua_lock)
742
 
            PJSUA_UNLOCK();
743
 
        while (call_med->tp_ready == PJ_EPENDING) {
744
 
            pjsua_handle_events(100);
745
 
        }
746
 
        if (has_pjsua_lock)
747
 
            PJSUA_LOCK();
748
 
    }
749
 
 
750
 
    if (async && call_med->tp_ready == PJ_EPENDING) {
751
 
        return PJ_EPENDING;
752
 
    } else if (call_med->tp_ready != PJ_SUCCESS) {
753
 
        pjsua_perror(THIS_FILE, "Error initializing ICE media transport",
754
 
                     call_med->tp_ready);
755
 
        status = call_med->tp_ready;
756
 
        goto on_error;
757
 
    }
758
 
 
759
 
    pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_ENCODING,
760
 
                                    pjsua_var.media_cfg.tx_drop_pct);
761
 
 
762
 
    pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_DECODING,
763
 
                                    pjsua_var.media_cfg.rx_drop_pct);
764
 
 
765
 
    return PJ_SUCCESS;
766
 
 
767
 
on_error:
768
 
    if (call_med->tp != NULL) {
769
 
        pjmedia_transport_close(call_med->tp);
770
 
        call_med->tp = NULL;
771
 
    }
772
 
 
773
 
    return status;
774
 
}
775
 
 
776
 
#if DISABLED_FOR_TICKET_1185
777
 
/* Create ICE media transports (when ice is enabled) */
778
 
static pj_status_t create_ice_media_transports(pjsua_transport_config *cfg)
779
 
{
780
 
    unsigned i;
781
 
    pj_status_t status;
782
 
 
783
 
    for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) {
784
 
        pjsua_call *call = &pjsua_var.calls[i];
785
 
        unsigned strm_idx;
786
 
 
787
 
        for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) {
788
 
            pjsua_call_media *call_med = &call->media[strm_idx];
789
 
 
790
 
            status = create_ice_media_transport(cfg, call_med);
791
 
            if (status != PJ_SUCCESS)
792
 
                goto on_error;
793
 
        }
794
 
    }
795
 
 
796
 
    return PJ_SUCCESS;
797
 
 
798
 
on_error:
799
 
    for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) {
800
 
        pjsua_call *call = &pjsua_var.calls[i];
801
 
        unsigned strm_idx;
802
 
 
803
 
        for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) {
804
 
            pjsua_call_media *call_med = &call->media[strm_idx];
805
 
 
806
 
            if (call_med->tp) {
807
 
                pjmedia_transport_close(call_med->tp);
808
 
                call_med->tp = NULL;
809
 
            }
810
 
        }
811
 
    }
812
 
    return status;
813
 
}
814
 
#endif
815
 
 
816
 
#if DISABLED_FOR_TICKET_1185
817
 
/*
818
 
 * Create media transports for all the calls. This function creates
819
 
 * one UDP media transport for each call.
820
 
 */
821
 
PJ_DEF(pj_status_t) pjsua_media_transports_create(
822
 
                        const pjsua_transport_config *app_cfg)
823
 
{
824
 
    pjsua_transport_config cfg;
825
 
    unsigned i;
826
 
    pj_status_t status;
827
 
 
828
 
 
829
 
    /* Make sure pjsua_init() has been called */
830
 
    PJ_ASSERT_RETURN(pjsua_var.ua_cfg.max_calls>0, PJ_EINVALIDOP);
831
 
 
832
 
    PJSUA_LOCK();
833
 
 
834
 
    /* Delete existing media transports */
835
 
    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
836
 
        pjsua_call *call = &pjsua_var.calls[i];
837
 
        unsigned strm_idx;
838
 
 
839
 
        for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) {
840
 
            pjsua_call_media *call_med = &call->media[strm_idx];
841
 
 
842
 
            if (call_med->tp && call_med->tp_auto_del) {
843
 
                pjmedia_transport_close(call_med->tp);
844
 
                call_med->tp = NULL;
845
 
                call_med->tp_orig = NULL;
846
 
            }
847
 
        }
848
 
    }
849
 
 
850
 
    /* Copy config */
851
 
    pjsua_transport_config_dup(pjsua_var.pool, &cfg, app_cfg);
852
 
 
853
 
    /* Create the transports */
854
 
    if (pjsua_var.media_cfg.enable_ice) {
855
 
        status = create_ice_media_transports(&cfg);
856
 
    } else {
857
 
        status = create_udp_media_transports(&cfg);
858
 
    }
859
 
 
860
 
    /* Set media transport auto_delete to True */
861
 
    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
862
 
        pjsua_call *call = &pjsua_var.calls[i];
863
 
        unsigned strm_idx;
864
 
 
865
 
        for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) {
866
 
            pjsua_call_media *call_med = &call->media[strm_idx];
867
 
 
868
 
            call_med->tp_auto_del = PJ_TRUE;
869
 
        }
870
 
    }
871
 
 
872
 
    PJSUA_UNLOCK();
873
 
 
874
 
    return status;
875
 
}
876
 
 
877
 
/*
878
 
 * Attach application's created media transports.
879
 
 */
880
 
PJ_DEF(pj_status_t) pjsua_media_transports_attach(pjsua_media_transport tp[],
881
 
                                                  unsigned count,
882
 
                                                  pj_bool_t auto_delete)
883
 
{
884
 
    unsigned i;
885
 
 
886
 
    PJ_ASSERT_RETURN(tp && count==pjsua_var.ua_cfg.max_calls, PJ_EINVAL);
887
 
 
888
 
    /* Assign the media transports */
889
 
    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
890
 
        pjsua_call *call = &pjsua_var.calls[i];
891
 
        unsigned strm_idx;
892
 
 
893
 
        for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) {
894
 
            pjsua_call_media *call_med = &call->media[strm_idx];
895
 
 
896
 
            if (call_med->tp && call_med->tp_auto_del) {
897
 
                pjmedia_transport_close(call_med->tp);
898
 
                call_med->tp = NULL;
899
 
                call_med->tp_orig = NULL;
900
 
            }
901
 
        }
902
 
 
903
 
        PJ_TODO(remove_pjsua_media_transports_attach);
904
 
 
905
 
        call->media[0].tp = tp[i].transport;
906
 
        call->media[0].tp_auto_del = auto_delete;
907
 
    }
908
 
 
909
 
    return PJ_SUCCESS;
910
 
}
911
 
#endif
912
 
 
913
 
/* Go through the list of media in the SDP, find acceptable media, and
914
 
 * sort them based on the "quality" of the media, and store the indexes
915
 
 * in the specified array. Media with the best quality will be listed
916
 
 * first in the array. The quality factors considered currently is
917
 
 * encryption.
918
 
 */
919
 
static void sort_media(const pjmedia_sdp_session *sdp,
920
 
                       const pj_str_t *type,
921
 
                       pjmedia_srtp_use use_srtp,
922
 
                       pj_uint8_t midx[],
923
 
                       unsigned *p_count,
924
 
                       unsigned *p_total_count)
925
 
{
926
 
    unsigned i;
927
 
    unsigned count = 0;
928
 
    int score[PJSUA_MAX_CALL_MEDIA];
929
 
 
930
 
    pj_assert(*p_count >= PJSUA_MAX_CALL_MEDIA);
931
 
    pj_assert(*p_total_count >= PJSUA_MAX_CALL_MEDIA);
932
 
 
933
 
    *p_count = 0;
934
 
    *p_total_count = 0;
935
 
    for (i=0; i<PJSUA_MAX_CALL_MEDIA; ++i)
936
 
        score[i] = 1;
937
 
 
938
 
    /* Score each media */
939
 
    for (i=0; i<sdp->media_count && count<PJSUA_MAX_CALL_MEDIA; ++i) {
940
 
        const pjmedia_sdp_media *m = sdp->media[i];
941
 
        const pjmedia_sdp_conn *c;
942
 
 
943
 
        /* Skip different media */
944
 
        if (pj_stricmp(&m->desc.media, type) != 0) {
945
 
            score[count++] = -22000;
946
 
            continue;
947
 
        }
948
 
 
949
 
        c = m->conn? m->conn : sdp->conn;
950
 
 
951
 
        /* Supported transports */
952
 
        if (pj_stricmp2(&m->desc.transport, "RTP/SAVP")==0) {
953
 
            switch (use_srtp) {
954
 
            case PJMEDIA_SRTP_MANDATORY:
955
 
            case PJMEDIA_SRTP_OPTIONAL:
956
 
                ++score[i];
957
 
                break;
958
 
            case PJMEDIA_SRTP_DISABLED:
959
 
                //--score[i];
960
 
                score[i] -= 5;
961
 
                break;
962
 
            }
963
 
        } else if (pj_stricmp2(&m->desc.transport, "RTP/AVP")==0) {
964
 
            switch (use_srtp) {
965
 
            case PJMEDIA_SRTP_MANDATORY:
966
 
                //--score[i];
967
 
                score[i] -= 5;
968
 
                break;
969
 
            case PJMEDIA_SRTP_OPTIONAL:
970
 
                /* No change in score */
971
 
                break;
972
 
            case PJMEDIA_SRTP_DISABLED:
973
 
                ++score[i];
974
 
                break;
975
 
            }
976
 
        } else {
977
 
            score[i] -= 10;
978
 
        }
979
 
 
980
 
        /* Is media disabled? */
981
 
        if (m->desc.port == 0)
982
 
            score[i] -= 10;
983
 
 
984
 
        /* Is media inactive? */
985
 
        if (pjmedia_sdp_media_find_attr2(m, "inactive", NULL) ||
986
 
            pj_strcmp2(&c->addr, "0.0.0.0") == 0)
987
 
        {
988
 
            //score[i] -= 10;
989
 
            score[i] -= 1;
990
 
        }
991
 
 
992
 
        ++count;
993
 
    }
994
 
 
995
 
    /* Created sorted list based on quality */
996
 
    for (i=0; i<count; ++i) {
997
 
        unsigned j;
998
 
        int best = 0;
999
 
 
1000
 
        for (j=1; j<count; ++j) {
1001
 
            if (score[j] > score[best])
1002
 
                best = j;
1003
 
        }
1004
 
        /* Don't put media with negative score, that media is unacceptable
1005
 
         * for us.
1006
 
         */
1007
 
        midx[i] = (pj_uint8_t)best;
1008
 
        if (score[best] >= 0)
1009
 
            (*p_count)++;
1010
 
        if (score[best] > -22000)
1011
 
            (*p_total_count)++;
1012
 
 
1013
 
        score[best] = -22000;
1014
 
 
1015
 
    }
1016
 
}
1017
 
 
1018
 
/* Callback to receive media events */
1019
 
pj_status_t call_media_on_event(pjmedia_event *event,
1020
 
                                void *user_data)
1021
 
{
1022
 
    pjsua_call_media *call_med = (pjsua_call_media*)user_data;
1023
 
    pjsua_call *call = call_med->call;
1024
 
    pj_status_t status = PJ_SUCCESS;
1025
 
 
1026
 
    switch(event->type) {
1027
 
        case PJMEDIA_EVENT_KEYFRAME_MISSING:
1028
 
            if (call->opt.req_keyframe_method & PJSUA_VID_REQ_KEYFRAME_SIP_INFO)
1029
 
            {
1030
 
                pj_timestamp now;
1031
 
 
1032
 
                pj_get_timestamp(&now);
1033
 
                if (pj_elapsed_msec(&call_med->last_req_keyframe, &now) >=
1034
 
                    PJSUA_VID_REQ_KEYFRAME_INTERVAL)
1035
 
                {
1036
 
                    pjsua_msg_data msg_data;
1037
 
                    const pj_str_t SIP_INFO = {"INFO", 4};
1038
 
                    const char *BODY_TYPE = "application/media_control+xml";
1039
 
                    const char *BODY =
1040
 
                        "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1041
 
                        "<media_control><vc_primitive><to_encoder>"
1042
 
                        "<picture_fast_update/>"
1043
 
                        "</to_encoder></vc_primitive></media_control>";
1044
 
 
1045
 
                    PJ_LOG(4,(THIS_FILE,
1046
 
                              "Sending video keyframe request via SIP INFO"));
1047
 
 
1048
 
                    pjsua_msg_data_init(&msg_data);
1049
 
                    pj_cstr(&msg_data.content_type, BODY_TYPE);
1050
 
                    pj_cstr(&msg_data.msg_body, BODY);
1051
 
                    status = pjsua_call_send_request(call->index, &SIP_INFO,
1052
 
                                                     &msg_data);
1053
 
                    if (status != PJ_SUCCESS) {
1054
 
                        pj_perror(3, THIS_FILE, status,
1055
 
                                  "Failed requesting keyframe via SIP INFO");
1056
 
                    } else {
1057
 
                        call_med->last_req_keyframe = now;
1058
 
                    }
1059
 
                }
1060
 
            }
1061
 
            break;
1062
 
 
1063
 
        default:
1064
 
            break;
1065
 
    }
1066
 
 
1067
 
    if (pjsua_var.ua_cfg.cb.on_call_media_event && call) {
1068
 
        (*pjsua_var.ua_cfg.cb.on_call_media_event)(call->index,
1069
 
                                                   call_med->idx, event);
1070
 
    }
1071
 
 
1072
 
    return status;
1073
 
}
1074
 
 
1075
 
/* Set media transport state and notify the application via the callback. */
1076
 
void pjsua_set_media_tp_state(pjsua_call_media *call_med,
1077
 
                              pjsua_med_tp_st tp_st)
1078
 
{
1079
 
    if (pjsua_var.ua_cfg.cb.on_call_media_transport_state &&
1080
 
        call_med->tp_st != tp_st)
1081
 
    {
1082
 
        pjsua_med_tp_state_info info;
1083
 
 
1084
 
        pj_bzero(&info, sizeof(info));
1085
 
        info.med_idx = call_med->idx;
1086
 
        info.state = tp_st;
1087
 
        info.status = call_med->tp_ready;
1088
 
        (*pjsua_var.ua_cfg.cb.on_call_media_transport_state)(
1089
 
            call_med->call->index, &info);
1090
 
    }
1091
 
 
1092
 
    call_med->tp_st = tp_st;
1093
 
}
1094
 
 
1095
 
/* Callback to resume pjsua_call_media_init() after media transport
1096
 
 * creation is completed.
1097
 
 */
1098
 
static pj_status_t call_media_init_cb(pjsua_call_media *call_med,
1099
 
                                      pj_status_t status,
1100
 
                                      int security_level,
1101
 
                                      int *sip_err_code)
1102
 
{
1103
 
    pjsua_acc *acc = &pjsua_var.acc[call_med->call->acc_id];
1104
 
    pjmedia_transport_info tpinfo;
1105
 
    int err_code = 0;
1106
 
 
1107
 
    if (status != PJ_SUCCESS)
1108
 
        goto on_return;
1109
 
 
1110
 
    pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_ENCODING,
1111
 
                                    pjsua_var.media_cfg.tx_drop_pct);
1112
 
 
1113
 
    pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_DECODING,
1114
 
                                    pjsua_var.media_cfg.rx_drop_pct);
1115
 
 
1116
 
    if (call_med->tp_st == PJSUA_MED_TP_CREATING)
1117
 
        pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_IDLE);
1118
 
 
1119
 
    if (!call_med->tp_orig &&
1120
 
        pjsua_var.ua_cfg.cb.on_create_media_transport)
1121
 
    {
1122
 
        call_med->use_custom_med_tp = PJ_TRUE;
1123
 
    } else
1124
 
        call_med->use_custom_med_tp = PJ_FALSE;
1125
 
 
1126
 
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
1127
 
    /* This function may be called when SRTP transport already exists
1128
 
     * (e.g: in re-invite, update), don't need to destroy/re-create.
1129
 
     */
1130
 
    if (!call_med->tp_orig) {
1131
 
        pjmedia_srtp_setting srtp_opt;
1132
 
        pjmedia_transport *srtp = NULL;
1133
 
 
1134
 
        /* Check if SRTP requires secure signaling */
1135
 
        if (acc->cfg.use_srtp != PJMEDIA_SRTP_DISABLED) {
1136
 
            if (security_level < acc->cfg.srtp_secure_signaling) {
1137
 
                err_code = PJSIP_SC_NOT_ACCEPTABLE;
1138
 
                status = PJSIP_ESESSIONINSECURE;
1139
 
                goto on_return;
1140
 
            }
1141
 
        }
1142
 
 
1143
 
        /* Always create SRTP adapter */
1144
 
        pjmedia_srtp_setting_default(&srtp_opt);
1145
 
        srtp_opt.close_member_tp = PJ_TRUE;
1146
 
 
1147
 
        /* If media session has been ever established, let's use remote's
1148
 
         * preference in SRTP usage policy, especially when it is stricter.
1149
 
         */
1150
 
        if (call_med->rem_srtp_use > acc->cfg.use_srtp)
1151
 
            srtp_opt.use = call_med->rem_srtp_use;
1152
 
        else
1153
 
            srtp_opt.use = acc->cfg.use_srtp;
1154
 
 
1155
 
        status = pjmedia_transport_srtp_create(pjsua_var.med_endpt,
1156
 
                                               call_med->tp,
1157
 
                                               &srtp_opt, &srtp);
1158
 
        if (status != PJ_SUCCESS) {
1159
 
            err_code = PJSIP_SC_INTERNAL_SERVER_ERROR;
1160
 
            goto on_return;
1161
 
        }
1162
 
 
1163
 
        /* Set SRTP as current media transport */
1164
 
        call_med->tp_orig = call_med->tp;
1165
 
        call_med->tp = srtp;
1166
 
    }
1167
 
#else
1168
 
    call_med->tp_orig = call_med->tp;
1169
 
    PJ_UNUSED_ARG(security_level);
1170
 
#endif
1171
 
 
1172
 
 
1173
 
    pjmedia_transport_info_init(&tpinfo);
1174
 
    pjmedia_transport_get_info(call_med->tp, &tpinfo);
1175
 
 
1176
 
    pj_sockaddr_cp(&call_med->rtp_addr, &tpinfo.sock_info.rtp_addr_name);
1177
 
 
1178
 
 
1179
 
on_return:
1180
 
    if (status != PJ_SUCCESS && call_med->tp) {
1181
 
        pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
1182
 
        pjmedia_transport_close(call_med->tp);
1183
 
        call_med->tp = NULL;
1184
 
    }
1185
 
 
1186
 
    if (sip_err_code)
1187
 
        *sip_err_code = err_code;
1188
 
 
1189
 
    if (call_med->med_init_cb) {
1190
 
        pjsua_med_tp_state_info info;
1191
 
 
1192
 
        pj_bzero(&info, sizeof(info));
1193
 
        info.status = status;
1194
 
        info.state = call_med->tp_st;
1195
 
        info.med_idx = call_med->idx;
1196
 
        info.sip_err_code = err_code;
1197
 
        (*call_med->med_init_cb)(call_med->call->index, &info);
1198
 
    }
1199
 
 
1200
 
    return status;
1201
 
}
1202
 
 
1203
 
/* Initialize the media line */
1204
 
pj_status_t pjsua_call_media_init(pjsua_call_media *call_med,
1205
 
                                  pjmedia_type type,
1206
 
                                  const pjsua_transport_config *tcfg,
1207
 
                                  int security_level,
1208
 
                                  int *sip_err_code,
1209
 
                                  pj_bool_t async,
1210
 
                                  pjsua_med_tp_state_cb cb)
1211
 
{
1212
 
    pj_status_t status = PJ_SUCCESS;
1213
 
 
1214
 
    /*
1215
 
     * Note: this function may be called when the media already exists
1216
 
     * (e.g. in reinvites, updates, etc.)
1217
 
     */
1218
 
    call_med->type = type;
1219
 
 
1220
 
    /* Create the media transport for initial call. Here are the possible
1221
 
     * media transport state and the action needed:
1222
 
     * - PJSUA_MED_TP_NULL or call_med->tp==NULL, create one.
1223
 
     * - PJSUA_MED_TP_RUNNING, do nothing.
1224
 
     * - PJSUA_MED_TP_DISABLED, re-init (media_create(), etc). Currently,
1225
 
     *   this won't happen as media_channel_update() will always clean up
1226
 
     *   the unused transport of a disabled media.
1227
 
     */
1228
 
    if (call_med->tp == NULL) {
1229
 
#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
1230
 
        /* While in initial call, set default video devices */
1231
 
        if (type == PJMEDIA_TYPE_VIDEO) {
1232
 
            status = pjsua_vid_channel_init(call_med);
1233
 
            if (status != PJ_SUCCESS)
1234
 
                return status;
1235
 
        }
1236
 
#endif
1237
 
 
1238
 
        pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_CREATING);
1239
 
 
1240
 
        if (pjsua_var.media_cfg.enable_ice) {
1241
 
            status = create_ice_media_transport(tcfg, call_med, async);
1242
 
            if (async && status == PJ_EPENDING) {
1243
 
                /* We will resume call media initialization in the
1244
 
                 * on_ice_complete() callback.
1245
 
                 */
1246
 
                call_med->med_create_cb = &call_media_init_cb;
1247
 
                call_med->med_init_cb = cb;
1248
 
 
1249
 
                return PJ_EPENDING;
1250
 
            }
1251
 
        } else {
1252
 
            status = create_udp_media_transport(tcfg, call_med);
1253
 
        }
1254
 
 
1255
 
        if (status != PJ_SUCCESS) {
1256
 
            PJ_PERROR(1,(THIS_FILE, status, "Error creating media transport"));
1257
 
            return status;
1258
 
        }
1259
 
 
1260
 
        /* Media transport creation completed immediately, so
1261
 
         * we don't need to call the callback.
1262
 
         */
1263
 
        call_med->med_init_cb = NULL;
1264
 
 
1265
 
    } else if (call_med->tp_st == PJSUA_MED_TP_DISABLED) {
1266
 
        /* Media is being reenabled. */
1267
 
        //pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_IDLE);
1268
 
 
1269
 
        pj_assert(!"Currently no media transport reuse");
1270
 
    }
1271
 
 
1272
 
    return call_media_init_cb(call_med, status, security_level,
1273
 
                              sip_err_code);
1274
 
}
1275
 
 
1276
 
/* Callback to resume pjsua_media_channel_init() after media transport
1277
 
 * initialization is completed.
1278
 
 */
1279
 
static pj_status_t media_channel_init_cb(pjsua_call_id call_id,
1280
 
                                         const pjsua_med_tp_state_info *info)
1281
 
{
1282
 
    pjsua_call *call = &pjsua_var.calls[call_id];
1283
 
    pj_status_t status = (info? info->status : PJ_SUCCESS);
1284
 
    unsigned mi;
1285
 
 
1286
 
    if (info) {
1287
 
        pj_mutex_lock(call->med_ch_mutex);
1288
 
 
1289
 
        /* Set the callback to NULL to indicate that the async operation
1290
 
         * has completed.
1291
 
         */
1292
 
        call->media_prov[info->med_idx].med_init_cb = NULL;
1293
 
 
1294
 
        /* In case of failure, save the information to be returned
1295
 
         * by the last media transport to finish.
1296
 
         */
1297
 
        if (info->status != PJ_SUCCESS)
1298
 
            pj_memcpy(&call->med_ch_info, info, sizeof(info));
1299
 
 
1300
 
        /* Check whether all the call's medias have finished calling their
1301
 
         * callbacks.
1302
 
         */
1303
 
        for (mi=0; mi < call->med_prov_cnt; ++mi) {
1304
 
            pjsua_call_media *call_med = &call->media_prov[mi];
1305
 
 
1306
 
            if (call_med->med_init_cb) {
1307
 
                pj_mutex_unlock(call->med_ch_mutex);
1308
 
                return PJ_SUCCESS;
1309
 
            }
1310
 
 
1311
 
            if (call_med->tp_ready != PJ_SUCCESS)
1312
 
                status = call_med->tp_ready;
1313
 
        }
1314
 
 
1315
 
        /* OK, we are called by the last media transport finished. */
1316
 
        pj_mutex_unlock(call->med_ch_mutex);
1317
 
    }
1318
 
 
1319
 
    if (call->med_ch_mutex) {
1320
 
        pj_mutex_destroy(call->med_ch_mutex);
1321
 
        call->med_ch_mutex = NULL;
1322
 
    }
1323
 
 
1324
 
    if (status != PJ_SUCCESS) {
1325
 
        if (call->med_ch_info.status == PJ_SUCCESS) {
1326
 
            call->med_ch_info.status = status;
1327
 
            call->med_ch_info.sip_err_code = PJSIP_SC_TEMPORARILY_UNAVAILABLE;
1328
 
        }
1329
 
        pjsua_media_prov_clean_up(call_id);
1330
 
        goto on_return;
1331
 
    }
1332
 
 
1333
 
    /* Tell the media transport of a new offer/answer session */
1334
 
    for (mi=0; mi < call->med_prov_cnt; ++mi) {
1335
 
        pjsua_call_media *call_med = &call->media_prov[mi];
1336
 
 
1337
 
        /* Note: tp may be NULL if this media line is disabled */
1338
 
        if (call_med->tp && call_med->tp_st == PJSUA_MED_TP_IDLE) {
1339
 
            pj_pool_t *tmp_pool = call->async_call.pool_prov;
1340
 
 
1341
 
            if (!tmp_pool) {
1342
 
                tmp_pool = (call->inv? call->inv->pool_prov:
1343
 
                            call->async_call.dlg->pool);
1344
 
            }
1345
 
 
1346
 
            if (call_med->use_custom_med_tp) {
1347
 
                unsigned custom_med_tp_flags = 0;
1348
 
 
1349
 
                /* Use custom media transport returned by the application */
1350
 
                call_med->tp =
1351
 
                    (*pjsua_var.ua_cfg.cb.on_create_media_transport)
1352
 
                        (call_id, mi, call_med->tp,
1353
 
                         custom_med_tp_flags);
1354
 
                if (!call_med->tp) {
1355
 
                    status =
1356
 
                        PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_TEMPORARILY_UNAVAILABLE);
1357
 
                }
1358
 
            }
1359
 
 
1360
 
            if (call_med->tp) {
1361
 
                status = pjmedia_transport_media_create(
1362
 
                             call_med->tp, tmp_pool,
1363
 
                             0, call->async_call.rem_sdp, mi);
1364
 
            }
1365
 
            if (status != PJ_SUCCESS) {
1366
 
                call->med_ch_info.status = status;
1367
 
                call->med_ch_info.med_idx = mi;
1368
 
                call->med_ch_info.state = call_med->tp_st;
1369
 
                call->med_ch_info.sip_err_code = PJSIP_SC_TEMPORARILY_UNAVAILABLE;
1370
 
                pjsua_media_prov_clean_up(call_id);
1371
 
                goto on_return;
1372
 
            }
1373
 
 
1374
 
            pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_INIT);
1375
 
        }
1376
 
    }
1377
 
 
1378
 
    call->med_ch_info.status = PJ_SUCCESS;
1379
 
 
1380
 
on_return:
1381
 
    if (call->med_ch_cb)
1382
 
        (*call->med_ch_cb)(call->index, &call->med_ch_info);
1383
 
 
1384
 
    return status;
1385
 
}
1386
 
 
1387
 
 
1388
 
/* Clean up media transports in provisional media that is not used
1389
 
 * by call media.
1390
 
 */
1391
 
void pjsua_media_prov_clean_up(pjsua_call_id call_id)
1392
 
{
1393
 
    pjsua_call *call = &pjsua_var.calls[call_id];
1394
 
    unsigned i;
1395
 
 
1396
 
    for (i = 0; i < call->med_prov_cnt; ++i) {
1397
 
        pjsua_call_media *call_med = &call->media_prov[i];
1398
 
        unsigned j;
1399
 
        pj_bool_t used = PJ_FALSE;
1400
 
 
1401
 
        if (call_med->tp == NULL)
1402
 
            continue;
1403
 
 
1404
 
        for (j = 0; j < call->med_cnt; ++j) {
1405
 
            if (call->media[j].tp == call_med->tp) {
1406
 
                used = PJ_TRUE;
1407
 
                break;
1408
 
            }
1409
 
        }
1410
 
 
1411
 
        if (!used) {
1412
 
            if (call_med->tp_st > PJSUA_MED_TP_IDLE) {
1413
 
                pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_IDLE);
1414
 
                pjmedia_transport_media_stop(call_med->tp);
1415
 
            }
1416
 
            pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
1417
 
            pjmedia_transport_close(call_med->tp);
1418
 
            call_med->tp = call_med->tp_orig = NULL;
1419
 
        }
1420
 
    }
1421
 
}
1422
 
 
1423
 
 
1424
 
pj_status_t pjsua_media_channel_init(pjsua_call_id call_id,
1425
 
                                     pjsip_role_e role,
1426
 
                                     int security_level,
1427
 
                                     pj_pool_t *tmp_pool,
1428
 
                                     const pjmedia_sdp_session *rem_sdp,
1429
 
                                     int *sip_err_code,
1430
 
                                     pj_bool_t async,
1431
 
                                     pjsua_med_tp_state_cb cb)
1432
 
{
1433
 
    const pj_str_t STR_AUDIO = { "audio", 5 };
1434
 
    const pj_str_t STR_VIDEO = { "video", 5 };
1435
 
    pjsua_call *call = &pjsua_var.calls[call_id];
1436
 
    pjsua_acc *acc = &pjsua_var.acc[call->acc_id];
1437
 
    pj_uint8_t maudidx[PJSUA_MAX_CALL_MEDIA];
1438
 
    unsigned maudcnt = PJ_ARRAY_SIZE(maudidx);
1439
 
    unsigned mtotaudcnt = PJ_ARRAY_SIZE(maudidx);
1440
 
    pj_uint8_t mvididx[PJSUA_MAX_CALL_MEDIA];
1441
 
    unsigned mvidcnt = PJ_ARRAY_SIZE(mvididx);
1442
 
    unsigned mtotvidcnt = PJ_ARRAY_SIZE(mvididx);
1443
 
    unsigned mi;
1444
 
    pj_bool_t pending_med_tp = PJ_FALSE;
1445
 
    pj_bool_t reinit = PJ_FALSE;
1446
 
    pj_status_t status;
1447
 
 
1448
 
    PJ_UNUSED_ARG(role);
1449
 
 
1450
 
    /*
1451
 
     * Note: this function may be called when the media already exists
1452
 
     * (e.g. in reinvites, updates, etc).
1453
 
     */
1454
 
 
1455
 
    if (pjsua_get_state() != PJSUA_STATE_RUNNING)
1456
 
        return PJ_EBUSY;
1457
 
 
1458
 
    if (async) {
1459
 
        pj_pool_t *tmppool = (call->inv? call->inv->pool_prov:
1460
 
                              call->async_call.dlg->pool);
1461
 
 
1462
 
        status = pj_mutex_create_simple(tmppool, NULL, &call->med_ch_mutex);
1463
 
        if (status != PJ_SUCCESS)
1464
 
            return status;
1465
 
    }
1466
 
 
1467
 
    if (call->inv && call->inv->state == PJSIP_INV_STATE_CONFIRMED)
1468
 
        reinit = PJ_TRUE;
1469
 
 
1470
 
    PJ_LOG(4,(THIS_FILE, "Call %d: %sinitializing media..",
1471
 
                         call_id, (reinit?"re-":"") ));
1472
 
 
1473
 
    pj_log_push_indent();
1474
 
 
1475
 
    /* Init provisional media state */
1476
 
    if (call->med_cnt == 0) {
1477
 
        /* New media session, just copy whole from call media state. */
1478
 
        pj_memcpy(call->media_prov, call->media, sizeof(call->media));
1479
 
    } else {
1480
 
        /* Clean up any unused transports. Note that when local SDP reoffer
1481
 
         * is rejected by remote, there may be any initialized transports that
1482
 
         * are not used by call media and currently there is no notification
1483
 
         * from PJSIP level regarding the reoffer rejection.
1484
 
         */
1485
 
        pjsua_media_prov_clean_up(call_id);
1486
 
 
1487
 
        /* Updating media session, copy from call media state. */
1488
 
        pj_memcpy(call->media_prov, call->media,
1489
 
                  sizeof(call->media[0]) * call->med_cnt);
1490
 
    }
1491
 
    call->med_prov_cnt = call->med_cnt;
1492
 
 
1493
 
#if DISABLED_FOR_TICKET_1185
1494
 
    /* Return error if media transport has not been created yet
1495
 
     * (e.g. application is starting)
1496
 
     */
1497
 
    for (i=0; i<call->med_cnt; ++i) {
1498
 
        if (call->media[i].tp == NULL) {
1499
 
            status = PJ_EBUSY;
1500
 
            goto on_error;
1501
 
        }
1502
 
    }
1503
 
#endif
1504
 
 
1505
 
    /* Get media count for each media type */
1506
 
    if (rem_sdp) {
1507
 
        sort_media(rem_sdp, &STR_AUDIO, acc->cfg.use_srtp,
1508
 
                   maudidx, &maudcnt, &mtotaudcnt);
1509
 
        if (maudcnt==0) {
1510
 
            /* Expecting audio in the offer */
1511
 
            if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE_HERE;
1512
 
            status = PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE_HERE);
1513
 
            goto on_error;
1514
 
        }
1515
 
 
1516
 
#if PJMEDIA_HAS_VIDEO
1517
 
        sort_media(rem_sdp, &STR_VIDEO, acc->cfg.use_srtp,
1518
 
                   mvididx, &mvidcnt, &mtotvidcnt);
1519
 
#else
1520
 
        mvidcnt = mtotvidcnt = 0;
1521
 
        PJ_UNUSED_ARG(STR_VIDEO);
1522
 
#endif
1523
 
 
1524
 
        /* Update media count only when remote add any media, this media count
1525
 
         * must never decrease. Also note that we shouldn't apply the media
1526
 
         * count setting (of the call setting) before the SDP negotiation.
1527
 
         */
1528
 
        if (call->med_prov_cnt < rem_sdp->media_count)
1529
 
            call->med_prov_cnt = PJ_MIN(rem_sdp->media_count,
1530
 
                                        PJSUA_MAX_CALL_MEDIA);
1531
 
 
1532
 
        call->rem_offerer = PJ_TRUE;
1533
 
        call->rem_aud_cnt = maudcnt;
1534
 
        call->rem_vid_cnt = mvidcnt;
1535
 
 
1536
 
    } else {
1537
 
 
1538
 
        /* If call already established, calculate media count from current
1539
 
         * local active SDP and call setting. Otherwise, calculate media
1540
 
         * count from the call setting only.
1541
 
         */
1542
 
        if (reinit) {
1543
 
            const pjmedia_sdp_session *sdp;
1544
 
 
1545
 
            status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &sdp);
1546
 
            pj_assert(status == PJ_SUCCESS);
1547
 
 
1548
 
            sort_media(sdp, &STR_AUDIO, acc->cfg.use_srtp,
1549
 
                       maudidx, &maudcnt, &mtotaudcnt);
1550
 
            pj_assert(maudcnt > 0);
1551
 
 
1552
 
            sort_media(sdp, &STR_VIDEO, acc->cfg.use_srtp,
1553
 
                       mvididx, &mvidcnt, &mtotvidcnt);
1554
 
 
1555
 
            /* Call setting may add or remove media. Adding media is done by
1556
 
             * enabling any disabled/port-zeroed media first, then adding new
1557
 
             * media whenever needed. Removing media is done by disabling
1558
 
             * media with the lowest 'quality'.
1559
 
             */
1560
 
 
1561
 
            /* Check if we need to add new audio */
1562
 
            if (maudcnt < call->opt.aud_cnt &&
1563
 
                mtotaudcnt < call->opt.aud_cnt)
1564
 
            {
1565
 
                for (mi = 0; mi < call->opt.aud_cnt - mtotaudcnt; ++mi)
1566
 
                    maudidx[maudcnt++] = (pj_uint8_t)call->med_prov_cnt++;
1567
 
 
1568
 
                mtotaudcnt = call->opt.aud_cnt;
1569
 
            }
1570
 
            maudcnt = call->opt.aud_cnt;
1571
 
 
1572
 
            /* Check if we need to add new video */
1573
 
            if (mvidcnt < call->opt.vid_cnt &&
1574
 
                mtotvidcnt < call->opt.vid_cnt)
1575
 
            {
1576
 
                for (mi = 0; mi < call->opt.vid_cnt - mtotvidcnt; ++mi)
1577
 
                    mvididx[mvidcnt++] = (pj_uint8_t)call->med_prov_cnt++;
1578
 
 
1579
 
                mtotvidcnt = call->opt.vid_cnt;
1580
 
            }
1581
 
            mvidcnt = call->opt.vid_cnt;
1582
 
 
1583
 
        } else {
1584
 
 
1585
 
            maudcnt = mtotaudcnt = call->opt.aud_cnt;
1586
 
            for (mi=0; mi<maudcnt; ++mi) {
1587
 
                maudidx[mi] = (pj_uint8_t)mi;
1588
 
            }
1589
 
            mvidcnt = mtotvidcnt = call->opt.vid_cnt;
1590
 
            for (mi=0; mi<mvidcnt; ++mi) {
1591
 
                mvididx[mi] = (pj_uint8_t)(maudcnt + mi);
1592
 
            }
1593
 
            call->med_prov_cnt = maudcnt + mvidcnt;
1594
 
 
1595
 
            /* Need to publish supported media? */
1596
 
            if (call->opt.flag & PJSUA_CALL_INCLUDE_DISABLED_MEDIA) {
1597
 
                if (mtotaudcnt == 0) {
1598
 
                    mtotaudcnt = 1;
1599
 
                    maudidx[0] = (pj_uint8_t)call->med_prov_cnt++;
1600
 
                }
1601
 
#if PJMEDIA_HAS_VIDEO
1602
 
                if (mtotvidcnt == 0) {
1603
 
                    mtotvidcnt = 1;
1604
 
                    mvididx[0] = (pj_uint8_t)call->med_prov_cnt++;
1605
 
                }
1606
 
#endif
1607
 
            }
1608
 
        }
1609
 
 
1610
 
        call->rem_offerer = PJ_FALSE;
1611
 
    }
1612
 
 
1613
 
    if (call->med_prov_cnt == 0) {
1614
 
        /* Expecting at least one media */
1615
 
        if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE_HERE;
1616
 
        status = PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE_HERE);
1617
 
        goto on_error;
1618
 
    }
1619
 
 
1620
 
    if (async) {
1621
 
        call->med_ch_cb = cb;
1622
 
    }
1623
 
 
1624
 
    if (rem_sdp) {
1625
 
        call->async_call.rem_sdp =
1626
 
            pjmedia_sdp_session_clone(call->inv->pool_prov, rem_sdp);
1627
 
    } else {
1628
 
        call->async_call.rem_sdp = NULL;
1629
 
    }
1630
 
 
1631
 
    call->async_call.pool_prov = tmp_pool;
1632
 
 
1633
 
    /* Initialize each media line */
1634
 
    for (mi=0; mi < call->med_prov_cnt; ++mi) {
1635
 
        pjsua_call_media *call_med = &call->media_prov[mi];
1636
 
        pj_bool_t enabled = PJ_FALSE;
1637
 
        pjmedia_type media_type = PJMEDIA_TYPE_UNKNOWN;
1638
 
 
1639
 
        if (pj_memchr(maudidx, mi, mtotaudcnt * sizeof(maudidx[0]))) {
1640
 
            media_type = PJMEDIA_TYPE_AUDIO;
1641
 
            if (call->opt.aud_cnt &&
1642
 
                pj_memchr(maudidx, mi, maudcnt * sizeof(maudidx[0])))
1643
 
            {
1644
 
                enabled = PJ_TRUE;
1645
 
            }
1646
 
        } else if (pj_memchr(mvididx, mi, mtotvidcnt * sizeof(mvididx[0]))) {
1647
 
            media_type = PJMEDIA_TYPE_VIDEO;
1648
 
            if (call->opt.vid_cnt &&
1649
 
                pj_memchr(mvididx, mi, mvidcnt * sizeof(mvididx[0])))
1650
 
            {
1651
 
                enabled = PJ_TRUE;
1652
 
            }
1653
 
        }
1654
 
 
1655
 
        if (enabled) {
1656
 
            status = pjsua_call_media_init(call_med, media_type,
1657
 
                                           &acc->cfg.rtp_cfg,
1658
 
                                           security_level, sip_err_code,
1659
 
                                           async,
1660
 
                                           (async? &media_channel_init_cb:
1661
 
                                            NULL));
1662
 
            if (status == PJ_EPENDING) {
1663
 
                pending_med_tp = PJ_TRUE;
1664
 
            } else if (status != PJ_SUCCESS) {
1665
 
                if (pending_med_tp) {
1666
 
                    /* Save failure information. */
1667
 
                    call_med->tp_ready = status;
1668
 
                    pj_bzero(&call->med_ch_info, sizeof(call->med_ch_info));
1669
 
                    call->med_ch_info.status = status;
1670
 
                    call->med_ch_info.state = call_med->tp_st;
1671
 
                    call->med_ch_info.med_idx = call_med->idx;
1672
 
                    if (sip_err_code)
1673
 
                        call->med_ch_info.sip_err_code = *sip_err_code;
1674
 
 
1675
 
                    /* We will return failure in the callback later. */
1676
 
                    return PJ_EPENDING;
1677
 
                }
1678
 
 
1679
 
                pjsua_media_prov_clean_up(call_id);
1680
 
                goto on_error;
1681
 
            }
1682
 
        } else {
1683
 
            /* By convention, the media is disabled if transport is NULL
1684
 
             * or transport state is PJSUA_MED_TP_DISABLED.
1685
 
             */
1686
 
            if (call_med->tp) {
1687
 
                // Don't close transport here, as SDP negotiation has not been
1688
 
                // done and stream may be still active. Once SDP negotiation
1689
 
                // is done (channel_update() invoked), this transport will be
1690
 
                // closed there.
1691
 
                //pjmedia_transport_close(call_med->tp);
1692
 
                //call_med->tp = NULL;
1693
 
                pj_assert(call_med->tp_st == PJSUA_MED_TP_INIT ||
1694
 
                          call_med->tp_st == PJSUA_MED_TP_RUNNING);
1695
 
                pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_DISABLED);
1696
 
            }
1697
 
 
1698
 
            /* Put media type just for info */
1699
 
            call_med->type = media_type;
1700
 
        }
1701
 
    }
1702
 
 
1703
 
    call->audio_idx = maudidx[0];
1704
 
 
1705
 
    PJ_LOG(4,(THIS_FILE, "Media index %d selected for audio call %d",
1706
 
              call->audio_idx, call->index));
1707
 
 
1708
 
    if (pending_med_tp) {
1709
 
        /* We shouldn't use temporary pool anymore. */
1710
 
        call->async_call.pool_prov = NULL;
1711
 
        /* We have a pending media transport initialization. */
1712
 
        pj_log_pop_indent();
1713
 
        return PJ_EPENDING;
1714
 
    }
1715
 
 
1716
 
    /* Media transport initialization completed immediately, so
1717
 
     * we don't need to call the callback.
1718
 
     */
1719
 
    call->med_ch_cb = NULL;
1720
 
 
1721
 
    status = media_channel_init_cb(call_id, NULL);
1722
 
    if (status != PJ_SUCCESS && sip_err_code)
1723
 
        *sip_err_code = call->med_ch_info.sip_err_code;
1724
 
 
1725
 
    pj_log_pop_indent();
1726
 
    return status;
1727
 
 
1728
 
on_error:
1729
 
    if (call->med_ch_mutex) {
1730
 
        pj_mutex_destroy(call->med_ch_mutex);
1731
 
        call->med_ch_mutex = NULL;
1732
 
    }
1733
 
 
1734
 
    pj_log_pop_indent();
1735
 
    return status;
1736
 
}
1737
 
 
1738
 
 
1739
 
/* Create SDP based on the current media channel. Note that, this function
1740
 
 * will not modify the media channel, so when receiving new offer or
1741
 
 * updating media count (via call setting), media channel must be reinit'd
1742
 
 * (using pjsua_media_channel_init()) first before calling this function.
1743
 
 */
1744
 
pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id,
1745
 
                                           pj_pool_t *pool,
1746
 
                                           const pjmedia_sdp_session *rem_sdp,
1747
 
                                           pjmedia_sdp_session **p_sdp,
1748
 
                                           int *sip_err_code)
1749
 
{
1750
 
    enum { MAX_MEDIA = PJSUA_MAX_CALL_MEDIA };
1751
 
    pjmedia_sdp_session *sdp;
1752
 
    pj_sockaddr origin;
1753
 
    pjsua_call *call = &pjsua_var.calls[call_id];
1754
 
    pjmedia_sdp_neg_state sdp_neg_state = PJMEDIA_SDP_NEG_STATE_NULL;
1755
 
    unsigned mi;
1756
 
    unsigned tot_bandw_tias = 0;
1757
 
    pj_status_t status;
1758
 
 
1759
 
    if (pjsua_get_state() != PJSUA_STATE_RUNNING)
1760
 
        return PJ_EBUSY;
1761
 
 
1762
 
#if 0
1763
 
    // This function should not really change the media channel.
1764
 
    if (rem_sdp) {
1765
 
        /* If this is a re-offer, let's re-initialize media as remote may
1766
 
         * add or remove media
1767
 
         */
1768
 
        if (call->inv && call->inv->state == PJSIP_INV_STATE_CONFIRMED) {
1769
 
            status = pjsua_media_channel_init(call_id, PJSIP_ROLE_UAS,
1770
 
                                              call->secure_level, pool,
1771
 
                                              rem_sdp, sip_err_code,
1772
 
                                              PJ_FALSE, NULL);
1773
 
            if (status != PJ_SUCCESS)
1774
 
                return status;
1775
 
        }
1776
 
    } else {
1777
 
        /* Audio is first in our offer, by convention */
1778
 
        // The audio_idx should not be changed here, as this function may be
1779
 
        // called in generating re-offer and the current active audio index
1780
 
        // can be anywhere.
1781
 
        //call->audio_idx = 0;
1782
 
    }
1783
 
#endif
1784
 
 
1785
 
#if 0
1786
 
    // Since r3512, old-style hold should have got transport, created by
1787
 
    // pjsua_media_channel_init() in initial offer/answer or remote reoffer.
1788
 
    /* Create media if it's not created. This could happen when call is
1789
 
     * currently on-hold (with the old style hold)
1790
 
     */
1791
 
    if (call->media[call->audio_idx].tp == NULL) {
1792
 
        pjsip_role_e role;
1793
 
        role = (rem_sdp ? PJSIP_ROLE_UAS : PJSIP_ROLE_UAC);
1794
 
        status = pjsua_media_channel_init(call_id, role, call->secure_level,
1795
 
                                          pool, rem_sdp, sip_err_code);
1796
 
        if (status != PJ_SUCCESS)
1797
 
            return status;
1798
 
    }
1799
 
#endif
1800
 
 
1801
 
    /* Get SDP negotiator state */
1802
 
    if (call->inv && call->inv->neg)
1803
 
        sdp_neg_state = pjmedia_sdp_neg_get_state(call->inv->neg);
1804
 
 
1805
 
    /* Get one address to use in the origin field */
1806
 
    pj_bzero(&origin, sizeof(origin));
1807
 
    for (mi=0; mi<call->med_prov_cnt; ++mi) {
1808
 
        pjmedia_transport_info tpinfo;
1809
 
 
1810
 
        if (call->media_prov[mi].tp == NULL)
1811
 
            continue;
1812
 
 
1813
 
        pjmedia_transport_info_init(&tpinfo);
1814
 
        pjmedia_transport_get_info(call->media_prov[mi].tp, &tpinfo);
1815
 
        pj_sockaddr_cp(&origin, &tpinfo.sock_info.rtp_addr_name);
1816
 
        break;
1817
 
    }
1818
 
 
1819
 
    /* Create the base (blank) SDP */
1820
 
    status = pjmedia_endpt_create_base_sdp(pjsua_var.med_endpt, pool, NULL,
1821
 
                                           &origin, &sdp);
1822
 
    if (status != PJ_SUCCESS)
1823
 
        return status;
1824
 
 
1825
 
    /* Process each media line */
1826
 
    for (mi=0; mi<call->med_prov_cnt; ++mi) {
1827
 
        pjsua_call_media *call_med = &call->media_prov[mi];
1828
 
        pjmedia_sdp_media *m = NULL;
1829
 
        pjmedia_transport_info tpinfo;
1830
 
        unsigned i;
1831
 
 
1832
 
        if (rem_sdp && mi >= rem_sdp->media_count) {
1833
 
            /* Remote might have removed some media lines. */
1834
 
            break;
1835
 
        }
1836
 
 
1837
 
        if (call_med->tp == NULL || call_med->tp_st == PJSUA_MED_TP_DISABLED)
1838
 
        {
1839
 
            /*
1840
 
             * This media is disabled. Just create a valid SDP with zero
1841
 
             * port.
1842
 
             */
1843
 
            if (rem_sdp) {
1844
 
                /* Just clone the remote media and deactivate it */
1845
 
                m = pjmedia_sdp_media_clone_deactivate(pool,
1846
 
                                                       rem_sdp->media[mi]);
1847
 
            } else {
1848
 
                m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media);
1849
 
                m->desc.transport = pj_str("RTP/AVP");
1850
 
                m->desc.fmt_count = 1;
1851
 
                m->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
1852
 
                m->conn->net_type = pj_str("IN");
1853
 
                m->conn->addr_type = pj_str("IP4");
1854
 
                m->conn->addr = pj_str("127.0.0.1");
1855
 
 
1856
 
                switch (call_med->type) {
1857
 
                case PJMEDIA_TYPE_AUDIO:
1858
 
                    m->desc.media = pj_str("audio");
1859
 
                    m->desc.fmt[0] = pj_str("0");
1860
 
                    break;
1861
 
                case PJMEDIA_TYPE_VIDEO:
1862
 
                    m->desc.media = pj_str("video");
1863
 
                    m->desc.fmt[0] = pj_str("31");
1864
 
                    break;
1865
 
                default:
1866
 
                    /* This must be us generating re-offer, and some unknown
1867
 
                     * media may exist, so just clone from active local SDP
1868
 
                     * (and it should have been deactivated already).
1869
 
                     */
1870
 
                    pj_assert(call->inv && call->inv->neg &&
1871
 
                              sdp_neg_state == PJMEDIA_SDP_NEG_STATE_DONE);
1872
 
                    {
1873
 
                        const pjmedia_sdp_session *s_;
1874
 
                        pjmedia_sdp_neg_get_active_local(call->inv->neg, &s_);
1875
 
 
1876
 
                        pj_assert(mi < s_->media_count);
1877
 
                        m = pjmedia_sdp_media_clone(pool, s_->media[mi]);
1878
 
                        m->desc.port = 0;
1879
 
                    }
1880
 
                    break;
1881
 
                }
1882
 
            }
1883
 
 
1884
 
            sdp->media[sdp->media_count++] = m;
1885
 
            continue;
1886
 
        }
1887
 
 
1888
 
        /* Get transport address info */
1889
 
        pjmedia_transport_info_init(&tpinfo);
1890
 
        pjmedia_transport_get_info(call_med->tp, &tpinfo);
1891
 
 
1892
 
        /* Ask pjmedia endpoint to create SDP media line */
1893
 
        switch (call_med->type) {
1894
 
        case PJMEDIA_TYPE_AUDIO:
1895
 
            status = pjmedia_endpt_create_audio_sdp(pjsua_var.med_endpt, pool,
1896
 
                                                    &tpinfo.sock_info, 0, &m);
1897
 
            break;
1898
 
#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
1899
 
        case PJMEDIA_TYPE_VIDEO:
1900
 
            status = pjmedia_endpt_create_video_sdp(pjsua_var.med_endpt, pool,
1901
 
                                                    &tpinfo.sock_info, 0, &m);
1902
 
            break;
1903
 
#endif
1904
 
        default:
1905
 
            pj_assert(!"Invalid call_med media type");
1906
 
            return PJ_EBUG;
1907
 
        }
1908
 
 
1909
 
        if (status != PJ_SUCCESS)
1910
 
            return status;
1911
 
 
1912
 
        sdp->media[sdp->media_count++] = m;
1913
 
 
1914
 
        /* Give to transport */
1915
 
        status = pjmedia_transport_encode_sdp(call_med->tp, pool,
1916
 
                                              sdp, rem_sdp, mi);
1917
 
        if (status != PJ_SUCCESS) {
1918
 
            if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE;
1919
 
            return status;
1920
 
        }
1921
 
 
1922
 
        /* Copy c= line of the first media to session level,
1923
 
         * if there's none.
1924
 
         */
1925
 
        if (sdp->conn == NULL) {
1926
 
            sdp->conn = pjmedia_sdp_conn_clone(pool, m->conn);
1927
 
        }
1928
 
 
1929
 
 
1930
 
        /* Find media bandwidth info */
1931
 
        for (i = 0; i < m->bandw_count; ++i) {
1932
 
            const pj_str_t STR_BANDW_MODIFIER_TIAS = { "TIAS", 4 };
1933
 
            if (!pj_stricmp(&m->bandw[i]->modifier, &STR_BANDW_MODIFIER_TIAS))
1934
 
            {
1935
 
                tot_bandw_tias += m->bandw[i]->value;
1936
 
                break;
1937
 
            }
1938
 
        }
1939
 
    }
1940
 
 
1941
 
    /* Add NAT info in the SDP */
1942
 
    if (pjsua_var.ua_cfg.nat_type_in_sdp) {
1943
 
        pjmedia_sdp_attr *a;
1944
 
        pj_str_t value;
1945
 
        char nat_info[80];
1946
 
 
1947
 
        value.ptr = nat_info;
1948
 
        if (pjsua_var.ua_cfg.nat_type_in_sdp == 1) {
1949
 
            value.slen = pj_ansi_snprintf(nat_info, sizeof(nat_info),
1950
 
                                          "%d", pjsua_var.nat_type);
1951
 
        } else {
1952
 
            const char *type_name = pj_stun_get_nat_name(pjsua_var.nat_type);
1953
 
            value.slen = pj_ansi_snprintf(nat_info, sizeof(nat_info),
1954
 
                                          "%d %s",
1955
 
                                          pjsua_var.nat_type,
1956
 
                                          type_name);
1957
 
        }
1958
 
 
1959
 
        a = pjmedia_sdp_attr_create(pool, "X-nat", &value);
1960
 
 
1961
 
        pjmedia_sdp_attr_add(&sdp->attr_count, sdp->attr, a);
1962
 
 
1963
 
    }
1964
 
 
1965
 
 
1966
 
    /* Add bandwidth info in session level using bandwidth modifier "AS". */
1967
 
    if (tot_bandw_tias) {
1968
 
        unsigned bandw;
1969
 
        const pj_str_t STR_BANDW_MODIFIER_AS = { "AS", 2 };
1970
 
        pjmedia_sdp_bandw *b;
1971
 
 
1972
 
        /* AS bandwidth = RTP bitrate + RTCP bitrate.
1973
 
         * RTP bitrate  = payload bitrate (total TIAS) + overheads (~16kbps).
1974
 
         * RTCP bitrate = est. 5% of RTP bitrate.
1975
 
         * Note that AS bandwidth is in kbps.
1976
 
         */
1977
 
        bandw = tot_bandw_tias + 16000;
1978
 
        bandw += bandw * 5 / 100;
1979
 
        b = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_bandw);
1980
 
        b->modifier = STR_BANDW_MODIFIER_AS;
1981
 
        b->value = bandw / 1000;
1982
 
        sdp->bandw[sdp->bandw_count++] = b;
1983
 
    }
1984
 
 
1985
 
 
1986
 
#if DISABLED_FOR_TICKET_1185 && defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
1987
 
    /* Check if SRTP is in optional mode and configured to use duplicated
1988
 
     * media, i.e: secured and unsecured version, in the SDP offer.
1989
 
     */
1990
 
    if (!rem_sdp &&
1991
 
        pjsua_var.acc[call->acc_id].cfg.use_srtp == PJMEDIA_SRTP_OPTIONAL &&
1992
 
        pjsua_var.acc[call->acc_id].cfg.srtp_optional_dup_offer)
1993
 
    {
1994
 
        unsigned i;
1995
 
 
1996
 
        for (i = 0; i < sdp->media_count; ++i) {
1997
 
            pjmedia_sdp_media *m = sdp->media[i];
1998
 
 
1999
 
            /* Check if this media is unsecured but has SDP "crypto"
2000
 
             * attribute.
2001
 
             */
2002
 
            if (pj_stricmp2(&m->desc.transport, "RTP/AVP") == 0 &&
2003
 
                pjmedia_sdp_media_find_attr2(m, "crypto", NULL) != NULL)
2004
 
            {
2005
 
                if (i == (unsigned)call->audio_idx &&
2006
 
                    sdp_neg_state == PJMEDIA_SDP_NEG_STATE_DONE)
2007
 
                {
2008
 
                    /* This is a session update, and peer has chosen the
2009
 
                     * unsecured version, so let's make this unsecured too.
2010
 
                     */
2011
 
                    pjmedia_sdp_media_remove_all_attr(m, "crypto");
2012
 
                } else {
2013
 
                    /* This is new offer, duplicate media so we'll have
2014
 
                     * secured (with "RTP/SAVP" transport) and and unsecured
2015
 
                     * versions.
2016
 
                     */
2017
 
                    pjmedia_sdp_media *new_m;
2018
 
 
2019
 
                    /* Duplicate this media and apply secured transport */
2020
 
                    new_m = pjmedia_sdp_media_clone(pool, m);
2021
 
                    pj_strdup2(pool, &new_m->desc.transport, "RTP/SAVP");
2022
 
 
2023
 
                    /* Remove the "crypto" attribute in the unsecured media */
2024
 
                    pjmedia_sdp_media_remove_all_attr(m, "crypto");
2025
 
 
2026
 
                    /* Insert the new media before the unsecured media */
2027
 
                    if (sdp->media_count < PJMEDIA_MAX_SDP_MEDIA) {
2028
 
                        pj_array_insert(sdp->media, sizeof(new_m),
2029
 
                                        sdp->media_count, i, &new_m);
2030
 
                        ++sdp->media_count;
2031
 
                        ++i;
2032
 
                    }
2033
 
                }
2034
 
            }
2035
 
        }
2036
 
    }
2037
 
#endif
2038
 
 
2039
 
    call->rem_offerer = (rem_sdp != NULL);
2040
 
 
2041
 
    /* Notify application */
2042
 
    if (pjsua_var.ua_cfg.cb.on_call_sdp_created) {
2043
 
        (*pjsua_var.ua_cfg.cb.on_call_sdp_created)(call_id, sdp,
2044
 
                                                   pool, rem_sdp);
2045
 
    }
2046
 
 
2047
 
    *p_sdp = sdp;
2048
 
    return PJ_SUCCESS;
2049
 
}
2050
 
 
2051
 
 
2052
 
static void stop_media_session(pjsua_call_id call_id)
2053
 
{
2054
 
    pjsua_call *call = &pjsua_var.calls[call_id];
2055
 
    unsigned mi;
2056
 
 
2057
 
    pj_log_push_indent();
2058
 
 
2059
 
    for (mi=0; mi<call->med_cnt; ++mi) {
2060
 
        pjsua_call_media *call_med = &call->media[mi];
2061
 
 
2062
 
        if (call_med->type == PJMEDIA_TYPE_AUDIO) {
2063
 
            pjsua_aud_stop_stream(call_med);
2064
 
        }
2065
 
 
2066
 
#if PJMEDIA_HAS_VIDEO
2067
 
        else if (call_med->type == PJMEDIA_TYPE_VIDEO) {
2068
 
            pjsua_vid_stop_stream(call_med);
2069
 
        }
2070
 
#endif
2071
 
 
2072
 
        PJ_LOG(4,(THIS_FILE, "Media session call%02d:%d is destroyed",
2073
 
                             call_id, mi));
2074
 
        call_med->prev_state = call_med->state;
2075
 
        call_med->state = PJSUA_CALL_MEDIA_NONE;
2076
 
 
2077
 
        /* Try to sync recent changes to provisional media */
2078
 
        if (mi<call->med_prov_cnt && call->media_prov[mi].tp==call_med->tp)
2079
 
        {
2080
 
            pjsua_call_media *prov_med = &call->media_prov[mi];
2081
 
 
2082
 
            /* Media state */
2083
 
            prov_med->prev_state = call_med->prev_state;
2084
 
            prov_med->state      = call_med->state;
2085
 
 
2086
 
            /* RTP seq/ts */
2087
 
            prov_med->rtp_tx_seq_ts_set = call_med->rtp_tx_seq_ts_set;
2088
 
            prov_med->rtp_tx_seq        = call_med->rtp_tx_seq;
2089
 
            prov_med->rtp_tx_ts         = call_med->rtp_tx_ts;
2090
 
 
2091
 
            /* Stream */
2092
 
            if (call_med->type == PJMEDIA_TYPE_AUDIO) {
2093
 
                prov_med->strm.a.conf_slot = call_med->strm.a.conf_slot;
2094
 
                prov_med->strm.a.stream    = call_med->strm.a.stream;
2095
 
            }
2096
 
#if PJMEDIA_HAS_VIDEO
2097
 
            else if (call_med->type == PJMEDIA_TYPE_VIDEO) {
2098
 
                prov_med->strm.v.cap_win_id = call_med->strm.v.cap_win_id;
2099
 
                prov_med->strm.v.rdr_win_id = call_med->strm.v.rdr_win_id;
2100
 
                prov_med->strm.v.stream     = call_med->strm.v.stream;
2101
 
            }
2102
 
#endif
2103
 
        }
2104
 
    }
2105
 
 
2106
 
    pj_log_pop_indent();
2107
 
}
2108
 
 
2109
 
pj_status_t pjsua_media_channel_deinit(pjsua_call_id call_id)
2110
 
{
2111
 
    pjsua_call *call = &pjsua_var.calls[call_id];
2112
 
    unsigned mi;
2113
 
 
2114
 
    for (mi=0; mi<call->med_cnt; ++mi) {
2115
 
        pjsua_call_media *call_med = &call->media[mi];
2116
 
 
2117
 
        if (call_med->tp_st == PJSUA_MED_TP_CREATING) {
2118
 
            /* We will do the deinitialization after media transport
2119
 
             * creation is completed.
2120
 
             */
2121
 
            call->async_call.med_ch_deinit = PJ_TRUE;
2122
 
            return PJ_SUCCESS;
2123
 
        }
2124
 
    }
2125
 
 
2126
 
    PJ_LOG(4,(THIS_FILE, "Call %d: deinitializing media..", call_id));
2127
 
    pj_log_push_indent();
2128
 
 
2129
 
    stop_media_session(call_id);
2130
 
 
2131
 
    /* Clean up media transports */
2132
 
    pjsua_media_prov_clean_up(call_id);
2133
 
    call->med_prov_cnt = 0;
2134
 
    for (mi=0; mi<call->med_cnt; ++mi) {
2135
 
        pjsua_call_media *call_med = &call->media[mi];
2136
 
 
2137
 
        if (call_med->tp_st > PJSUA_MED_TP_IDLE) {
2138
 
            pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_IDLE);
2139
 
            pjmedia_transport_media_stop(call_med->tp);
2140
 
        }
2141
 
 
2142
 
        if (call_med->tp) {
2143
 
            pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
2144
 
            pjmedia_transport_close(call_med->tp);
2145
 
            call_med->tp = call_med->tp_orig = NULL;
2146
 
        }
2147
 
        call_med->tp_orig = NULL;
2148
 
    }
2149
 
 
2150
 
    pj_log_pop_indent();
2151
 
 
2152
 
    return PJ_SUCCESS;
2153
 
}
2154
 
 
2155
 
 
2156
 
pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
2157
 
                                       const pjmedia_sdp_session *local_sdp,
2158
 
                                       const pjmedia_sdp_session *remote_sdp)
2159
 
{
2160
 
    pjsua_call *call = &pjsua_var.calls[call_id];
2161
 
    pjsua_acc *acc = &pjsua_var.acc[call->acc_id];
2162
 
    pj_pool_t *tmp_pool = call->inv->pool_prov;
2163
 
    unsigned mi;
2164
 
    pj_bool_t got_media = PJ_FALSE;
2165
 
    pj_status_t status = PJ_SUCCESS;
2166
 
 
2167
 
    const pj_str_t STR_AUDIO = { "audio", 5 };
2168
 
    const pj_str_t STR_VIDEO = { "video", 5 };
2169
 
    pj_uint8_t maudidx[PJSUA_MAX_CALL_MEDIA];
2170
 
    unsigned maudcnt = PJ_ARRAY_SIZE(maudidx);
2171
 
    unsigned mtotaudcnt = PJ_ARRAY_SIZE(maudidx);
2172
 
    pj_uint8_t mvididx[PJSUA_MAX_CALL_MEDIA];
2173
 
    unsigned mvidcnt = PJ_ARRAY_SIZE(mvididx);
2174
 
    unsigned mtotvidcnt = PJ_ARRAY_SIZE(mvididx);
2175
 
    pj_bool_t need_renego_sdp = PJ_FALSE;
2176
 
 
2177
 
    if (pjsua_get_state() != PJSUA_STATE_RUNNING)
2178
 
        return PJ_EBUSY;
2179
 
 
2180
 
    PJ_LOG(4,(THIS_FILE, "Call %d: updating media..", call_id));
2181
 
    pj_log_push_indent();
2182
 
 
2183
 
    /* Destroy existing media session, if any. */
2184
 
    stop_media_session(call->index);
2185
 
 
2186
 
    /* Call media count must be at least equal to SDP media. Note that
2187
 
     * it may not be equal when remote removed any SDP media line.
2188
 
     */
2189
 
    pj_assert(call->med_prov_cnt >= local_sdp->media_count);
2190
 
 
2191
 
    /* Reset audio_idx first */
2192
 
    call->audio_idx = -1;
2193
 
 
2194
 
    /* Sort audio/video based on "quality" */
2195
 
    sort_media(local_sdp, &STR_AUDIO, acc->cfg.use_srtp,
2196
 
               maudidx, &maudcnt, &mtotaudcnt);
2197
 
#if PJMEDIA_HAS_VIDEO
2198
 
    sort_media(local_sdp, &STR_VIDEO, acc->cfg.use_srtp,
2199
 
               mvididx, &mvidcnt, &mtotvidcnt);
2200
 
#else
2201
 
    PJ_UNUSED_ARG(STR_VIDEO);
2202
 
    mvidcnt = mtotvidcnt = 0;
2203
 
#endif
2204
 
 
2205
 
    /* Applying media count limitation. Note that in generating SDP answer,
2206
 
     * no media count limitation applied, as we didn't know yet which media
2207
 
     * would pass the SDP negotiation.
2208
 
     */
2209
 
    if (maudcnt > call->opt.aud_cnt || mvidcnt > call->opt.vid_cnt)
2210
 
    {
2211
 
        pjmedia_sdp_session *local_sdp2;
2212
 
 
2213
 
        maudcnt = PJ_MIN(maudcnt, call->opt.aud_cnt);
2214
 
        mvidcnt = PJ_MIN(mvidcnt, call->opt.vid_cnt);
2215
 
        local_sdp2 = pjmedia_sdp_session_clone(tmp_pool, local_sdp);
2216
 
 
2217
 
        for (mi=0; mi < local_sdp2->media_count; ++mi) {
2218
 
            pjmedia_sdp_media *m = local_sdp2->media[mi];
2219
 
 
2220
 
            if (m->desc.port == 0 ||
2221
 
                pj_memchr(maudidx, mi, maudcnt*sizeof(maudidx[0])) ||
2222
 
                pj_memchr(mvididx, mi, mvidcnt*sizeof(mvididx[0])))
2223
 
            {
2224
 
                continue;
2225
 
            }
2226
 
 
2227
 
            /* Deactivate this media */
2228
 
            pjmedia_sdp_media_deactivate(tmp_pool, m);
2229
 
        }
2230
 
 
2231
 
        local_sdp = local_sdp2;
2232
 
        need_renego_sdp = PJ_TRUE;
2233
 
    }
2234
 
 
2235
 
    /* Process each media stream */
2236
 
    for (mi=0; mi < call->med_prov_cnt; ++mi) {
2237
 
        pjsua_call_media *call_med = &call->media_prov[mi];
2238
 
 
2239
 
        if (mi >= local_sdp->media_count ||
2240
 
            mi >= remote_sdp->media_count)
2241
 
        {
2242
 
            /* This may happen when remote removed any SDP media lines in
2243
 
             * its re-offer.
2244
 
             */
2245
 
            if (call_med->tp) {
2246
 
                /* Close the media transport */
2247
 
                pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
2248
 
                pjmedia_transport_close(call_med->tp);
2249
 
                call_med->tp = call_med->tp_orig = NULL;
2250
 
            }
2251
 
            continue;
2252
 
#if 0
2253
 
            /* Something is wrong */
2254
 
            PJ_LOG(1,(THIS_FILE, "Error updating media for call %d: "
2255
 
                      "invalid media index %d in SDP", call_id, mi));
2256
 
            status = PJMEDIA_SDP_EINSDP;
2257
 
            goto on_error;
2258
 
#endif
2259
 
        }
2260
 
 
2261
 
        if (call_med->type==PJMEDIA_TYPE_AUDIO) {
2262
 
            pjmedia_stream_info the_si, *si = &the_si;
2263
 
 
2264
 
            status = pjmedia_stream_info_from_sdp(si, tmp_pool, pjsua_var.med_endpt,
2265
 
                                                  local_sdp, remote_sdp, mi);
2266
 
            if (status != PJ_SUCCESS) {
2267
 
                PJ_PERROR(1,(THIS_FILE, status,
2268
 
                             "pjmedia_stream_info_from_sdp() failed "
2269
 
                                 "for call_id %d media %d",
2270
 
                             call_id, mi));
2271
 
                continue;
2272
 
            }
2273
 
 
2274
 
            /* Check if no media is active */
2275
 
            if (si->dir == PJMEDIA_DIR_NONE) {
2276
 
                /* Update call media state and direction */
2277
 
                call_med->state = PJSUA_CALL_MEDIA_NONE;
2278
 
                call_med->dir = PJMEDIA_DIR_NONE;
2279
 
 
2280
 
            } else {
2281
 
                pjmedia_transport_info tp_info;
2282
 
 
2283
 
                /* Start/restart media transport based on info in SDP */
2284
 
                status = pjmedia_transport_media_start(call_med->tp,
2285
 
                                                       tmp_pool, local_sdp,
2286
 
                                                       remote_sdp, mi);
2287
 
                if (status != PJ_SUCCESS) {
2288
 
                    PJ_PERROR(1,(THIS_FILE, status,
2289
 
                                 "pjmedia_transport_media_start() failed "
2290
 
                                     "for call_id %d media %d",
2291
 
                                 call_id, mi));
2292
 
                    continue;
2293
 
                }
2294
 
 
2295
 
                pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_RUNNING);
2296
 
 
2297
 
                /* Get remote SRTP usage policy */
2298
 
                pjmedia_transport_info_init(&tp_info);
2299
 
                pjmedia_transport_get_info(call_med->tp, &tp_info);
2300
 
                if (tp_info.specific_info_cnt > 0) {
2301
 
                    unsigned i;
2302
 
                    for (i = 0; i < tp_info.specific_info_cnt; ++i) {
2303
 
                        if (tp_info.spc_info[i].type == PJMEDIA_TRANSPORT_TYPE_SRTP)
2304
 
                        {
2305
 
                            pjmedia_srtp_info *srtp_info =
2306
 
                                        (pjmedia_srtp_info*) tp_info.spc_info[i].buffer;
2307
 
 
2308
 
                            call_med->rem_srtp_use = srtp_info->peer_use;
2309
 
                            break;
2310
 
                        }
2311
 
                    }
2312
 
                }
2313
 
 
2314
 
                /* Call media direction */
2315
 
                call_med->dir = si->dir;
2316
 
 
2317
 
                /* Call media state */
2318
 
                if (call->local_hold)
2319
 
                    call_med->state = PJSUA_CALL_MEDIA_LOCAL_HOLD;
2320
 
                else if (call_med->dir == PJMEDIA_DIR_DECODING)
2321
 
                    call_med->state = PJSUA_CALL_MEDIA_REMOTE_HOLD;
2322
 
                else
2323
 
                    call_med->state = PJSUA_CALL_MEDIA_ACTIVE;
2324
 
            }
2325
 
 
2326
 
            /* Call implementation */
2327
 
            status = pjsua_aud_channel_update(call_med, tmp_pool, si,
2328
 
                                              local_sdp, remote_sdp);
2329
 
            if (status != PJ_SUCCESS) {
2330
 
                PJ_PERROR(1,(THIS_FILE, status,
2331
 
                             "pjsua_aud_channel_update() failed "
2332
 
                                 "for call_id %d media %d",
2333
 
                             call_id, mi));
2334
 
                continue;
2335
 
            }
2336
 
 
2337
 
            /* Print info. */
2338
 
            if (status == PJ_SUCCESS) {
2339
 
                char info[80];
2340
 
                int info_len = 0;
2341
 
                int len;
2342
 
                const char *dir;
2343
 
 
2344
 
                switch (si->dir) {
2345
 
                case PJMEDIA_DIR_NONE:
2346
 
                    dir = "inactive";
2347
 
                    break;
2348
 
                case PJMEDIA_DIR_ENCODING:
2349
 
                    dir = "sendonly";
2350
 
                    break;
2351
 
                case PJMEDIA_DIR_DECODING:
2352
 
                    dir = "recvonly";
2353
 
                    break;
2354
 
                case PJMEDIA_DIR_ENCODING_DECODING:
2355
 
                    dir = "sendrecv";
2356
 
                    break;
2357
 
                default:
2358
 
                    dir = "unknown";
2359
 
                    break;
2360
 
                }
2361
 
                len = pj_ansi_sprintf( info+info_len,
2362
 
                                       ", stream #%d: %.*s (%s)", mi,
2363
 
                                       (int)si->fmt.encoding_name.slen,
2364
 
                                       si->fmt.encoding_name.ptr,
2365
 
                                       dir);
2366
 
                if (len > 0)
2367
 
                    info_len += len;
2368
 
                PJ_LOG(4,(THIS_FILE,"Audio updated%s", info));
2369
 
            }
2370
 
 
2371
 
 
2372
 
            if (call->audio_idx==-1 && status==PJ_SUCCESS &&
2373
 
                si->dir != PJMEDIA_DIR_NONE)
2374
 
            {
2375
 
                call->audio_idx = mi;
2376
 
            }
2377
 
 
2378
 
#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
2379
 
        } else if (call_med->type==PJMEDIA_TYPE_VIDEO) {
2380
 
            pjmedia_vid_stream_info the_si, *si = &the_si;
2381
 
 
2382
 
            status = pjmedia_vid_stream_info_from_sdp(si, tmp_pool, pjsua_var.med_endpt,
2383
 
                                                      local_sdp, remote_sdp, mi);
2384
 
            if (status != PJ_SUCCESS) {
2385
 
                PJ_PERROR(1,(THIS_FILE, status,
2386
 
                             "pjmedia_vid_stream_info_from_sdp() failed "
2387
 
                                 "for call_id %d media %d",
2388
 
                             call_id, mi));
2389
 
                continue;
2390
 
            }
2391
 
 
2392
 
            /* Check if no media is active */
2393
 
            if (si->dir == PJMEDIA_DIR_NONE) {
2394
 
                /* Update call media state and direction */
2395
 
                call_med->state = PJSUA_CALL_MEDIA_NONE;
2396
 
                call_med->dir = PJMEDIA_DIR_NONE;
2397
 
 
2398
 
            } else {
2399
 
                pjmedia_transport_info tp_info;
2400
 
 
2401
 
                /* Start/restart media transport */
2402
 
                status = pjmedia_transport_media_start(call_med->tp,
2403
 
                                                       tmp_pool, local_sdp,
2404
 
                                                       remote_sdp, mi);
2405
 
                if (status != PJ_SUCCESS) {
2406
 
                    PJ_PERROR(1,(THIS_FILE, status,
2407
 
                                 "pjmedia_transport_media_start() failed "
2408
 
                                     "for call_id %d media %d",
2409
 
                                 call_id, mi));
2410
 
                    continue;
2411
 
                }
2412
 
 
2413
 
                pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_RUNNING);
2414
 
 
2415
 
                /* Get remote SRTP usage policy */
2416
 
                pjmedia_transport_info_init(&tp_info);
2417
 
                pjmedia_transport_get_info(call_med->tp, &tp_info);
2418
 
                if (tp_info.specific_info_cnt > 0) {
2419
 
                    unsigned i;
2420
 
                    for (i = 0; i < tp_info.specific_info_cnt; ++i) {
2421
 
                        if (tp_info.spc_info[i].type ==
2422
 
                                PJMEDIA_TRANSPORT_TYPE_SRTP)
2423
 
                        {
2424
 
                            pjmedia_srtp_info *sri;
2425
 
                            sri=(pjmedia_srtp_info*)tp_info.spc_info[i].buffer;
2426
 
                            call_med->rem_srtp_use = sri->peer_use;
2427
 
                            break;
2428
 
                        }
2429
 
                    }
2430
 
                }
2431
 
 
2432
 
                /* Call media direction */
2433
 
                call_med->dir = si->dir;
2434
 
 
2435
 
                /* Call media state */
2436
 
                if (call->local_hold)
2437
 
                    call_med->state = PJSUA_CALL_MEDIA_LOCAL_HOLD;
2438
 
                else if (call_med->dir == PJMEDIA_DIR_DECODING)
2439
 
                    call_med->state = PJSUA_CALL_MEDIA_REMOTE_HOLD;
2440
 
                else
2441
 
                    call_med->state = PJSUA_CALL_MEDIA_ACTIVE;
2442
 
            }
2443
 
 
2444
 
            status = pjsua_vid_channel_update(call_med, tmp_pool, si,
2445
 
                                              local_sdp, remote_sdp);
2446
 
            if (status != PJ_SUCCESS) {
2447
 
                PJ_PERROR(1,(THIS_FILE, status,
2448
 
                             "pjsua_vid_channel_update() failed "
2449
 
                                 "for call_id %d media %d",
2450
 
                             call_id, mi));
2451
 
                continue;
2452
 
            }
2453
 
 
2454
 
            /* Print info. */
2455
 
            {
2456
 
                char info[80];
2457
 
                int info_len = 0;
2458
 
                int len;
2459
 
                const char *dir;
2460
 
 
2461
 
                switch (si->dir) {
2462
 
                case PJMEDIA_DIR_NONE:
2463
 
                    dir = "inactive";
2464
 
                    break;
2465
 
                case PJMEDIA_DIR_ENCODING:
2466
 
                    dir = "sendonly";
2467
 
                    break;
2468
 
                case PJMEDIA_DIR_DECODING:
2469
 
                    dir = "recvonly";
2470
 
                    break;
2471
 
                case PJMEDIA_DIR_ENCODING_DECODING:
2472
 
                    dir = "sendrecv";
2473
 
                    break;
2474
 
                default:
2475
 
                    dir = "unknown";
2476
 
                    break;
2477
 
                }
2478
 
                len = pj_ansi_sprintf( info+info_len,
2479
 
                                       ", stream #%d: %.*s (%s)", mi,
2480
 
                                       (int)si->codec_info.encoding_name.slen,
2481
 
                                       si->codec_info.encoding_name.ptr,
2482
 
                                       dir);
2483
 
                if (len > 0)
2484
 
                    info_len += len;
2485
 
                PJ_LOG(4,(THIS_FILE,"Video updated%s", info));
2486
 
            }
2487
 
 
2488
 
#endif
2489
 
        } else {
2490
 
            status = PJMEDIA_EINVALIMEDIATYPE;
2491
 
        }
2492
 
 
2493
 
        /* Close the transport of deactivated media, need this here as media
2494
 
         * can be deactivated by the SDP negotiation and the max media count
2495
 
         * (account) setting.
2496
 
         */
2497
 
        if (local_sdp->media[mi]->desc.port==0 && call_med->tp) {
2498
 
            pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
2499
 
            pjmedia_transport_close(call_med->tp);
2500
 
            call_med->tp = call_med->tp_orig = NULL;
2501
 
        }
2502
 
 
2503
 
        if (status != PJ_SUCCESS) {
2504
 
            PJ_PERROR(1,(THIS_FILE, status, "Error updating media call%02d:%d",
2505
 
                         call_id, mi));
2506
 
        } else {
2507
 
            got_media = PJ_TRUE;
2508
 
        }
2509
 
    }
2510
 
 
2511
 
    /* Update call media from provisional media */
2512
 
    call->med_cnt = call->med_prov_cnt;
2513
 
    pj_memcpy(call->media, call->media_prov,
2514
 
              sizeof(call->media_prov[0]) * call->med_prov_cnt);
2515
 
 
2516
 
    /* Perform SDP re-negotiation if needed. */
2517
 
    if (got_media && need_renego_sdp) {
2518
 
        pjmedia_sdp_neg *neg = call->inv->neg;
2519
 
 
2520
 
        /* This should only happen when we are the answerer. */
2521
 
        PJ_ASSERT_RETURN(neg && !pjmedia_sdp_neg_was_answer_remote(neg),
2522
 
                         PJMEDIA_SDPNEG_EINSTATE);
2523
 
 
2524
 
        status = pjmedia_sdp_neg_set_remote_offer(tmp_pool, neg, remote_sdp);
2525
 
        if (status != PJ_SUCCESS)
2526
 
            goto on_error;
2527
 
 
2528
 
        status = pjmedia_sdp_neg_set_local_answer(tmp_pool, neg, local_sdp);
2529
 
        if (status != PJ_SUCCESS)
2530
 
            goto on_error;
2531
 
 
2532
 
        status = pjmedia_sdp_neg_negotiate(tmp_pool, neg, 0);
2533
 
        if (status != PJ_SUCCESS)
2534
 
            goto on_error;
2535
 
    }
2536
 
 
2537
 
    pj_log_pop_indent();
2538
 
    return (got_media? PJ_SUCCESS : PJMEDIA_SDPNEG_ENOMEDIA);
2539
 
 
2540
 
on_error:
2541
 
    pj_log_pop_indent();
2542
 
    return status;
2543
 
}
2544
 
 
2545
 
/*****************************************************************************
2546
 
 * Codecs.
2547
 
 */
2548
 
 
2549
 
/*
2550
 
 * Enum all supported codecs in the system.
2551
 
 */
2552
 
PJ_DEF(pj_status_t) pjsua_enum_codecs( pjsua_codec_info id[],
2553
 
                                       unsigned *p_count )
2554
 
{
2555
 
    pjmedia_codec_mgr *codec_mgr;
2556
 
    pjmedia_codec_info info[32];
2557
 
    unsigned i, count, prio[32];
2558
 
    pj_status_t status;
2559
 
 
2560
 
    codec_mgr = pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt);
2561
 
    count = PJ_ARRAY_SIZE(info);
2562
 
    status = pjmedia_codec_mgr_enum_codecs( codec_mgr, &count, info, prio);
2563
 
    if (status != PJ_SUCCESS) {
2564
 
        *p_count = 0;
2565
 
        return status;
2566
 
    }
2567
 
 
2568
 
    if (count > *p_count) count = *p_count;
2569
 
 
2570
 
    for (i=0; i<count; ++i) {
2571
 
        pj_bzero(&id[i], sizeof(pjsua_codec_info));
2572
 
 
2573
 
        pjmedia_codec_info_to_id(&info[i], id[i].buf_, sizeof(id[i].buf_));
2574
 
        id[i].codec_id = pj_str(id[i].buf_);
2575
 
        id[i].priority = (pj_uint8_t) prio[i];
2576
 
    }
2577
 
 
2578
 
    *p_count = count;
2579
 
 
2580
 
    return PJ_SUCCESS;
2581
 
}
2582
 
 
2583
 
 
2584
 
/*
2585
 
 * Change codec priority.
2586
 
 */
2587
 
PJ_DEF(pj_status_t) pjsua_codec_set_priority( const pj_str_t *codec_id,
2588
 
                                              pj_uint8_t priority )
2589
 
{
2590
 
    const pj_str_t all = { NULL, 0 };
2591
 
    pjmedia_codec_mgr *codec_mgr;
2592
 
 
2593
 
    codec_mgr = pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt);
2594
 
 
2595
 
    if (codec_id->slen==1 && *codec_id->ptr=='*')
2596
 
        codec_id = &all;
2597
 
 
2598
 
    return pjmedia_codec_mgr_set_codec_priority(codec_mgr, codec_id,
2599
 
                                                priority);
2600
 
}
2601
 
 
2602
 
 
2603
 
/*
2604
 
 * Get codec parameters.
2605
 
 */
2606
 
PJ_DEF(pj_status_t) pjsua_codec_get_param( const pj_str_t *codec_id,
2607
 
                                           pjmedia_codec_param *param )
2608
 
{
2609
 
    const pj_str_t all = { NULL, 0 };
2610
 
    const pjmedia_codec_info *info;
2611
 
    pjmedia_codec_mgr *codec_mgr;
2612
 
    unsigned count = 1;
2613
 
    pj_status_t status;
2614
 
 
2615
 
    codec_mgr = pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt);
2616
 
 
2617
 
    if (codec_id->slen==1 && *codec_id->ptr=='*')
2618
 
        codec_id = &all;
2619
 
 
2620
 
    status = pjmedia_codec_mgr_find_codecs_by_id(codec_mgr, codec_id,
2621
 
                                                 &count, &info, NULL);
2622
 
    if (status != PJ_SUCCESS)
2623
 
        return status;
2624
 
 
2625
 
    if (count != 1)
2626
 
        return (count > 1? PJ_ETOOMANY : PJ_ENOTFOUND);
2627
 
 
2628
 
    status = pjmedia_codec_mgr_get_default_param( codec_mgr, info, param);
2629
 
    return status;
2630
 
}
2631
 
 
2632
 
 
2633
 
/*
2634
 
 * Set codec parameters.
2635
 
 */
2636
 
PJ_DEF(pj_status_t) pjsua_codec_set_param( const pj_str_t *codec_id,
2637
 
                                           const pjmedia_codec_param *param)
2638
 
{
2639
 
    const pjmedia_codec_info *info[2];
2640
 
    pjmedia_codec_mgr *codec_mgr;
2641
 
    unsigned count = 2;
2642
 
    pj_status_t status;
2643
 
 
2644
 
    codec_mgr = pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt);
2645
 
 
2646
 
    status = pjmedia_codec_mgr_find_codecs_by_id(codec_mgr, codec_id,
2647
 
                                                 &count, info, NULL);
2648
 
    if (status != PJ_SUCCESS)
2649
 
        return status;
2650
 
 
2651
 
    /* Codec ID should be specific, except for G.722.1 */
2652
 
    if (count > 1 &&
2653
 
        pj_strnicmp2(codec_id, "G7221/16", 8) != 0 &&
2654
 
        pj_strnicmp2(codec_id, "G7221/32", 8) != 0)
2655
 
    {
2656
 
        pj_assert(!"Codec ID is not specific");
2657
 
        return PJ_ETOOMANY;
2658
 
    }
2659
 
 
2660
 
    status = pjmedia_codec_mgr_set_default_param(codec_mgr, info[0], param);
2661
 
    return status;
2662
 
}
2663
 
 
2664
 
 
2665
 
pj_status_t pjsua_media_apply_xml_control(pjsua_call_id call_id,
2666
 
                                          const pj_str_t *xml_st)
2667
 
{
2668
 
#if PJMEDIA_HAS_VIDEO
2669
 
    pjsua_call *call = &pjsua_var.calls[call_id];
2670
 
    const pj_str_t PICT_FAST_UPDATE = {"picture_fast_update", 19};
2671
 
 
2672
 
    if (pj_strstr(xml_st, &PICT_FAST_UPDATE)) {
2673
 
        unsigned i;
2674
 
 
2675
 
        PJ_LOG(4,(THIS_FILE, "Received keyframe request via SIP INFO"));
2676
 
 
2677
 
        for (i = 0; i < call->med_cnt; ++i) {
2678
 
            pjsua_call_media *cm = &call->media[i];
2679
 
            if (cm->type != PJMEDIA_TYPE_VIDEO || !cm->strm.v.stream)
2680
 
                continue;
2681
 
 
2682
 
            pjmedia_vid_stream_send_keyframe(cm->strm.v.stream);
2683
 
        }
2684
 
 
2685
 
        return PJ_SUCCESS;
2686
 
    }
2687
 
#endif
2688
 
 
2689
 
    /* Just to avoid compiler warning of unused var */
2690
 
    PJ_UNUSED_ARG(call_id);
2691
 
    PJ_UNUSED_ARG(xml_st);
2692
 
 
2693
 
    return PJ_ENOTSUP;
2694
 
}