Asterisk - The Open Source Telephony Project GIT-master-70eff7f
Loading...
Searching...
No Matches
res_pjsip_sdp_rtp.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2013, Digium, Inc.
5 *
6 * Joshua Colp <jcolp@digium.com>
7 * Kevin Harwell <kharwell@digium.com>
8 *
9 * See http://www.asterisk.org for more information about
10 * the Asterisk project. Please do not directly contact
11 * any of the maintainers of this project for assistance;
12 * the project provides a web site, mailing lists and IRC
13 * channels for your use.
14 *
15 * This program is free software, distributed under the terms of
16 * the GNU General Public License Version 2. See the LICENSE file
17 * at the top of the source tree.
18 */
19
20/*! \file
21 *
22 * \author Joshua Colp <jcolp@digium.com>
23 *
24 * \brief SIP SDP media stream handling
25 */
26
27/*** MODULEINFO
28 <depend>pjproject</depend>
29 <depend>res_pjsip</depend>
30 <depend>res_pjsip_session</depend>
31 <support_level>core</support_level>
32 ***/
33
34#include "asterisk.h"
35
36#include <pjsip.h>
37#include <pjsip_ua.h>
38#include <pjmedia.h>
39#include <pjlib.h>
40
41#include "asterisk/utils.h"
42#include "asterisk/module.h"
43#include "asterisk/format.h"
44#include "asterisk/format_cap.h"
45#include "asterisk/rtp_engine.h"
46#include "asterisk/netsock2.h"
47#include "asterisk/channel.h"
48#include "asterisk/causes.h"
49#include "asterisk/sched.h"
50#include "asterisk/acl.h"
51#include "asterisk/sdp_srtp.h"
52#include "asterisk/dsp.h"
53#include "asterisk/linkedlists.h" /* for AST_LIST_NEXT */
54#include "asterisk/stream.h"
57
58#include "asterisk/res_pjsip.h"
61
62/*! \brief Scheduler for RTCP purposes */
63static struct ast_sched_context *sched;
64
65/*! \brief Address for RTP */
67
68static const char STR_AUDIO[] = "audio";
69static const char STR_VIDEO[] = "video";
70
71static int send_keepalive(const void *data)
72{
73 struct ast_sip_session_media *session_media = (struct ast_sip_session_media *) data;
74 struct ast_rtp_instance *rtp = session_media->rtp;
75 int keepalive;
76 time_t interval;
78
79 if (!rtp) {
80 return 0;
81 }
82
84
85 if (!ast_sockaddr_isnull(&session_media->direct_media_addr)) {
86 ast_debug_rtp(3, "(%p) RTP not sending keepalive since direct media is in use\n", rtp);
87 return keepalive * 1000;
88 }
89
90 interval = time(NULL) - ast_rtp_instance_get_last_tx(rtp);
91 send_keepalive = interval >= keepalive;
92
93 ast_debug_rtp(3, "(%p) RTP it has been %d seconds since RTP was last sent. %sending keepalive\n",
94 rtp, (int) interval, send_keepalive ? "S" : "Not s");
95
96 if (send_keepalive) {
98 return keepalive * 1000;
99 }
100
101 return (keepalive - interval) * 1000;
102}
103
104/*! \brief Check whether RTP is being received or not */
105static int rtp_check_timeout(const void *data)
106{
107 struct ast_sip_session_media *session_media = (struct ast_sip_session_media *)data;
108 struct ast_rtp_instance *rtp = session_media->rtp;
109 struct ast_channel *chan;
110 int elapsed;
111 int now;
112 int timeout;
113
114 if (!rtp) {
115 return 0;
116 }
117
119 if (!chan) {
120 return 0;
121 }
122
123 /* Store these values locally to avoid multiple function calls */
124 now = time(NULL);
125 timeout = ast_rtp_instance_get_timeout(rtp);
126
127 /* If the channel is not in UP state or call is redirected
128 * outside Asterisk return for later check.
129 */
130 if (ast_channel_state(chan) != AST_STATE_UP || !ast_sockaddr_isnull(&session_media->direct_media_addr)) {
131 /* Avoiding immediately disconnect after channel up or direct media has been stopped */
133 ast_channel_unref(chan);
134 /* Recheck after half timeout for avoiding possible races
135 * and faster reacting to cases while there is no an RTP at all.
136 */
137 return timeout * 500;
138 }
139
140 elapsed = now - ast_rtp_instance_get_last_rx(rtp);
141 if (elapsed < timeout) {
142 ast_channel_unref(chan);
143 return (timeout - elapsed) * 1000;
144 }
145
146 ast_log(LOG_NOTICE, "Disconnecting channel '%s' for lack of %s RTP activity in %d seconds\n",
147 ast_channel_name(chan), ast_codec_media_type2str(session_media->type), elapsed);
148
149 ast_channel_lock(chan);
151 ast_channel_unlock(chan);
152
154 ast_channel_unref(chan);
155
156 return 0;
157}
158
159/*!
160 * \brief Enable RTCP on an RTP session.
161 */
162static void enable_rtcp(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
163 const struct pjmedia_sdp_media *remote_media)
164{
165 enum ast_rtp_instance_rtcp rtcp_type;
166
167 if (session->endpoint->media.rtcp_mux && session_media->remote_rtcp_mux) {
168 rtcp_type = AST_RTP_INSTANCE_RTCP_MUX;
169 } else {
171 }
172
173 ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_RTCP, rtcp_type);
174}
175
176/*!
177 * \brief Enable an RTP extension on an RTP session.
178 */
179static void enable_rtp_extension(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
181 const pjmedia_sdp_session *sdp)
182{
183 int id = -1;
184
185 /* For a bundle group the local unique identifier space is shared across all streams within
186 * it.
187 */
188 if (session_media->bundle_group != -1) {
189 int index;
190
191 for (index = 0; index < sdp->media_count; ++index) {
192 struct ast_sip_session_media *other_session_media;
193 int other_id;
194
195 if (index >= AST_VECTOR_SIZE(&session->pending_media_state->sessions)) {
196 break;
197 }
198
199 other_session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, index);
200 if (!other_session_media->rtp || other_session_media->bundle_group != session_media->bundle_group) {
201 continue;
202 }
203
204 other_id = ast_rtp_instance_extmap_get_id(other_session_media->rtp, extension);
205 if (other_id == -1) {
206 /* Worst case we have to fall back to the highest available free local unique identifier
207 * for the bundle group.
208 */
209 other_id = ast_rtp_instance_extmap_count(other_session_media->rtp) + 1;
210 if (id < other_id) {
211 id = other_id;
212 }
213 continue;
214 }
215
216 id = other_id;
217 break;
218 }
219 }
220
222}
223
224/*! \brief Internal function which creates an RTP instance */
225static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
226 const pjmedia_sdp_session *sdp)
227{
228 struct ast_rtp_engine_ice *ice;
229 struct ast_sockaddr temp_media_address;
230 struct ast_sockaddr *media_address = &address_rtp;
231
232 if (session->endpoint->media.bind_rtp_to_media_address && !ast_strlen_zero(session->endpoint->media.address)) {
233 if (ast_sockaddr_parse(&temp_media_address, session->endpoint->media.address, 0)) {
234 ast_debug_rtp(1, "Endpoint %s: Binding RTP media to %s\n",
236 session->endpoint->media.address);
237 media_address = &temp_media_address;
238 } else {
239 ast_debug_rtp(1, "Endpoint %s: RTP media address invalid: %s\n",
241 session->endpoint->media.address);
242 }
243 } else {
244 struct ast_sip_transport *transport;
245
246 transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport",
247 session->endpoint->transport);
248 if (transport) {
249 struct ast_sip_transport_state *trans_state;
250
252 if (trans_state) {
253 char hoststr[PJ_INET6_ADDRSTRLEN];
254
255 pj_sockaddr_print(&trans_state->host, hoststr, sizeof(hoststr), 0);
256 if (ast_sockaddr_parse(&temp_media_address, hoststr, 0)) {
257 ast_debug_rtp(1, "Transport %s bound to %s: Using it for RTP media.\n",
258 session->endpoint->transport, hoststr);
259 media_address = &temp_media_address;
260 } else {
261 ast_debug_rtp(1, "Transport %s bound to %s: Invalid for RTP media.\n",
262 session->endpoint->transport, hoststr);
263 }
264 ao2_ref(trans_state, -1);
265 }
266 ao2_ref(transport, -1);
267 }
268 }
269
270 if (session->endpoint->media.rtp.port_start && session->endpoint->media.rtp.port_end) {
272 .port_start = session->endpoint->media.rtp.port_start,
273 .port_end = session->endpoint->media.rtp.port_end,
274 };
275 if (!(session_media->rtp = ast_rtp_instance_new_with_options(
276 session->endpoint->media.rtp.engine, sched, media_address, NULL,
277 &options))) {
278 ast_log(LOG_ERROR, "Unable to create RTP instance using RTP engine '%s' with port range %u-%u\n",
279 session->endpoint->media.rtp.engine,
280 session->endpoint->media.rtp.port_start,
281 session->endpoint->media.rtp.port_end);
282 return -1;
283 }
284 } else {
285 if (!(session_media->rtp = ast_rtp_instance_new(session->endpoint->media.rtp.engine, sched, media_address, NULL))) {
286 ast_log(LOG_ERROR, "Unable to create RTP instance using RTP engine '%s'\n", session->endpoint->media.rtp.engine);
287 return -1;
288 }
289 }
290
291 ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_NAT, session->endpoint->media.rtp.symmetric);
292 ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_ASYMMETRIC_CODEC, session->endpoint->asymmetric_rtp_codec);
293
294 if (!session->endpoint->media.rtp.ice_support && (ice = ast_rtp_instance_get_ice(session_media->rtp))) {
295 ice->stop(session_media->rtp);
296 }
297
301 } else if (session->dtmf == AST_SIP_DTMF_INBAND) {
303 }
304
305 if (session_media->type == AST_MEDIA_TYPE_AUDIO &&
306 (session->endpoint->media.tos_audio || session->endpoint->media.cos_audio)) {
307 ast_rtp_instance_set_qos(session_media->rtp, session->endpoint->media.tos_audio,
308 session->endpoint->media.cos_audio, "SIP RTP Audio");
309 } else if (session_media->type == AST_MEDIA_TYPE_VIDEO) {
310 ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_RETRANS_RECV, session->endpoint->media.webrtc);
311 ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_RETRANS_SEND, session->endpoint->media.webrtc);
312 ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_REMB, session->endpoint->media.webrtc);
313 if (session->endpoint->media.webrtc) {
316 }
317 if (session->endpoint->media.tos_video || session->endpoint->media.cos_video) {
318 ast_rtp_instance_set_qos(session_media->rtp, session->endpoint->media.tos_video,
319 session->endpoint->media.cos_video, "SIP RTP Video");
320 }
321 }
322
323 ast_rtp_instance_set_last_rx(session_media->rtp, time(NULL));
324
325 return 0;
326}
327
328static void get_codecs(struct ast_sip_session *session, const struct pjmedia_sdp_media *stream, struct ast_rtp_codecs *codecs,
329 struct ast_sip_session_media *session_media, struct ast_format_cap *astformats)
330{
331 pjmedia_sdp_attr *attr;
332 pjmedia_sdp_rtpmap *rtpmap;
333 pjmedia_sdp_fmtp fmtp;
334 struct ast_format *format;
335 int i, num = 0, tel_event = 0;
336 char name[256];
337 char media[20];
338 char fmt_param[256];
339 enum ast_rtp_options options = session->endpoint->media.g726_non_standard ?
342
344
346
347 /* Iterate through provided formats */
348 for (i = 0; i < stream->desc.fmt_count; ++i) {
349 /* The payload is kept as a string for things like t38 but for video it is always numerical */
350 ast_rtp_codecs_payloads_set_m_type(codecs, NULL, pj_strtoul(&stream->desc.fmt[i]));
351 /* Look for the optional rtpmap attribute */
352 if (!(attr = pjmedia_sdp_media_find_attr2(stream, "rtpmap", &stream->desc.fmt[i]))) {
353 continue;
354 }
355
356 /* Interpret the attribute as an rtpmap */
357 if ((pjmedia_sdp_attr_to_rtpmap(session->inv_session->pool_prov, attr, &rtpmap)) != PJ_SUCCESS) {
358 continue;
359 }
360
361 ast_copy_pj_str(name, &rtpmap->enc_name, sizeof(name));
362 if (strcmp(name, "telephone-event") == 0) {
363 if (tel_event == 0) {
364 int dtmf_rate = 0, dtmf_code = 0;
365 char dtmf_pt[8];
366 ast_copy_pj_str(dtmf_pt, &rtpmap->pt, sizeof(dtmf_pt));
367 dtmf_code = atoi(dtmf_pt);
368 dtmf_rate = rtpmap->clock_rate;
370 }
371 tel_event++;
372 }
373
374 ast_copy_pj_str(media, (pj_str_t*)&stream->desc.media, sizeof(media));
376 pj_strtoul(&stream->desc.fmt[i]), media, name, options, rtpmap->clock_rate);
377 /* Look for an optional associated fmtp attribute */
378 if (!(attr = pjmedia_sdp_media_find_attr2(stream, "fmtp", &rtpmap->pt))) {
379 continue;
380 }
381
382 if ((pjmedia_sdp_attr_get_fmtp(attr, &fmtp)) == PJ_SUCCESS) {
383 ast_copy_pj_str(fmt_param, &fmtp.fmt, sizeof(fmt_param));
384 if (sscanf(fmt_param, "%30d", &num) != 1) {
385 continue;
386 }
387
388 if ((format = ast_rtp_codecs_get_payload_format(codecs, num))) {
389 struct ast_format *format_parsed;
390
391 ast_copy_pj_str(fmt_param, &fmtp.fmt_param, sizeof(fmt_param));
392
393 format_parsed = ast_format_parse_sdp_fmtp(format, fmt_param);
394 if (format_parsed) {
396 ao2_ref(format_parsed, -1);
397 }
398 ao2_ref(format, -1);
399 }
400 }
401 }
402
403 /* Parsing done, now fill the ast_format_cap struct in the correct order */
404 for (i = 0; i < stream->desc.fmt_count; ++i) {
405 if ((format = ast_rtp_codecs_get_payload_format(codecs, pj_strtoul(&stream->desc.fmt[i])))) {
406 ast_format_cap_append(astformats, format, 0);
407 ao2_ref(format, -1);
408 }
409 }
410
411 if (session->dtmf == AST_SIP_DTMF_AUTO) {
412 if (tel_event) {
415 } else {
418 }
419 }
420
421 if (session->dtmf == AST_SIP_DTMF_AUTO_INFO) {
422 if (tel_event) {
425 } else {
428 }
429 }
430
431
432 /* Get the packetization, if it exists */
433 if ((attr = pjmedia_sdp_media_find_attr2(stream, "ptime", NULL))) {
434 unsigned long framing = pj_strtoul(pj_strltrim(&attr->value));
435 if (framing && session->endpoint->media.rtp.use_ptime) {
437 ast_format_cap_set_framing(astformats, framing);
438 }
439 }
440
442}
443
444static int apply_cap_to_bundled(struct ast_sip_session_media *session_media,
445 struct ast_sip_session_media *session_media_transport,
446 struct ast_stream *asterisk_stream, struct ast_format_cap *joint)
447{
448 if (!joint) {
449 return -1;
450 }
451
452 ast_stream_set_formats(asterisk_stream, joint);
453
454 /* If this is a bundled stream then apply the payloads to RTP instance acting as transport to prevent conflicts */
455 if (session_media_transport != session_media && session_media->bundled) {
456 int index;
457
458 for (index = 0; index < ast_format_cap_count(joint); ++index) {
459 struct ast_format *format = ast_format_cap_get_format(joint, index);
460 int rtp_code;
461
462 /* Ensure this payload is in the bundle group transport codecs, this purposely doesn't check the return value for
463 * things as the format is guaranteed to have a payload already.
464 */
465 rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(session_media->rtp), 1, format, 0);
466 ast_rtp_codecs_payload_set_rx(ast_rtp_instance_get_codecs(session_media_transport->rtp), rtp_code, format);
467
468 ao2_ref(format, -1);
469 }
470 }
471
472 return 0;
473}
474
476 struct ast_sip_session *session, struct ast_sip_session_media *session_media,
477 const struct pjmedia_sdp_media *stream)
478{
479 struct ast_format_cap *incoming_call_offer_cap;
480 struct ast_format_cap *remote;
483
484
486 if (!remote) {
487 ast_log(LOG_ERROR, "Failed to allocate %s incoming remote capabilities\n",
488 ast_codec_media_type2str(session_media->type));
489 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't allocate caps\n");
490 }
491
492 /* Get the peer's capabilities*/
493 get_codecs(session, stream, &codecs, session_media, remote);
494
495 incoming_call_offer_cap = ast_sip_session_create_joint_call_cap(
496 session, session_media->type, remote);
497
498 ao2_ref(remote, -1);
499
500 if (!incoming_call_offer_cap || ast_format_cap_empty(incoming_call_offer_cap)) {
501 ao2_cleanup(incoming_call_offer_cap);
503 SCOPE_EXIT_RTN_VALUE(NULL, "No incoming call offer caps\n");
504 }
505
506 /*
507 * Setup rx payload type mapping to prefer the mapping
508 * from the peer that the RFC says we SHOULD use.
509 */
511
512 /*
513 * This only merges the newly offered payloads into the live RTP instance
514 * rather than doing a destructive replace, so any format the channel is
515 * still actively sending in (e.g. while a reINVITE is in flight) remains
516 * usable right up until set_caps() commits the channel to the new
517 * negotiated format. A destructive replace here, before the channel's
518 * own read/write format has caught up, is what let a concurrent bridge
519 * write briefly land on a payload mapping that no longer had its format.
520 */
522 ast_rtp_instance_get_codecs(session_media->rtp), session_media->rtp);
523
525
526 SCOPE_EXIT_RTN_VALUE(incoming_call_offer_cap);
527}
528
530 struct ast_sip_session_media *session_media,
531 struct ast_sip_session_media *session_media_transport,
532 const struct pjmedia_sdp_media *stream,
533 int is_offer, struct ast_stream *asterisk_stream)
534{
535 RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
536 RAII_VAR(struct ast_format_cap *, peer, NULL, ao2_cleanup);
537 RAII_VAR(struct ast_format_cap *, joint, NULL, ao2_cleanup);
538 enum ast_media_type media_type = session_media->type;
540 int direct_media_enabled = !ast_sockaddr_isnull(&session_media->direct_media_addr) &&
541 ast_format_cap_count(session->direct_media_cap);
542 int dsp_features = 0;
543 SCOPE_ENTER(1, "%s %s\n", ast_sip_session_get_name(session), is_offer ? "OFFER" : "ANSWER");
544
548 ast_log(LOG_ERROR, "Failed to allocate %s capabilities\n",
549 ast_codec_media_type2str(session_media->type));
550 SCOPE_EXIT_RTN_VALUE(-1, "Couldn't create %s capabilities\n",
551 ast_codec_media_type2str(session_media->type));
552 }
553
554 /* get the endpoint capabilities */
555 if (direct_media_enabled) {
556 ast_format_cap_get_compatible(session->endpoint->media.codecs, session->direct_media_cap, caps);
557 } else {
558 ast_format_cap_append_from_cap(caps, session->endpoint->media.codecs, media_type);
559 }
560
561 /* get the capabilities on the peer */
562 get_codecs(session, stream, &codecs, session_media, peer);
563
564 /* get the joint capabilities between peer and endpoint */
565 ast_format_cap_get_compatible(caps, peer, joint);
566 if (!ast_format_cap_count(joint)) {
569
571 ast_log(LOG_NOTICE, "No joint capabilities for '%s' media stream between our configuration(%s) and incoming SDP(%s)\n",
572 ast_codec_media_type2str(session_media->type),
573 ast_format_cap_get_names(caps, &usbuf),
574 ast_format_cap_get_names(peer, &thembuf));
575 SCOPE_EXIT_RTN_VALUE(-1, "No joint capabilities for '%s' media stream between our configuration(%s) and incoming SDP(%s)\n",
576 ast_codec_media_type2str(session_media->type),
577 ast_format_cap_get_names(caps, &usbuf),
578 ast_format_cap_get_names(peer, &thembuf));
579 } else {
580 struct ast_format *preferred_fmt = ast_format_cap_get_format(joint, 0);
581
583 ao2_ref(preferred_fmt, -1);
584 }
585
586 if (is_offer) {
587 /*
588 * Setup rx payload type mapping to prefer the mapping
589 * from the peer that the RFC says we SHOULD use.
590 */
592 }
593
594 if (session->channel) {
595 ast_channel_lock(session->channel);
596 }
597
599 session_media->rtp);
600
601 apply_cap_to_bundled(session_media, session_media_transport, asterisk_stream, joint);
602
603 if (session->channel && ast_sip_session_is_pending_stream_default(session, asterisk_stream)) {
607 ast_format_cap_remove_by_type(caps, media_type);
608
609 if (session->endpoint->preferred_codec_only) {
610 struct ast_format *preferred_fmt = ast_format_cap_get_format(joint, 0);
611 ast_format_cap_append(caps, preferred_fmt, 0);
612 ao2_ref(preferred_fmt, -1);
613 } else if (!session->endpoint->asymmetric_rtp_codec) {
614 struct ast_format *best;
615 /*
616 * If we don't allow the sending codec to be changed on our side
617 * then get the best codec from the joint capabilities of the media
618 * type and use only that. This ensures the core won't start sending
619 * out a format that we aren't currently sending.
620 */
621
622 best = ast_format_cap_get_best_by_type(joint, media_type);
623 if (best) {
625 ao2_ref(best, -1);
626 }
627 } else {
628 ast_format_cap_append_from_cap(caps, joint, media_type);
629 }
630
631 /*
632 * Apply the new formats to the channel, potentially changing
633 * raw read/write formats and translation path while doing so.
634 */
636 if (media_type == AST_MEDIA_TYPE_AUDIO) {
639 }
640
641 if ( ((session->dtmf == AST_SIP_DTMF_AUTO) || (session->dtmf == AST_SIP_DTMF_AUTO_INFO) )
643 && (session->dsp)) {
644 dsp_features = ast_dsp_get_features(session->dsp);
645 dsp_features &= ~DSP_FEATURE_DIGIT_DETECT;
646 if (dsp_features) {
647 ast_dsp_set_features(session->dsp, dsp_features);
648 } else {
649 ast_dsp_free(session->dsp);
650 session->dsp = NULL;
651 }
652 }
653
654 if (ast_channel_is_bridged(session->channel)) {
656 }
657 }
658
659 if (session->channel) {
660 ast_channel_unlock(session->channel);
661 }
662
665}
666
667static pjmedia_sdp_attr* generate_rtpmap_attr(struct ast_sip_session *session, pjmedia_sdp_media *media, pj_pool_t *pool,
668 int rtp_code, int asterisk_format, struct ast_format *format, int code)
669{
670#ifndef HAVE_PJSIP_ENDPOINT_COMPACT_FORM
671 extern pj_bool_t pjsip_use_compact_form;
672#else
673 pj_bool_t pjsip_use_compact_form = pjsip_cfg()->endpt.use_compact_form;
674#endif
675 pjmedia_sdp_rtpmap rtpmap;
676 pjmedia_sdp_attr *attr = NULL;
677 char tmp[64];
678 enum ast_rtp_options options = session->endpoint->media.g726_non_standard ?
680
681 snprintf(tmp, sizeof(tmp), "%d", rtp_code);
682 pj_strdup2(pool, &media->desc.fmt[media->desc.fmt_count++], tmp);
683
684 if (rtp_code <= AST_RTP_PT_LAST_STATIC && pjsip_use_compact_form) {
685 return NULL;
686 }
687
688 rtpmap.pt = media->desc.fmt[media->desc.fmt_count - 1];
689 rtpmap.clock_rate = ast_rtp_lookup_sample_rate2(asterisk_format, format, code);
690 pj_strdup2(pool, &rtpmap.enc_name, ast_rtp_lookup_mime_subtype2(asterisk_format, format, code, options));
691 if (!pj_stricmp2(&rtpmap.enc_name, "opus")) {
692 pj_cstr(&rtpmap.param, "2");
693 } else {
694 pj_cstr(&rtpmap.param, NULL);
695 }
696
697 pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);
698
699 return attr;
700}
701
702
703static pjmedia_sdp_attr* generate_rtpmap_attr2(struct ast_sip_session *session, pjmedia_sdp_media *media, pj_pool_t *pool,
704 int rtp_code, int asterisk_format, struct ast_format *format, int code, int sample_rate)
705{
706#ifndef HAVE_PJSIP_ENDPOINT_COMPACT_FORM
707 extern pj_bool_t pjsip_use_compact_form;
708#else
709 pj_bool_t pjsip_use_compact_form = pjsip_cfg()->endpt.use_compact_form;
710#endif
711 pjmedia_sdp_rtpmap rtpmap;
712 pjmedia_sdp_attr *attr = NULL;
713 char tmp[64];
714 enum ast_rtp_options options = session->endpoint->media.g726_non_standard ?
716
717 snprintf(tmp, sizeof(tmp), "%d", rtp_code);
718 pj_strdup2(pool, &media->desc.fmt[media->desc.fmt_count++], tmp);
719
720 if (rtp_code <= AST_RTP_PT_LAST_STATIC && pjsip_use_compact_form) {
721 return NULL;
722 }
723
724 rtpmap.pt = media->desc.fmt[media->desc.fmt_count - 1];
725 rtpmap.clock_rate = sample_rate;
726 pj_strdup2(pool, &rtpmap.enc_name, ast_rtp_lookup_mime_subtype2(asterisk_format, format, code, options));
727 if (!pj_stricmp2(&rtpmap.enc_name, "opus")) {
728 pj_cstr(&rtpmap.param, "2");
729 } else {
730 pj_cstr(&rtpmap.param, NULL);
731 }
732
733 pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);
734
735 return attr;
736}
737
738static pjmedia_sdp_attr* generate_fmtp_attr(pj_pool_t *pool, struct ast_format *format, int rtp_code)
739{
740 struct ast_str *fmtp0 = ast_str_alloca(256);
741 pj_str_t fmtp1;
742 pjmedia_sdp_attr *attr = NULL;
743 char *tmp;
744
745 ast_format_generate_sdp_fmtp(format, rtp_code, &fmtp0);
746 if (ast_str_strlen(fmtp0)) {
747 tmp = ast_str_buffer(fmtp0) + ast_str_strlen(fmtp0) - 1;
748 /* remove any carriage return line feeds */
749 while (*tmp == '\r' || *tmp == '\n') --tmp;
750 *++tmp = '\0';
751 /* ast...generate gives us everything, just need value */
752 tmp = strchr(ast_str_buffer(fmtp0), ':');
753 if (tmp && tmp[1] != '\0') {
754 fmtp1 = pj_str(tmp + 1);
755 } else {
756 fmtp1 = pj_str(ast_str_buffer(fmtp0));
757 }
758 attr = pjmedia_sdp_attr_create(pool, "fmtp", &fmtp1);
759 }
760 return attr;
761}
762
763/*! \brief Function which adds ICE attributes to a media stream */
764static void add_ice_to_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media,
765 unsigned int include_candidates)
766{
767 struct ast_rtp_engine_ice *ice;
768 struct ao2_container *candidates;
769 const char *username, *password;
770 pj_str_t stmp;
771 pjmedia_sdp_attr *attr;
772 struct ao2_iterator it_candidates;
773 struct ast_rtp_engine_ice_candidate *candidate;
774
775 if (!session->endpoint->media.rtp.ice_support || !(ice = ast_rtp_instance_get_ice(session_media->rtp))) {
776 return;
777 }
778
779 if (!session_media->remote_ice) {
780 ice->stop(session_media->rtp);
781 return;
782 }
783
784 if ((username = ice->get_ufrag(session_media->rtp))) {
785 attr = pjmedia_sdp_attr_create(pool, "ice-ufrag", pj_cstr(&stmp, username));
786 media->attr[media->attr_count++] = attr;
787 }
788
789 if ((password = ice->get_password(session_media->rtp))) {
790 attr = pjmedia_sdp_attr_create(pool, "ice-pwd", pj_cstr(&stmp, password));
791 media->attr[media->attr_count++] = attr;
792 }
793
794 if (!include_candidates) {
795 return;
796 }
797
798 candidates = ice->get_local_candidates(session_media->rtp);
799 if (!candidates) {
800 return;
801 }
802
803 it_candidates = ao2_iterator_init(candidates, 0);
804 for (; (candidate = ao2_iterator_next(&it_candidates)); ao2_ref(candidate, -1)) {
805 struct ast_str *attr_candidate = ast_str_create(128);
806
807 ast_str_set(&attr_candidate, -1, "%s %u %s %d %s ", candidate->foundation, candidate->id, candidate->transport,
808 candidate->priority, ast_sockaddr_stringify_addr_remote(&candidate->address));
809 ast_str_append(&attr_candidate, -1, "%s typ ", ast_sockaddr_stringify_port(&candidate->address));
810
811 switch (candidate->type) {
813 ast_str_append(&attr_candidate, -1, "host");
814 break;
816 ast_str_append(&attr_candidate, -1, "srflx");
817 break;
819 ast_str_append(&attr_candidate, -1, "relay");
820 break;
821 }
822
823 if (!ast_sockaddr_isnull(&candidate->relay_address)) {
824 ast_str_append(&attr_candidate, -1, " raddr %s rport", ast_sockaddr_stringify_addr_remote(&candidate->relay_address));
825 ast_str_append(&attr_candidate, -1, " %s", ast_sockaddr_stringify_port(&candidate->relay_address));
826 }
827
828 attr = pjmedia_sdp_attr_create(pool, "candidate", pj_cstr(&stmp, ast_str_buffer(attr_candidate)));
829 media->attr[media->attr_count++] = attr;
830
831 ast_free(attr_candidate);
832 }
833
834 ao2_iterator_destroy(&it_candidates);
835 ao2_ref(candidates, -1);
836}
837
838/*! \brief Function which checks for ice attributes in an audio stream */
839static void check_ice_support(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
840 const struct pjmedia_sdp_media *remote_stream)
841{
842 struct ast_rtp_engine_ice *ice;
843 const pjmedia_sdp_attr *attr;
844 unsigned int attr_i;
845
846 if (!session->endpoint->media.rtp.ice_support || !(ice = ast_rtp_instance_get_ice(session_media->rtp))) {
847 session_media->remote_ice = 0;
848 return;
849 }
850
851 /* Find all of the candidates */
852 for (attr_i = 0; attr_i < remote_stream->attr_count; ++attr_i) {
853 attr = remote_stream->attr[attr_i];
854 if (!pj_strcmp2(&attr->name, "candidate")) {
855 session_media->remote_ice = 1;
856 break;
857 }
858 }
859
860 if (attr_i == remote_stream->attr_count) {
861 session_media->remote_ice = 0;
862 }
863}
864
866 const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream)
867{
868 struct ast_rtp_engine_ice *ice;
870 char ufrag_attr_value[256];
871 char passwd_attr_value[256];
872
873 /* If ICE support is not enabled or available exit early */
874 if (!session->endpoint->media.rtp.ice_support || !(ice = ast_rtp_instance_get_ice(session_media->rtp))) {
875 return;
876 }
877
879 if (!ufrag_attr) {
880 ufrag_attr = pjmedia_sdp_attr_find2(remote->attr_count, remote->attr, "ice-ufrag", NULL);
881 }
882 if (ufrag_attr) {
884 } else {
885 return;
886 }
888 if (!passwd_attr) {
889 passwd_attr = pjmedia_sdp_attr_find2(remote->attr_count, remote->attr, "ice-pwd", NULL);
890 }
891 if (passwd_attr) {
893 } else {
894 return;
895 }
896
897 if (ufrag_attr && passwd_attr) {
899 }
900}
901
902/*! \brief Function which processes ICE attributes in an audio stream */
904 const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream)
905{
906 struct ast_rtp_engine_ice *ice;
907 const pjmedia_sdp_attr *attr;
908 char attr_value[256];
909 unsigned int attr_i;
910
911 /* If ICE support is not enabled or available exit early */
912 if (!session->endpoint->media.rtp.ice_support || !(ice = ast_rtp_instance_get_ice(session_media->rtp))) {
913 return;
914 }
915
916 ast_debug_ice(2, "(%p) ICE process attributes\n", session_media->rtp);
917
918 attr = pjmedia_sdp_media_find_attr2(remote_stream, "ice-ufrag", NULL);
919 if (!attr) {
920 attr = pjmedia_sdp_attr_find2(remote->attr_count, remote->attr, "ice-ufrag", NULL);
921 }
922 if (attr) {
923 ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value));
925 } else {
926 ast_debug_ice(2, "(%p) ICE no, or invalid ice-ufrag\n", session_media->rtp);
927 return;
928 }
929
931 if (!attr) {
932 attr = pjmedia_sdp_attr_find2(remote->attr_count, remote->attr, "ice-pwd", NULL);
933 }
934 if (attr) {
935 ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value));
937 } else {
938 ast_debug_ice(2, "(%p) ICE no, or invalid ice-pwd\n", session_media->rtp);
939 return;
940 }
941
943 ice->ice_lite(session_media->rtp);
944 }
945
946 /* Find all of the candidates */
947 for (attr_i = 0; attr_i < remote_stream->attr_count; ++attr_i) {
948 char foundation[33], transport[32], address[PJ_INET6_ADDRSTRLEN + 1], cand_type[6], relay_address[PJ_INET6_ADDRSTRLEN + 1] = "";
949 unsigned int port, relay_port = 0;
950 struct ast_rtp_engine_ice_candidate candidate = { 0, };
951
952 attr = remote_stream->attr[attr_i];
953
954 /* If this is not a candidate line skip it */
955 if (pj_strcmp2(&attr->name, "candidate")) {
956 continue;
957 }
958
959 ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value));
960
961 if (sscanf(attr_value, "%32s %30u %31s %30u %46s %30u typ %5s %*s %23s %*s %30u", foundation, &candidate.id, transport,
962 (unsigned *)&candidate.priority, address, &port, cand_type, relay_address, &relay_port) < 7) {
963 /* Candidate did not parse properly */
964 continue;
965 }
966
967 if (session->endpoint->media.rtcp_mux && session_media->remote_rtcp_mux && candidate.id > 1) {
968 /* Remote side may have offered RTP and RTCP candidates. However, if we're using RTCP MUX,
969 * then we should ignore RTCP candidates.
970 */
971 continue;
972 }
973
974 candidate.foundation = foundation;
975 candidate.transport = transport;
976
978 ast_sockaddr_set_port(&candidate.address, port);
979
980 if (!strcasecmp(cand_type, "host")) {
982 } else if (!strcasecmp(cand_type, "srflx")) {
984 } else if (!strcasecmp(cand_type, "relay")) {
986 } else {
987 continue;
988 }
989
992 }
993
994 if (relay_port) {
995 ast_sockaddr_set_port(&candidate.relay_address, relay_port);
996 }
997
998 ice->add_remote_candidate(session_media->rtp, &candidate);
999 }
1000
1001 ice->set_role(session_media->rtp, pjmedia_sdp_neg_was_answer_remote(session->inv_session->neg) == PJ_TRUE ?
1003 ice->start(session_media->rtp);
1004}
1005
1006/*! \brief figure out if media stream has crypto lines for sdes */
1007static int media_stream_has_crypto(const struct pjmedia_sdp_media *stream)
1008{
1009 int i;
1010
1011 for (i = 0; i < stream->attr_count; i++) {
1012 pjmedia_sdp_attr *attr;
1013
1014 /* check the stream for the required crypto attribute */
1015 attr = stream->attr[i];
1016 if (pj_strcmp2(&attr->name, "crypto")) {
1017 continue;
1018 }
1019
1020 return 1;
1021 }
1022
1023 return 0;
1024}
1025
1026/*! \brief figure out media transport encryption type from the media transport string */
1028 const struct pjmedia_sdp_media *stream, unsigned int *optimistic)
1029{
1030 RAII_VAR(char *, transport_str, ast_strndup(transport.ptr, transport.slen), ast_free);
1031
1032 *optimistic = 0;
1033
1034 if (!transport_str) {
1036 }
1037 if (strstr(transport_str, "UDP/TLS")) {
1039 } else if (strstr(transport_str, "SAVP")) {
1041 } else if (media_stream_has_crypto(stream)) {
1042 *optimistic = 1;
1044 } else {
1046 }
1047}
1048
1049/*!
1050 * \brief Checks whether the encryption offered in SDP is compatible with the endpoint's configuration
1051 * \internal
1052 *
1053 * \param endpoint Media encryption configured for the endpoint
1054 * \param stream pjmedia_sdp_media stream description
1055 *
1056 * \retval AST_SIP_MEDIA_TRANSPORT_INVALID on encryption mismatch
1057 * \retval The encryption requested in the SDP
1058 */
1060 struct ast_sip_endpoint *endpoint,
1061 const struct pjmedia_sdp_media *stream)
1062{
1063 enum ast_sip_session_media_encryption incoming_encryption;
1064 char transport_end = stream->desc.transport.ptr[stream->desc.transport.slen - 1];
1065 unsigned int optimistic;
1066
1067 if ((transport_end == 'F' && !endpoint->media.rtp.use_avpf)
1068 || (transport_end != 'F' && endpoint->media.rtp.use_avpf)) {
1070 }
1071
1072 incoming_encryption = get_media_encryption_type(stream->desc.transport, stream, &optimistic);
1073
1074 if (incoming_encryption == endpoint->media.rtp.encryption) {
1075 return incoming_encryption;
1076 }
1077
1078 if (endpoint->media.rtp.force_avp ||
1079 endpoint->media.rtp.encryption_optimistic) {
1080 return incoming_encryption;
1081 }
1082
1083 /* If an optimistic offer has been made but encryption is not enabled consider it as having
1084 * no offer of crypto at all instead of invalid so the session proceeds.
1085 */
1086 if (optimistic) {
1088 }
1089
1091}
1092
1093static int setup_srtp(struct ast_sip_session_media *session_media)
1094{
1095 if (!session_media->srtp) {
1096 session_media->srtp = ast_sdp_srtp_alloc();
1097 if (!session_media->srtp) {
1098 return -1;
1099 }
1100 }
1101
1102 if (!session_media->srtp->crypto) {
1103 session_media->srtp->crypto = ast_sdp_crypto_alloc();
1104 if (!session_media->srtp->crypto) {
1105 return -1;
1106 }
1107 }
1108
1109 return 0;
1110}
1111
1113 struct ast_sip_session_media *session_media)
1114{
1115 struct ast_rtp_engine_dtls *dtls;
1116
1117 if (!session->endpoint->media.rtp.dtls_cfg.enabled || !session_media->rtp) {
1118 return -1;
1119 }
1120
1121 dtls = ast_rtp_instance_get_dtls(session_media->rtp);
1122 if (!dtls) {
1123 return -1;
1124 }
1125
1126 session->endpoint->media.rtp.dtls_cfg.suite = ((session->endpoint->media.rtp.srtp_tag_32) ? AST_AES_CM_128_HMAC_SHA1_32 : AST_AES_CM_128_HMAC_SHA1_80);
1127 if (dtls->set_configuration(session_media->rtp, &session->endpoint->media.rtp.dtls_cfg)) {
1128 ast_log(LOG_ERROR, "Attempted to set an invalid DTLS-SRTP configuration on RTP instance '%p'\n",
1129 session_media->rtp);
1130 return -1;
1131 }
1132
1133 if (setup_srtp(session_media)) {
1134 return -1;
1135 }
1136 return 0;
1137}
1138
1139static void apply_dtls_attrib(struct ast_sip_session_media *session_media,
1140 pjmedia_sdp_attr *attr)
1141{
1142 struct ast_rtp_engine_dtls *dtls = ast_rtp_instance_get_dtls(session_media->rtp);
1143 pj_str_t *value;
1144
1145 if (!attr->value.ptr || !dtls) {
1146 return;
1147 }
1148
1149 value = pj_strtrim(&attr->value);
1150
1151 if (!pj_strcmp2(&attr->name, "setup")) {
1152 if (!pj_stricmp2(value, "active")) {
1153 dtls->set_setup(session_media->rtp, AST_RTP_DTLS_SETUP_ACTIVE);
1154 } else if (!pj_stricmp2(value, "passive")) {
1155 dtls->set_setup(session_media->rtp, AST_RTP_DTLS_SETUP_PASSIVE);
1156 } else if (!pj_stricmp2(value, "actpass")) {
1157 dtls->set_setup(session_media->rtp, AST_RTP_DTLS_SETUP_ACTPASS);
1158 } else if (!pj_stricmp2(value, "holdconn")) {
1159 dtls->set_setup(session_media->rtp, AST_RTP_DTLS_SETUP_HOLDCONN);
1160 } else {
1161 ast_log(LOG_WARNING, "Unsupported setup attribute value '%*s'\n", (int)value->slen, value->ptr);
1162 }
1163 } else if (!pj_strcmp2(&attr->name, "connection")) {
1164 if (!pj_stricmp2(value, "new")) {
1165 dtls->reset(session_media->rtp);
1166 } else if (!pj_stricmp2(value, "existing")) {
1167 /* Do nothing */
1168 } else {
1169 ast_log(LOG_WARNING, "Unsupported connection attribute value '%*s'\n", (int)value->slen, value->ptr);
1170 }
1171 } else if (!pj_strcmp2(&attr->name, "fingerprint")) {
1172 char hash_value[256], hash[32];
1173 char fingerprint_text[value->slen + 1];
1174 ast_copy_pj_str(fingerprint_text, value, sizeof(fingerprint_text));
1175 if (sscanf(fingerprint_text, "%31s %255s", hash, hash_value) == 2) {
1176 if (!strcasecmp(hash, "sha-1")) {
1177 dtls->set_fingerprint(session_media->rtp, AST_RTP_DTLS_HASH_SHA1, hash_value);
1178 } else if (!strcasecmp(hash, "sha-256")) {
1179 dtls->set_fingerprint(session_media->rtp, AST_RTP_DTLS_HASH_SHA256, hash_value);
1180 } else {
1181 ast_log(LOG_WARNING, "Unsupported fingerprint hash type '%s'\n",
1182 hash);
1183 }
1184 }
1185 }
1186}
1187
1188static int parse_dtls_attrib(struct ast_sip_session_media *session_media,
1189 const struct pjmedia_sdp_session *sdp,
1190 const struct pjmedia_sdp_media *stream)
1191{
1192 int i;
1193
1194 for (i = 0; i < sdp->attr_count; i++) {
1195 apply_dtls_attrib(session_media, sdp->attr[i]);
1196 }
1197
1198 for (i = 0; i < stream->attr_count; i++) {
1199 apply_dtls_attrib(session_media, stream->attr[i]);
1200 }
1201
1203
1204 return 0;
1205}
1206
1207static int setup_sdes_srtp(struct ast_sip_session_media *session_media,
1208 const struct pjmedia_sdp_media *stream)
1209{
1210 int i;
1211
1212 for (i = 0; i < stream->attr_count; i++) {
1213 pjmedia_sdp_attr *attr;
1214 RAII_VAR(char *, crypto_str, NULL, ast_free);
1215
1216 /* check the stream for the required crypto attribute */
1217 attr = stream->attr[i];
1218 if (pj_strcmp2(&attr->name, "crypto")) {
1219 continue;
1220 }
1221
1222 crypto_str = ast_strndup(attr->value.ptr, attr->value.slen);
1223 if (!crypto_str) {
1224 return -1;
1225 }
1226
1227 if (setup_srtp(session_media)) {
1228 return -1;
1229 }
1230
1231 if (!ast_sdp_crypto_process(session_media->rtp, session_media->srtp, crypto_str)) {
1232 /* found a valid crypto attribute */
1233 return 0;
1234 }
1235
1236 ast_debug(1, "Ignoring crypto offer with unsupported parameters: %s\n", crypto_str);
1237 }
1238
1239 /* no usable crypto attributes found */
1240 return -1;
1241}
1242
1244 struct ast_sip_session_media *session_media,
1245 const struct pjmedia_sdp_session *sdp,
1246 const struct pjmedia_sdp_media *stream)
1247{
1248 switch (session_media->encryption) {
1250 if (setup_sdes_srtp(session_media, stream)) {
1251 return -1;
1252 }
1253 break;
1255 if (setup_dtls_srtp(session, session_media)) {
1256 return -1;
1257 }
1258 if (parse_dtls_attrib(session_media, sdp, stream)) {
1259 return -1;
1260 }
1261 break;
1264 break;
1265 }
1266
1267 return 0;
1268}
1269
1270static void set_ice_components(struct ast_sip_session *session, struct ast_sip_session_media *session_media)
1271{
1272 struct ast_rtp_engine_ice *ice;
1273
1274 ast_assert(session_media->rtp != NULL);
1275
1277 if (!session->endpoint->media.rtp.ice_support || !ice) {
1278 return;
1279 }
1280
1281 if (session->endpoint->media.rtcp_mux && session_media->remote_rtcp_mux) {
1282 /* We both support RTCP mux. Only one ICE component necessary */
1283 ice->change_components(session_media->rtp, 1);
1284 } else {
1285 /* They either don't support RTCP mux or we don't know if they do yet. */
1286 ice->change_components(session_media->rtp, 2);
1287 }
1288}
1289
1290/*! \brief Function which adds ssrc attributes to a media stream */
1292{
1293 pj_str_t stmp;
1294 pjmedia_sdp_attr *attr;
1295 char tmp[128];
1296
1297 if (!session->endpoint->media.bundle || session_media->bundle_group == -1) {
1298 return;
1299 }
1300
1302 attr = pjmedia_sdp_attr_create(pool, "ssrc", pj_cstr(&stmp, tmp));
1303 media->attr[media->attr_count++] = attr;
1304}
1305
1306/*! \brief Function which processes ssrc attributes in a stream */
1308 const struct pjmedia_sdp_media *remote_stream)
1309{
1310 int index;
1311
1312 if (!session->endpoint->media.bundle) {
1313 return;
1314 }
1315
1316 for (index = 0; index < remote_stream->attr_count; ++index) {
1317 pjmedia_sdp_attr *attr = remote_stream->attr[index];
1318 char attr_value[pj_strlen(&attr->value) + 1];
1320 unsigned int ssrc;
1321
1322 /* We only care about ssrc attributes */
1323 if (pj_strcmp2(&attr->name, "ssrc")) {
1324 continue;
1325 }
1326
1327 ast_copy_pj_str(attr_value, &attr->value, sizeof(attr_value));
1328
1329 if ((ssrc_attribute_name = strchr(attr_value, ' '))) {
1330 /* This has an actual attribute */
1331 *ssrc_attribute_name++ = '\0';
1334 /* Values are actually optional according to the spec */
1335 *ssrc_attribute_value++ = '\0';
1336 }
1337 }
1338
1339 if (sscanf(attr_value, "%30u", &ssrc) < 1) {
1340 continue;
1341 }
1342
1343 /* If we are currently negotiating as a result of the remote side renegotiating then
1344 * determine if the source for this stream has changed.
1345 */
1347 session->active_media_state) {
1348 struct ast_rtp_instance_stats stats = { 0, };
1349
1351 stats.remote_ssrc != ssrc) {
1352 session_media->changed = 1;
1353 }
1354 }
1355
1356 ast_rtp_instance_set_remote_ssrc(session_media->rtp, ssrc);
1357 break;
1358 }
1359}
1360
1362 struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media,
1363 struct ast_stream *stream)
1364{
1365 pj_str_t stmp;
1366 pjmedia_sdp_attr *attr;
1367 char msid[(AST_UUID_STR_LEN * 2) + 2];
1368 const char *stream_label = ast_stream_get_metadata(stream, "SDP:LABEL");
1369
1370 if (!session->endpoint->media.webrtc) {
1371 return;
1372 }
1373
1374 if (ast_strlen_zero(session_media->mslabel)) {
1375 /* If this stream is grouped with another then use its media stream label if possible */
1376 if (ast_stream_get_group(stream) != -1) {
1377 struct ast_sip_session_media *group_session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, ast_stream_get_group(stream));
1378
1379 ast_copy_string(session_media->mslabel, group_session_media->mslabel, sizeof(session_media->mslabel));
1380 }
1381
1382 if (ast_strlen_zero(session_media->mslabel)) {
1383 ast_uuid_generate_str(session_media->mslabel, sizeof(session_media->mslabel));
1384 }
1385 }
1386
1387 if (ast_strlen_zero(session_media->label)) {
1388 ast_uuid_generate_str(session_media->label, sizeof(session_media->label));
1389 /* add for stream identification to replace stream_name */
1390 ast_stream_set_metadata(stream, "MSID:LABEL", session_media->label);
1391 }
1392
1393 snprintf(msid, sizeof(msid), "%s %s", session_media->mslabel, session_media->label);
1394 ast_debug(3, "Stream msid: %p %s %s\n", stream,
1396 attr = pjmedia_sdp_attr_create(pool, "msid", pj_cstr(&stmp, msid));
1397 pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr);
1398
1399 /* 'label' must come after 'msid' */
1400 if (!ast_strlen_zero(stream_label)) {
1401 ast_debug(3, "Stream Label: %p %s %s\n", stream,
1402 ast_codec_media_type2str(ast_stream_get_type(stream)), stream_label);
1403 attr = pjmedia_sdp_attr_create(pool, "label", pj_cstr(&stmp, stream_label));
1404 pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr);
1405 }
1406}
1407
1409 struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media)
1410{
1411 pj_str_t stmp;
1412 pjmedia_sdp_attr *attr;
1413
1414 if (!session->endpoint->media.webrtc) {
1415 return;
1416 }
1417
1418 /* transport-cc is supposed to be for the entire transport, and any media sources so
1419 * while the header does not appear in audio streams and isn't negotiated there, we still
1420 * place this attribute in as Chrome does.
1421 */
1422 attr = pjmedia_sdp_attr_create(pool, "rtcp-fb", pj_cstr(&stmp, "* transport-cc"));
1423 pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr);
1424
1425 if (session_media->type != AST_MEDIA_TYPE_VIDEO) {
1426 return;
1427 }
1428
1429 /*
1430 * For now just automatically add it the stream even though it hasn't
1431 * necessarily been negotiated.
1432 */
1433 attr = pjmedia_sdp_attr_create(pool, "rtcp-fb", pj_cstr(&stmp, "* ccm fir"));
1434 pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr);
1435
1436 attr = pjmedia_sdp_attr_create(pool, "rtcp-fb", pj_cstr(&stmp, "* goog-remb"));
1437 pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr);
1438
1439 attr = pjmedia_sdp_attr_create(pool, "rtcp-fb", pj_cstr(&stmp, "* nack"));
1440 pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr);
1441}
1442
1444 struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media)
1445{
1446 int idx;
1447 char extmap_value[256];
1448
1449 if (!session->endpoint->media.webrtc || session_media->type != AST_MEDIA_TYPE_VIDEO) {
1450 return;
1451 }
1452
1453 /* RTP extension local unique identifiers start at '1' */
1454 for (idx = 1; idx <= ast_rtp_instance_extmap_count(session_media->rtp); ++idx) {
1456 const char *direction_str = "";
1457 pj_str_t stmp;
1458 pjmedia_sdp_attr *attr;
1459
1460 /* If this is an unsupported RTP extension we can't place it into the SDP */
1462 continue;
1463 }
1464
1465 switch (ast_rtp_instance_extmap_get_direction(session_media->rtp, idx)) {
1467 /* Lack of a direction indicates sendrecv, so we leave it out */
1468 direction_str = "";
1469 break;
1471 direction_str = "/sendonly";
1472 break;
1474 direction_str = "/recvonly";
1475 break;
1477 /* It is impossible for a "none" direction extension to be negotiated but just in case
1478 * we treat it as inactive.
1479 */
1481 direction_str = "/inactive";
1482 break;
1483 }
1484
1485 snprintf(extmap_value, sizeof(extmap_value), "%d%s %s", idx, direction_str,
1486 ast_rtp_instance_extmap_get_uri(session_media->rtp, idx));
1487 attr = pjmedia_sdp_attr_create(pool, "extmap", pj_cstr(&stmp, extmap_value));
1488 pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr);
1489 }
1490}
1491
1492/*! \brief Function which processes extmap attributes in a stream */
1494 const struct pjmedia_sdp_media *remote_stream)
1495{
1496 int index;
1497
1498 if (!session->endpoint->media.webrtc || session_media->type != AST_MEDIA_TYPE_VIDEO) {
1499 return;
1500 }
1501
1502 ast_rtp_instance_extmap_clear(session_media->rtp);
1503
1504 for (index = 0; index < remote_stream->attr_count; ++index) {
1505 pjmedia_sdp_attr *attr = remote_stream->attr[index];
1506 char attr_value[pj_strlen(&attr->value) + 1];
1507 char *uri;
1508 int id;
1509 char direction_str[10] = "";
1510 char *attributes;
1512
1513 /* We only care about extmap attributes */
1514 if (pj_strcmp2(&attr->name, "extmap")) {
1515 continue;
1516 }
1517
1518 ast_copy_pj_str(attr_value, &attr->value, sizeof(attr_value));
1519
1520 /* Split the combined unique identifier and direction away from the URI and attributes for easier parsing */
1521 uri = strchr(attr_value, ' ');
1522 if (ast_strlen_zero(uri)) {
1523 continue;
1524 }
1525 *uri++ = '\0';
1526
1527 if ((sscanf(attr_value, "%30d%9s", &id, direction_str) < 1) || (id < 1)) {
1528 /* We require at a minimum the unique identifier */
1529 continue;
1530 }
1531
1532 /* Convert from the string to the internal representation */
1533 if (!strcasecmp(direction_str, "/sendonly")) {
1535 } else if (!strcasecmp(direction_str, "/recvonly")) {
1537 } else if (!strcasecmp(direction_str, "/inactive")) {
1539 }
1540
1541 attributes = strchr(uri, ' ');
1542 if (!ast_strlen_zero(attributes)) {
1543 *attributes++ = '\0';
1544 }
1545
1546 ast_rtp_instance_extmap_negotiate(session_media->rtp, id, direction, uri, attributes);
1547 }
1548}
1549
1551 const struct ast_sip_session *session,
1552 const pjmedia_sdp_media *media,
1553 const struct ast_stream *stream,
1554 const struct ast_sockaddr *addrs)
1555{
1557 (session_media->type == AST_MEDIA_TYPE_AUDIO)) {
1558 if (((addrs != NULL) && ast_sockaddr_isnull(addrs)) ||
1559 ((addrs != NULL) && ast_sockaddr_is_any(addrs)) ||
1560 pjmedia_sdp_media_find_attr2(media, "sendonly", NULL) ||
1561 pjmedia_sdp_media_find_attr2(media, "inactive", NULL)) {
1562 if (!session_media->remotely_held) {
1563 session_media->remotely_held = 1;
1564 session_media->remotely_held_changed = 1;
1565 }
1566 } else if (session_media->remotely_held) {
1567 session_media->remotely_held = 0;
1568 session_media->remotely_held_changed = 1;
1569 }
1570 }
1571}
1572
1573/*! \brief Function which negotiates an incoming media stream */
1575 struct ast_sip_session_media *session_media, const pjmedia_sdp_session *sdp,
1576 int index, struct ast_stream *asterisk_stream)
1577{
1578 char host[NI_MAXHOST];
1579 RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free);
1580 pjmedia_sdp_media *stream = sdp->media[index];
1581 struct ast_sip_session_media *session_media_transport;
1582 enum ast_media_type media_type = session_media->type;
1584 struct ast_format_cap *joint;
1585 int res;
1587
1588 /* If no type formats have been configured reject this stream */
1589 if (!ast_format_cap_has_type(session->endpoint->media.codecs, media_type)) {
1590 ast_debug(3, "Endpoint has no codecs for media type '%s', declining stream\n",
1591 ast_codec_media_type2str(session_media->type));
1592 SCOPE_EXIT_RTN_VALUE(0, "Endpoint has no codecs\n");
1593 }
1594
1595 /* Ensure incoming transport is compatible with the endpoint's configuration */
1596 if (!session->endpoint->media.rtp.use_received_transport) {
1597 encryption = check_endpoint_media_transport(session->endpoint, stream);
1598
1599 if (encryption == AST_SIP_MEDIA_TRANSPORT_INVALID) {
1600 SCOPE_EXIT_RTN_VALUE(-1, "Incompatible transport\n");
1601 }
1602 }
1603
1604 ast_copy_pj_str(host, stream->conn ? &stream->conn->addr : &sdp->conn->addr, sizeof(host));
1605
1606 /* Ensure that the address provided is valid */
1607 if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) {
1608 /* The provided host was actually invalid so we error out this negotiation */
1609 SCOPE_EXIT_RTN_VALUE(-1, "Invalid host\n");
1610 }
1611
1612 /* Using the connection information create an appropriate RTP instance */
1613 if (!session_media->rtp && create_rtp(session, session_media, sdp)) {
1614 SCOPE_EXIT_RTN_VALUE(-1, "Couldn't create rtp\n");
1615 }
1616
1617 process_ssrc_attributes(session, session_media, stream);
1618 process_extmap_attributes(session, session_media, stream);
1619 session_media_transport = ast_sip_session_media_get_transport(session, session_media);
1620
1621 if (session_media_transport == session_media || !session_media->bundled) {
1622 /* If this media session is carrying actual traffic then set up those aspects */
1623 session_media->remote_rtcp_mux = (pjmedia_sdp_media_find_attr2(stream, "rtcp-mux", NULL) != NULL);
1624 set_ice_components(session, session_media);
1625
1626 enable_rtcp(session, session_media, stream);
1627
1628 res = setup_media_encryption(session, session_media, sdp, stream);
1629 if (res) {
1630 if (!session->endpoint->media.rtp.encryption_optimistic ||
1631 !pj_strncmp2(&stream->desc.transport, "RTP/SAVP", 8)) {
1632 /* If optimistic encryption is disabled and crypto should have been enabled
1633 * but was not this session must fail. This must also fail if crypto was
1634 * required in the offer but could not be set up.
1635 */
1636 SCOPE_EXIT_RTN_VALUE(-1, "Incompatible crypto\n");
1637 }
1638 /* There is no encryption, sad. */
1639 session_media->encryption = AST_SIP_MEDIA_ENCRYPT_NONE;
1640 }
1641
1642 /* If we've been explicitly configured to use the received transport OR if
1643 * encryption is on and crypto is present use the received transport.
1644 * This is done in case of optimistic because it may come in as RTP/AVP or RTP/SAVP depending
1645 * on the configuration of the remote endpoint (optimistic themselves or mandatory).
1646 */
1647 if ((session->endpoint->media.rtp.use_received_transport) ||
1648 ((encryption == AST_SIP_MEDIA_ENCRYPT_SDES) && !res)) {
1649 pj_strdup(session->inv_session->pool, &session_media->transport, &stream->desc.transport);
1650 }
1651 } else {
1652 /* This is bundled with another session, so mark it as such */
1653 ast_rtp_instance_bundle(session_media->rtp, session_media_transport->rtp);
1654
1655 enable_rtcp(session, session_media, stream);
1656 }
1657
1658 /* If ICE support is enabled find all the needed attributes */
1659 check_ice_support(session, session_media, stream);
1660
1661 /* If ICE support is enabled then check remote ICE started? */
1662 if (session_media->remote_ice) {
1663 process_ice_auth_attrb(session, session_media, sdp, stream);
1664 }
1665
1666 /* Check if incoming SDP is changing the remotely held state */
1667 set_session_media_remotely_held(session_media, session, stream, asterisk_stream, addrs);
1668
1669 joint = set_incoming_call_offer_cap(session, session_media, stream);
1670 res = apply_cap_to_bundled(session_media, session_media_transport, asterisk_stream, joint);
1671 ao2_cleanup(joint);
1672 if (res != 0) {
1673 SCOPE_EXIT_RTN_VALUE(0, "Something failed\n");
1674 }
1675
1677}
1678
1680 struct ast_sip_session_media *session_media,
1681 pj_pool_t *pool, pjmedia_sdp_media *media)
1682{
1683 pj_str_t stmp;
1684 pjmedia_sdp_attr *attr;
1685 enum ast_rtp_dtls_hash hash;
1686 const char *crypto_attribute;
1687 struct ast_rtp_engine_dtls *dtls;
1688 struct ast_sdp_srtp *tmp;
1689 static const pj_str_t STR_NEW = { "new", 3 };
1690 static const pj_str_t STR_EXISTING = { "existing", 8 };
1691 static const pj_str_t STR_ACTIVE = { "active", 6 };
1692 static const pj_str_t STR_PASSIVE = { "passive", 7 };
1693 static const pj_str_t STR_ACTPASS = { "actpass", 7 };
1694 static const pj_str_t STR_HOLDCONN = { "holdconn", 8 };
1695 static const pj_str_t STR_MEDSECREQ = { "requested", 9 };
1696 enum ast_rtp_dtls_setup setup;
1697
1698 switch (session_media->encryption) {
1701 break;
1703 if (!session_media->srtp) {
1704 session_media->srtp = ast_sdp_srtp_alloc();
1705 if (!session_media->srtp) {
1706 return -1;
1707 }
1708 }
1709
1710 tmp = session_media->srtp;
1711
1712 do {
1713 crypto_attribute = ast_sdp_srtp_get_attrib(tmp,
1714 0 /* DTLS running? No */,
1715 session->endpoint->media.rtp.srtp_tag_32 /* 32 byte tag length? */);
1716 if (!crypto_attribute) {
1717 /* No crypto attribute to add, bad news */
1718 return -1;
1719 }
1720
1721 attr = pjmedia_sdp_attr_create(pool, "crypto",
1722 pj_cstr(&stmp, crypto_attribute));
1723 media->attr[media->attr_count++] = attr;
1724 } while ((tmp = AST_LIST_NEXT(tmp, sdp_srtp_list)));
1725
1726 if (session->endpoint->security_negotiation == AST_SIP_SECURITY_NEG_MEDIASEC) {
1727 attr = pjmedia_sdp_attr_create(pool, "3ge2ae", &STR_MEDSECREQ);
1728 media->attr[media->attr_count++] = attr;
1729 }
1730
1731 break;
1733 if (setup_dtls_srtp(session, session_media)) {
1734 return -1;
1735 }
1736
1737 dtls = ast_rtp_instance_get_dtls(session_media->rtp);
1738 if (!dtls) {
1739 return -1;
1740 }
1741
1742 switch (dtls->get_connection(session_media->rtp)) {
1744 attr = pjmedia_sdp_attr_create(pool, "connection", &STR_NEW);
1745 media->attr[media->attr_count++] = attr;
1746 break;
1748 attr = pjmedia_sdp_attr_create(pool, "connection", &STR_EXISTING);
1749 media->attr[media->attr_count++] = attr;
1750 break;
1751 default:
1752 break;
1753 }
1754
1755 /* If this is an answer we need to use our current state, if it's an offer we need to use
1756 * the configured value.
1757 */
1758 if (session->inv_session->neg
1759 && pjmedia_sdp_neg_get_state(session->inv_session->neg) != PJMEDIA_SDP_NEG_STATE_DONE) {
1760 setup = dtls->get_setup(session_media->rtp);
1761 } else {
1762 setup = session->endpoint->media.rtp.dtls_cfg.default_setup;
1763 }
1764
1765 switch (setup) {
1767 attr = pjmedia_sdp_attr_create(pool, "setup", &STR_ACTIVE);
1768 media->attr[media->attr_count++] = attr;
1769 break;
1771 attr = pjmedia_sdp_attr_create(pool, "setup", &STR_PASSIVE);
1772 media->attr[media->attr_count++] = attr;
1773 break;
1775 attr = pjmedia_sdp_attr_create(pool, "setup", &STR_ACTPASS);
1776 media->attr[media->attr_count++] = attr;
1777 break;
1779 attr = pjmedia_sdp_attr_create(pool, "setup", &STR_HOLDCONN);
1780 break;
1781 default:
1782 break;
1783 }
1784
1785 hash = dtls->get_fingerprint_hash(session_media->rtp);
1786 crypto_attribute = dtls->get_fingerprint(session_media->rtp);
1787 if (crypto_attribute && (hash == AST_RTP_DTLS_HASH_SHA1 || hash == AST_RTP_DTLS_HASH_SHA256)) {
1788 RAII_VAR(struct ast_str *, fingerprint, ast_str_create(64), ast_free);
1789 if (!fingerprint) {
1790 return -1;
1791 }
1792
1793 if (hash == AST_RTP_DTLS_HASH_SHA1) {
1794 ast_str_set(&fingerprint, 0, "SHA-1 %s", crypto_attribute);
1795 } else {
1796 ast_str_set(&fingerprint, 0, "SHA-256 %s", crypto_attribute);
1797 }
1798
1799 attr = pjmedia_sdp_attr_create(pool, "fingerprint", pj_cstr(&stmp, ast_str_buffer(fingerprint)));
1800 media->attr[media->attr_count++] = attr;
1801 }
1802 break;
1803 }
1804
1805 return 0;
1806}
1807
1808/*! \brief Function which creates an outgoing stream */
1810 struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_session *remote, struct ast_stream *stream)
1811{
1812 pj_pool_t *pool = session->inv_session->pool_prov;
1813 static const pj_str_t STR_RTP_AVP = { "RTP/AVP", 7 };
1814 static const pj_str_t STR_IN = { "IN", 2 };
1815 static const pj_str_t STR_IP4 = { "IP4", 3};
1816 static const pj_str_t STR_IP6 = { "IP6", 3};
1817 static const pj_str_t STR_SENDRECV = { "sendrecv", 8 };
1818 static const pj_str_t STR_SENDONLY = { "sendonly", 8 };
1819 static const pj_str_t STR_INACTIVE = { "inactive", 8 };
1820 static const pj_str_t STR_RECVONLY = { "recvonly", 8 };
1821 pjmedia_sdp_media *media;
1822 const char *hostip = NULL;
1823 struct ast_sockaddr addr;
1824 char tmp[512];
1825 pj_str_t stmp;
1826 pjmedia_sdp_attr *attr;
1827 int index = 0;
1828 int noncodec = (session->dtmf == AST_SIP_DTMF_RFC_4733 || session->dtmf == AST_SIP_DTMF_AUTO || session->dtmf == AST_SIP_DTMF_AUTO_INFO) ? AST_RTP_DTMF : 0;
1829 int min_packet_size = 0, max_packet_size = 0;
1830 int rtp_code;
1831 RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
1832 enum ast_media_type media_type = session_media->type;
1833 struct ast_sip_session_media *session_media_transport;
1834 pj_sockaddr ip;
1835 int direct_media_enabled = !ast_sockaddr_isnull(&session_media->direct_media_addr) &&
1836 ast_format_cap_count(session->direct_media_cap);
1837
1838 /* Keep track of the sample rates for offered codecs so we can build matching
1839 RFC 2833/4733 payload offers. */
1840 AST_VECTOR(, int) sample_rates;
1841 /* In case we can't init the sample rates, still try to do the rest. */
1842 int build_dtmf_sample_rates = 1;
1843
1844 SCOPE_ENTER(1, "%s Type: %s %s\n", ast_sip_session_get_name(session),
1845 ast_codec_media_type2str(media_type), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
1846
1847 media = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_media));
1848 if (!media) {
1849 SCOPE_EXIT_RTN_VALUE(-1, "Pool alloc failure\n");
1850 }
1851 pj_strdup2(pool, &media->desc.media, ast_codec_media_type2str(session_media->type));
1852
1853 /* If this is a removed (or declined) stream OR if no formats exist then construct a minimal stream in SDP */
1856 media->desc.port = 0;
1857 media->desc.port_count = 1;
1858
1859 if (remote && remote->media[ast_stream_get_position(stream)]) {
1860 pjmedia_sdp_media *remote_media = remote->media[ast_stream_get_position(stream)];
1861 int index;
1862
1863 media->desc.transport = remote_media->desc.transport;
1864
1865 /* Preserve existing behavior by copying the formats provided from the offer */
1866 for (index = 0; index < remote_media->desc.fmt_count; ++index) {
1867 media->desc.fmt[index] = remote_media->desc.fmt[index];
1868 }
1869 media->desc.fmt_count = remote_media->desc.fmt_count;
1870 } else {
1871 /* This is actually an offer so put a dummy payload in that is ignored and sane transport */
1872 media->desc.transport = STR_RTP_AVP;
1873 pj_strdup2(pool, &media->desc.fmt[media->desc.fmt_count++], "32");
1874 }
1875
1876 sdp->media[sdp->media_count++] = media;
1878
1879 SCOPE_EXIT_RTN_VALUE(1, "Stream removed or no formats\n");
1880 }
1881
1882 if (!session_media->rtp && create_rtp(session, session_media, sdp)) {
1883 SCOPE_EXIT_RTN_VALUE(-1, "Couldn't create rtp\n");
1884 }
1885
1886 /* If this stream has not been bundled already it is new and we need to ensure there is no SSRC conflict */
1887 if (session_media->bundle_group != -1 && !session_media->bundled) {
1888 for (index = 0; index < sdp->media_count; ++index) {
1889 struct ast_sip_session_media *other_session_media;
1890
1891 other_session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, index);
1892 if (!other_session_media->rtp || other_session_media->bundle_group != session_media->bundle_group) {
1893 continue;
1894 }
1895
1896 if (ast_rtp_instance_get_ssrc(session_media->rtp) == ast_rtp_instance_get_ssrc(other_session_media->rtp)) {
1897 ast_rtp_instance_change_source(session_media->rtp);
1898 /* Start the conflict check over again */
1899 index = -1;
1900 continue;
1901 }
1902 }
1903 }
1904
1905 session_media_transport = ast_sip_session_media_get_transport(session, session_media);
1906
1907 if (session_media_transport == session_media || !session_media->bundled) {
1908 set_ice_components(session, session_media);
1909 enable_rtcp(session, session_media, NULL);
1910
1911 /* Crypto has to be added before setting the media transport so that SRTP is properly
1912 * set up according to the configuration. This ends up changing the media transport.
1913 */
1914 if (add_crypto_to_stream(session, session_media, pool, media)) {
1915 SCOPE_EXIT_RTN_VALUE(-1, "Couldn't add crypto\n");
1916 }
1917
1918 if (pj_strlen(&session_media->transport)) {
1919 /* If a transport has already been specified use it */
1920 media->desc.transport = session_media->transport;
1921 } else {
1922 media->desc.transport = pj_str(ast_sdp_get_rtp_profile(
1923 /* Optimistic encryption places crypto in the normal RTP/AVP profile */
1924 !session->endpoint->media.rtp.encryption_optimistic &&
1925 (session_media->encryption == AST_SIP_MEDIA_ENCRYPT_SDES),
1926 session_media->rtp, session->endpoint->media.rtp.use_avpf,
1927 session->endpoint->media.rtp.force_avp));
1928 }
1929
1930 media->conn = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_conn));
1931 if (!media->conn) {
1932 SCOPE_EXIT_RTN_VALUE(-1, "Pool alloc failure\n");
1933 }
1934
1935 /* Add connection level details */
1936 if (direct_media_enabled) {
1938 } else if (ast_strlen_zero(session->endpoint->media.address)) {
1939 hostip = ast_sip_get_host_ip_string(session->endpoint->media.rtp.ipv6 ? pj_AF_INET6() : pj_AF_INET());
1940 } else {
1941 hostip = session->endpoint->media.address;
1942 }
1943
1944 if (ast_strlen_zero(hostip)) {
1945 ast_log(LOG_ERROR, "No local host IP available for stream %s\n",
1946 ast_codec_media_type2str(session_media->type));
1947 SCOPE_EXIT_RTN_VALUE(-1, "No local host ip\n");
1948 }
1949
1950 media->conn->net_type = STR_IN;
1951 /* Assume that the connection will use IPv4 until proven otherwise */
1952 media->conn->addr_type = STR_IP4;
1953 pj_strdup2(pool, &media->conn->addr, hostip);
1954
1955 if ((pj_sockaddr_parse(pj_AF_UNSPEC(), 0, &media->conn->addr, &ip) == PJ_SUCCESS) &&
1956 (ip.addr.sa_family == pj_AF_INET6())) {
1957 media->conn->addr_type = STR_IP6;
1958 }
1959
1960 /* Add ICE attributes and candidates */
1961 add_ice_to_stream(session, session_media, pool, media, 1);
1962
1963 ast_rtp_instance_get_local_address(session_media->rtp, &addr);
1964 media->desc.port = direct_media_enabled ? ast_sockaddr_port(&session_media->direct_media_addr) : (pj_uint16_t) ast_sockaddr_port(&addr);
1965 media->desc.port_count = 1;
1966 } else {
1967 pjmedia_sdp_media *bundle_group_stream = sdp->media[session_media_transport->stream_num];
1968
1969 /* As this is in a bundle group it shares the same details as the group instance */
1970 media->desc.transport = bundle_group_stream->desc.transport;
1971 media->conn = bundle_group_stream->conn;
1972 media->desc.port = bundle_group_stream->desc.port;
1973
1974 if (add_crypto_to_stream(session, session_media_transport, pool, media)) {
1975 SCOPE_EXIT_RTN_VALUE(-1, "Couldn't add crypto\n");
1976 }
1977
1978 add_ice_to_stream(session, session_media_transport, pool, media, 0);
1979
1980 enable_rtcp(session, session_media, NULL);
1981 }
1982
1984 ast_log(LOG_ERROR, "Failed to allocate %s capabilities\n",
1985 ast_codec_media_type2str(session_media->type));
1986 SCOPE_EXIT_RTN_VALUE(-1, "Couldn't create caps\n");
1987 }
1988
1989 if (direct_media_enabled) {
1990 ast_format_cap_get_compatible(session->endpoint->media.codecs, session->direct_media_cap, caps);
1991 } else {
1992 ast_format_cap_append_from_cap(caps, ast_stream_get_formats(stream), media_type);
1993 }
1994
1995 /* Init the sample rates before we start adding them. Assume we will have at least one. */
1996 if (AST_VECTOR_INIT(&sample_rates, 1)) {
1997 ast_log(LOG_ERROR, "Unable to add dtmf formats to SDP!\n");
1998 build_dtmf_sample_rates = 0;
1999 }
2000
2001 for (index = 0; index < ast_format_cap_count(caps); ++index) {
2002 struct ast_format *format = ast_format_cap_get_format(caps, index);
2003
2004 if (ast_format_get_type(format) != media_type) {
2005 ao2_ref(format, -1);
2006 continue;
2007 }
2008
2009 /* It is possible for some formats not to have SDP information available for them
2010 * and if this is the case, skip over them so the SDP can still be created.
2011 */
2012 if (!ast_rtp_lookup_sample_rate2(1, format, 0)) {
2013 ast_log(LOG_WARNING, "Format '%s' can not be added to SDP, consider disallowing it on endpoint '%s'\n",
2015 ao2_ref(format, -1);
2016 continue;
2017 }
2018
2019 /* If this stream is not a transport we need to use the transport codecs structure for payload management to prevent
2020 * conflicts.
2021 */
2022 if (session_media_transport != session_media) {
2023 if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(session_media_transport->rtp), 1, format, 0)) == -1) {
2024 ast_log(LOG_WARNING,"Unable to get rtp codec payload code for %s\n", ast_format_get_name(format));
2025 ao2_ref(format, -1);
2026 continue;
2027 }
2028 /* Our instance has to match the payload number though */
2029 ast_rtp_codecs_payload_set_rx(ast_rtp_instance_get_codecs(session_media->rtp), rtp_code, format);
2030 } else {
2031 if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(session_media->rtp), 1, format, 0)) == -1) {
2032 ast_log(LOG_WARNING,"Unable to get rtp codec payload code for %s\n", ast_format_get_name(format));
2033 ao2_ref(format, -1);
2034 continue;
2035 }
2036 }
2037
2038 if ((attr = generate_rtpmap_attr(session, media, pool, rtp_code, 1, format, 0))) {
2039 int i, added = 0;
2040 int newrate = ast_rtp_lookup_sample_rate2(1, format, 0);
2041 if (build_dtmf_sample_rates) {
2042 for (i = 0; i < AST_VECTOR_SIZE(&sample_rates); i++) {
2043 /* Only add if we haven't already processed this sample rate. For instance
2044 A-law and u-law 'share' one 8K DTMF payload type. */
2045 if (newrate == AST_VECTOR_GET(&sample_rates, i)) {
2046 added = 1;
2047 break;
2048 }
2049 }
2050
2051 if (!added) {
2052 AST_VECTOR_APPEND(&sample_rates, newrate);
2053 }
2054 }
2055 media->attr[media->attr_count++] = attr;
2056 }
2057
2058 if ((attr = generate_fmtp_attr(pool, format, rtp_code))) {
2059 media->attr[media->attr_count++] = attr;
2060 }
2061
2062 if (ast_format_get_maximum_ms(format) &&
2063 ((ast_format_get_maximum_ms(format) < max_packet_size) || !max_packet_size)) {
2064 max_packet_size = ast_format_get_maximum_ms(format);
2065 }
2066 ao2_ref(format, -1);
2067
2068 if (media->desc.fmt_count == PJMEDIA_MAX_SDP_FMT) {
2069 break;
2070 }
2071 }
2072
2073 /* Add non-codec formats */
2075 && media->desc.fmt_count < PJMEDIA_MAX_SDP_FMT) {
2076 for (index = 1LL; index <= AST_RTP_MAX; index <<= 1) {
2077 if (!(noncodec & index)) {
2078 continue;
2079 }
2080
2081 if (index != AST_RTP_DTMF) {
2082 rtp_code = ast_rtp_codecs_payload_code(
2083 ast_rtp_instance_get_codecs(session_media->rtp), 0, NULL, index);
2084 if (rtp_code == -1) {
2085 continue;
2086 } else if ((attr = generate_rtpmap_attr(session, media, pool, rtp_code, 0, NULL, index))) {
2087 media->attr[media->attr_count++] = attr;
2088 }
2089 } else if (build_dtmf_sample_rates) {
2090 /*
2091 * Walk through the possible bitrates for the RFC 2833/4733 digits and generate the rtpmap
2092 * attributes.
2093 */
2094 int i, found_default_offer = 0;
2095 for (i = 0; i < AST_VECTOR_SIZE(&sample_rates); i++) {
2097 ast_rtp_instance_get_codecs(session_media->rtp), 0, NULL, index, AST_VECTOR_GET(&sample_rates, i));
2098
2099 if (rtp_code == -1) {
2100 continue;
2101 }
2102
2103 if (AST_VECTOR_GET(&sample_rates, i) == DEFAULT_DTMF_SAMPLE_RATE_MS) {
2104 /* we found and added a default offer, so no need to include a default one.*/
2105 found_default_offer = 1;
2106 }
2107
2108 if ((attr = generate_rtpmap_attr2(session, media, pool, rtp_code, 0, NULL, index, AST_VECTOR_GET(&sample_rates, i)))) {
2109 media->attr[media->attr_count++] = attr;
2110 snprintf(tmp, sizeof(tmp), "%d 0-16", (rtp_code));
2111 attr = pjmedia_sdp_attr_create(pool, "fmtp", pj_cstr(&stmp, tmp));
2112 media->attr[media->attr_count++] = attr;
2113 }
2114 }
2115
2116 /* If we weren't able to add any matching RFC 2833/4733, assume this endpoint is using a
2117 * mismatched 8K offer and try to add one as a fall-back/default.
2118 */
2119 if (!found_default_offer) {
2122
2123 if (rtp_code != -1 && (attr = generate_rtpmap_attr2(session, media, pool, rtp_code, 0, NULL, index, DEFAULT_DTMF_SAMPLE_RATE_MS))) {
2124 media->attr[media->attr_count++] = attr;
2125 snprintf(tmp, sizeof(tmp), "%d 0-16", (rtp_code));
2126 attr = pjmedia_sdp_attr_create(pool, "fmtp", pj_cstr(&stmp, tmp));
2127 media->attr[media->attr_count++] = attr;
2128 }
2129 }
2130 }
2131
2132 if (media->desc.fmt_count == PJMEDIA_MAX_SDP_FMT) {
2133 break;
2134 }
2135 }
2136 }
2137
2138 /* we are done with the sample rates */
2139 AST_VECTOR_FREE(&sample_rates);
2140
2141 /* If no formats were actually added to the media stream don't add it to the SDP */
2142 if (!media->desc.fmt_count) {
2143 SCOPE_EXIT_RTN_VALUE(1, "No formats added to stream\n");
2144 }
2145
2146 /* If ptime is set add it as an attribute */
2147 min_packet_size = ast_rtp_codecs_get_framing(ast_rtp_instance_get_codecs(session_media->rtp));
2148 if (!min_packet_size) {
2149 min_packet_size = ast_format_cap_get_framing(caps);
2150 }
2151 if (min_packet_size) {
2152 snprintf(tmp, sizeof(tmp), "%d", min_packet_size);
2153 attr = pjmedia_sdp_attr_create(pool, "ptime", pj_cstr(&stmp, tmp));
2154 media->attr[media->attr_count++] = attr;
2155 }
2156
2157 if (max_packet_size) {
2158 snprintf(tmp, sizeof(tmp), "%d", max_packet_size);
2159 attr = pjmedia_sdp_attr_create(pool, "maxptime", pj_cstr(&stmp, tmp));
2160 media->attr[media->attr_count++] = attr;
2161 }
2162
2163 attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
2164 if (session_media->locally_held) {
2165 if (session_media->remotely_held) {
2166 attr->name = STR_INACTIVE; /* To place on hold a recvonly stream, send inactive */
2167 } else {
2168 attr->name = STR_SENDONLY; /* Send sendonly to initate a local hold */
2169 }
2170 } else {
2171 if (session_media->remotely_held) {
2172 attr->name = STR_RECVONLY; /* Remote has sent sendonly, reply recvonly */
2173 } else if (ast_stream_get_state(stream) == AST_STREAM_STATE_SENDONLY) {
2174 attr->name = STR_SENDONLY; /* Stream has requested sendonly */
2175 } else if (ast_stream_get_state(stream) == AST_STREAM_STATE_RECVONLY) {
2176 attr->name = STR_RECVONLY; /* Stream has requested recvonly */
2177 } else if (ast_stream_get_state(stream) == AST_STREAM_STATE_INACTIVE) {
2178 attr->name = STR_INACTIVE; /* Stream has requested inactive */
2179 } else {
2180 attr->name = STR_SENDRECV; /* No hold in either direction */
2181 }
2182 }
2183 media->attr[media->attr_count++] = attr;
2184
2185 /* If we've got rtcp-mux enabled, add it unless we received an offer without it */
2186 if (session->endpoint->media.rtcp_mux && session_media->remote_rtcp_mux) {
2187 attr = pjmedia_sdp_attr_create(pool, "rtcp-mux", NULL);
2188 pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr);
2189 }
2190
2191 add_ssrc_to_stream(session, session_media, pool, media);
2192 add_msid_to_stream(session, session_media, pool, media, stream);
2193 add_rtcp_fb_to_stream(session, session_media, pool, media);
2194 add_extmap_to_stream(session, session_media, pool, media);
2195
2196 /* Add the media stream to the SDP */
2197 sdp->media[sdp->media_count++] = media;
2198
2199 SCOPE_EXIT_RTN_VALUE(1, "RC: 1\n");
2200}
2201
2203{
2204 struct ast_frame *f;
2205
2206 if (!session_media->rtp) {
2207 return &ast_null_frame;
2208 }
2209
2210 f = ast_rtp_instance_read(session_media->rtp, 0);
2211 if (!f) {
2212 return NULL;
2213 }
2214
2215 ast_rtp_instance_set_last_rx(session_media->rtp, time(NULL));
2216
2217 return f;
2218}
2219
2221{
2222 struct ast_frame *f;
2223
2224 if (!session_media->rtp) {
2225 return &ast_null_frame;
2226 }
2227
2228 f = ast_rtp_instance_read(session_media->rtp, 1);
2229 if (!f) {
2230 return NULL;
2231 }
2232
2233 ast_rtp_instance_set_last_rx(session_media->rtp, time(NULL));
2234
2235 return f;
2236}
2237
2238static int media_session_rtp_write_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media, struct ast_frame *frame)
2239{
2240 if (!session_media->rtp) {
2241 return 0;
2242 }
2243
2244 return ast_rtp_instance_write(session_media->rtp, frame);
2245}
2246
2248 struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *local,
2249 const struct pjmedia_sdp_session *remote, int index, struct ast_stream *asterisk_stream)
2250{
2251 RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free);
2252 struct pjmedia_sdp_media *remote_stream = remote->media[index];
2253 enum ast_media_type media_type = session_media->type;
2254 char host[NI_MAXHOST];
2255 int res;
2256 int rtp_timeout;
2257 struct ast_sip_session_media *session_media_transport;
2258 SCOPE_ENTER(1, "%s Stream: %s\n", ast_sip_session_get_name(session),
2259 ast_str_tmp(128, ast_stream_to_str(asterisk_stream, &STR_TMP)));
2260
2261 if (!session->channel) {
2262 SCOPE_EXIT_RTN_VALUE(1, "No channel\n");
2263 }
2264
2265 /* Ensure incoming transport is compatible with the endpoint's configuration */
2266 if (!session->endpoint->media.rtp.use_received_transport &&
2268 SCOPE_EXIT_RTN_VALUE(-1, "Incompatible transport\n");
2269 }
2270
2271 /* Create an RTP instance if need be */
2272 if (!session_media->rtp && create_rtp(session, session_media, local)) {
2273 SCOPE_EXIT_RTN_VALUE(-1, "Couldn't create rtp\n");
2274 }
2275
2276 process_ssrc_attributes(session, session_media, remote_stream);
2277 process_extmap_attributes(session, session_media, remote_stream);
2278
2279 session_media_transport = ast_sip_session_media_get_transport(session, session_media);
2280
2281 if (session_media_transport == session_media || !session_media->bundled) {
2282 session_media->remote_rtcp_mux = (pjmedia_sdp_media_find_attr2(remote_stream, "rtcp-mux", NULL) != NULL);
2283 set_ice_components(session, session_media);
2284
2285 enable_rtcp(session, session_media, remote_stream);
2286
2287 res = setup_media_encryption(session, session_media, remote, remote_stream);
2288 if (!session->endpoint->media.rtp.encryption_optimistic && res) {
2289 /* If optimistic encryption is disabled and crypto should have been enabled but was not
2290 * this session must fail.
2291 */
2292 SCOPE_EXIT_RTN_VALUE(-1, "Incompatible crypto\n");
2293 }
2294
2295 if (!remote_stream->conn && !remote->conn) {
2296 SCOPE_EXIT_RTN_VALUE(1, "No connection info\n");
2297 }
2298
2299 ast_copy_pj_str(host, remote_stream->conn ? &remote_stream->conn->addr : &remote->conn->addr, sizeof(host));
2300
2301 /* Ensure that the address provided is valid */
2302 if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) {
2303 /* The provided host was actually invalid so we error out this negotiation */
2304 SCOPE_EXIT_RTN_VALUE(-1, "Host invalid\n");
2305 }
2306
2307 /* Apply connection information to the RTP instance */
2308 ast_sockaddr_set_port(addrs, remote_stream->desc.port);
2309 ast_rtp_instance_set_remote_address(session_media->rtp, addrs);
2310
2314 if (!session->endpoint->media.rtcp_mux || !session_media->remote_rtcp_mux) {
2317 }
2318
2319 /* If ICE support is enabled find all the needed attributes */
2320 process_ice_attributes(session, session_media, remote, remote_stream);
2321 } else {
2322 /* This is bundled with another session, so mark it as such */
2323 ast_rtp_instance_bundle(session_media->rtp, session_media_transport->rtp);
2325 enable_rtcp(session, session_media, remote_stream);
2326 }
2327
2328 if (set_caps(session, session_media, session_media_transport, remote_stream, 0, asterisk_stream)) {
2329 SCOPE_EXIT_RTN_VALUE(-1, "set_caps failed\n");
2330 }
2331
2332 /* Set the channel uniqueid on the RTP instance now that it is becoming active */
2333 ast_channel_lock(session->channel);
2335 ast_channel_unlock(session->channel);
2336
2337 /* Ensure the RTP instance is active */
2338 ast_rtp_instance_set_stream_num(session_media->rtp, ast_stream_get_position(asterisk_stream));
2339 ast_rtp_instance_activate(session_media->rtp);
2340
2341 /* audio stream handles music on hold */
2342 if (media_type != AST_MEDIA_TYPE_AUDIO && media_type != AST_MEDIA_TYPE_VIDEO) {
2343 if ((pjmedia_sdp_neg_was_answer_remote(session->inv_session->neg) == PJ_FALSE)
2344 && (session->inv_session->state == PJSIP_INV_STATE_CONFIRMED)) {
2346 }
2347 SCOPE_EXIT_RTN_VALUE(1, "moh\n");
2348 }
2349
2350 set_session_media_remotely_held(session_media, session, remote_stream, asterisk_stream, addrs);
2351
2352 if (session_media->remotely_held_changed) {
2353 if (session_media->remotely_held) {
2354 /* The remote side has put us on hold */
2355 if (!session->endpoint->suppress_moh_on_sendonly) {
2356 ast_queue_hold(session->channel, session->endpoint->mohsuggest);
2357 ast_rtp_instance_stop(session_media->rtp);
2359 }
2360 session_media->remotely_held_changed = 0;
2361 } else {
2362 /* The remote side has taken us off hold */
2363 if (!session->endpoint->suppress_moh_on_sendonly) {
2364 ast_queue_unhold(session->channel);
2366 }
2367 session_media->remotely_held_changed = 0;
2368 }
2369 } else if ((pjmedia_sdp_neg_was_answer_remote(session->inv_session->neg) == PJ_FALSE)
2370 && (session->inv_session->state == PJSIP_INV_STATE_CONFIRMED)) {
2372 }
2373
2374 /* This purposely resets the encryption to the configured in case it gets added later */
2375 session_media->encryption = session->endpoint->media.rtp.encryption;
2376
2377 if (session->endpoint->media.rtp.keepalive > 0 &&
2378 (session_media->type == AST_MEDIA_TYPE_AUDIO ||
2379 session_media->type == AST_MEDIA_TYPE_VIDEO)) {
2380 ast_rtp_instance_set_keepalive(session_media->rtp, session->endpoint->media.rtp.keepalive);
2381 /* Schedule the initial keepalive early in case this is being used to punch holes through
2382 * a NAT. This way there won't be an awkward delay before media starts flowing in some
2383 * scenarios.
2384 */
2385 AST_SCHED_DEL(sched, session_media->keepalive_sched_id);
2387 session_media, 1);
2388 }
2389
2390 /* As the channel lock is not held during this process the scheduled item won't block if
2391 * it is hanging up the channel at the same point we are applying this negotiated SDP.
2392 */
2393 AST_SCHED_DEL(sched, session_media->timeout_sched_id);
2394
2395 /* Due to the fact that we only ever have one scheduled timeout item for when we are both
2396 * off hold and on hold we don't need to store the two timeouts differently on the RTP
2397 * instance itself.
2398 */
2399 ast_rtp_instance_set_timeout(session_media->rtp, 0);
2400 if (session->endpoint->media.rtp.timeout && !session_media->remotely_held && !session_media->locally_held) {
2401 ast_rtp_instance_set_timeout(session_media->rtp, session->endpoint->media.rtp.timeout);
2402 } else if (session->endpoint->media.rtp.timeout_hold && (session_media->remotely_held || session_media->locally_held)) {
2403 ast_rtp_instance_set_timeout(session_media->rtp, session->endpoint->media.rtp.timeout_hold);
2404 }
2405
2406 rtp_timeout = ast_rtp_instance_get_timeout(session_media->rtp);
2407
2408 if (rtp_timeout) {
2409 session_media->timeout_sched_id = ast_sched_add_variable(sched, rtp_timeout*1000, rtp_check_timeout,
2410 session_media, 1);
2411 }
2412
2413 SCOPE_EXIT_RTN_VALUE(1, "Handled\n");
2414}
2415
2416/*! \brief Function which updates the media stream with external media address, if applicable */
2417static void change_outgoing_sdp_stream_media_address(pjsip_tx_data *tdata, struct pjmedia_sdp_media *stream, struct ast_sip_transport *transport)
2418{
2420 char host[NI_MAXHOST];
2421 struct ast_sockaddr our_sdp_addr = { { 0, } };
2422
2423 /* If the stream has been rejected there will be no connection line */
2424 if (!stream->conn || !transport_state) {
2425 return;
2426 }
2427
2428 ast_copy_pj_str(host, &stream->conn->addr, sizeof(host));
2429 ast_sockaddr_parse(&our_sdp_addr, host, PARSE_PORT_FORBID);
2430
2431 /* Reversed check here. We don't check the remote endpoint being
2432 * in our local net, but whether our outgoing session IP is
2433 * local. If it is not, we won't do rewriting. No localnet
2434 * configured? Always rewrite. */
2435 if (ast_sip_transport_is_nonlocal(transport_state, &our_sdp_addr) && transport_state->localnet) {
2436 return;
2437 }
2438 ast_debug(5, "Setting media address to %s\n", ast_sockaddr_stringify_addr_remote(&transport_state->external_media_address));
2439 pj_strdup2(tdata->pool, &stream->conn->addr, ast_sockaddr_stringify_addr_remote(&transport_state->external_media_address));
2440}
2441
2442/*! \brief Function which stops the RTP instance */
2443static void stream_stop(struct ast_sip_session_media *session_media)
2444{
2445 if (!session_media->rtp) {
2446 return;
2447 }
2448
2449 AST_SCHED_DEL(sched, session_media->keepalive_sched_id);
2450 AST_SCHED_DEL(sched, session_media->timeout_sched_id);
2451 ast_rtp_instance_stop(session_media->rtp);
2452}
2453
2454/*! \brief Function which destroys the RTP instance when session ends */
2455static void stream_destroy(struct ast_sip_session_media *session_media)
2456{
2457 if (session_media->rtp) {
2458 stream_stop(session_media);
2459 ast_rtp_instance_destroy(session_media->rtp);
2460 }
2461 session_media->rtp = NULL;
2462}
2463
2464/*! \brief SDP handler for 'audio' media stream */
2466 .id = STR_AUDIO,
2467 .negotiate_incoming_sdp_stream = negotiate_incoming_sdp_stream,
2468 .create_outgoing_sdp_stream = create_outgoing_sdp_stream,
2469 .apply_negotiated_sdp_stream = apply_negotiated_sdp_stream,
2470 .change_outgoing_sdp_stream_media_address = change_outgoing_sdp_stream_media_address,
2471 .stream_stop = stream_stop,
2472 .stream_destroy = stream_destroy,
2473};
2474
2475/*! \brief SDP handler for 'video' media stream */
2477 .id = STR_VIDEO,
2478 .negotiate_incoming_sdp_stream = negotiate_incoming_sdp_stream,
2479 .create_outgoing_sdp_stream = create_outgoing_sdp_stream,
2480 .apply_negotiated_sdp_stream = apply_negotiated_sdp_stream,
2481 .change_outgoing_sdp_stream_media_address = change_outgoing_sdp_stream_media_address,
2482 .stream_stop = stream_stop,
2483 .stream_destroy = stream_destroy,
2484};
2485
2486static int video_info_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
2487{
2488 struct pjsip_transaction *tsx;
2489 pjsip_tx_data *tdata;
2490
2491 if (!session->channel
2492 || !ast_sip_are_media_types_equal(&rdata->msg_info.msg->body->content_type,
2494 return 0;
2495 }
2496
2497 tsx = pjsip_rdata_get_tsx(rdata);
2498
2500
2501 if (pjsip_dlg_create_response(session->inv_session->dlg, rdata, 200, NULL, &tdata) == PJ_SUCCESS) {
2502 pjsip_dlg_send_response(session->inv_session->dlg, tsx, tdata);
2503 }
2504
2505 return 0;
2506}
2507
2509 .method = "INFO",
2510 .incoming_request = video_info_incoming_request,
2511};
2512
2513/*! \brief Unloads the sdp RTP/AVP module from Asterisk */
2526
2527/*!
2528 * \brief Load the module
2529 *
2530 * Module loading including tests for configuration or dependencies.
2531 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
2532 * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
2533 * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
2534 * configuration file or other non-critical problem return
2535 * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
2536 */
2537static int load_module(void)
2538{
2539 if (ast_check_ipv6()) {
2541 } else {
2542 ast_sockaddr_parse(&address_rtp, "0.0.0.0", 0);
2543 }
2544
2545 if (!(sched = ast_sched_context_create())) {
2546 ast_log(LOG_ERROR, "Unable to create scheduler context.\n");
2547 goto end;
2548 }
2549
2551 ast_log(LOG_ERROR, "Unable to create scheduler context thread.\n");
2552 goto end;
2553 }
2554
2556 ast_log(LOG_ERROR, "Unable to register SDP handler for %s stream type\n", STR_AUDIO);
2557 goto end;
2558 }
2559
2561 ast_log(LOG_ERROR, "Unable to register SDP handler for %s stream type\n", STR_VIDEO);
2562 goto end;
2563 }
2564
2566
2568end:
2569 unload_module();
2570
2572}
2573
2574AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP SDP RTP/AVP stream handler",
2575 .support_level = AST_MODULE_SUPPORT_CORE,
2576 .load = load_module,
2577 .unload = unload_module,
2578 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
2579 .requires = "res_pjsip,res_pjsip_session",
Access Control of various sorts.
enum queue_result id
Definition app_queue.c:1790
Asterisk main include file. File version handling, generic pbx functions.
static struct ast_mansession session
#define ast_free(a)
Definition astmm.h:180
#define ast_strndup(str, len)
A wrapper for strndup()
Definition astmm.h:256
#define ast_log
Definition astobj2.c:42
#define ao2_iterator_next(iter)
Definition astobj2.h:1911
#define ao2_cleanup(obj)
Definition astobj2.h:1934
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
Internal Asterisk hangup causes.
#define AST_CAUSE_REQUESTED_CHAN_UNAVAIL
Definition causes.h:125
General Asterisk PBX channel definitions.
const char * ast_channel_name(const struct ast_channel *chan)
void ast_channel_set_unbridged_nolock(struct ast_channel *chan, int value)
Variant of ast_channel_set_unbridged. Use this if the channel is already locked prior to calling.
void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
#define ast_channel_lock(chan)
Definition channel.h:2983
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
int ast_queue_control(struct ast_channel *chan, enum ast_control_frame_type control)
Queue a control frame without payload.
Definition channel.c:1289
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel's frame queue.
Definition channel.c:1171
const char * ast_channel_uniqueid(const struct ast_channel *chan)
struct ast_channel * ast_channel_get_by_name(const char *search)
Find a channel by name or uniqueid.
Definition channel.c:1417
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition channel.c:5785
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition channel.c:10725
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition channel.c:2462
int ast_queue_unhold(struct ast_channel *chan)
Queue an unhold frame.
Definition channel.c:1274
int ast_queue_hold(struct ast_channel *chan, const char *musicclass)
Queue a hold frame.
Definition channel.c:1249
#define ast_channel_unref(c)
Decrease channel reference count.
Definition channel.h:3019
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition channel.c:5826
@ AST_SOFTHANGUP_DEV
Definition channel.h:1141
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
#define ast_channel_unlock(chan)
Definition channel.h:2984
struct ast_format * ast_channel_readformat(struct ast_channel *chan)
ast_channel_state
ast_channel states
@ AST_STATE_UP
static struct ao2_container * codecs
Registered codecs.
Definition codec.c:48
ast_media_type
Types of media.
Definition codec.h:30
@ AST_MEDIA_TYPE_AUDIO
Definition codec.h:32
@ AST_MEDIA_TYPE_UNKNOWN
Definition codec.h:31
@ AST_MEDIA_TYPE_VIDEO
Definition codec.h:33
const char * ast_codec_media_type2str(enum ast_media_type type)
Conversion function to take a media type and turn it into a string.
Definition codec.c:348
Convenient Signal Processing routines.
void ast_dsp_free(struct ast_dsp *dsp)
Definition dsp.c:1968
int ast_dsp_get_features(struct ast_dsp *dsp)
Get features.
Definition dsp.c:1962
void ast_dsp_set_features(struct ast_dsp *dsp, int features)
Select feature set.
Definition dsp.c:1953
char * end
Definition eagi_proxy.c:73
char * address
Definition f2c.h:59
Media Format API.
enum ast_media_type ast_format_get_type(const struct ast_format *format)
Get the media type of a format.
Definition format.c:354
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition format.c:334
void ast_format_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str)
This function is used to produce an fmtp SDP line for an Asterisk format. The attributes present on t...
Definition format.c:305
struct ast_format * ast_format_parse_sdp_fmtp(const struct ast_format *format, const char *attributes)
This function is used to have a media format aware module parse and interpret SDP attribute informati...
Definition format.c:286
unsigned int ast_format_get_maximum_ms(const struct ast_format *format)
Get the maximum amount of media carried in this format.
Definition format.c:369
Media Format Cache API.
Format Capabilities API.
#define AST_FORMAT_CAP_NAMES_LEN
Definition format_cap.h:324
int ast_format_cap_empty(const struct ast_format_cap *cap)
Determine if a format cap has no formats in it.
Definition format_cap.c:752
struct ast_format * ast_format_cap_get_format(const struct ast_format_cap *cap, int position)
Get the format at a specific index.
Definition format_cap.c:408
unsigned int ast_format_cap_get_framing(const struct ast_format_cap *cap)
Get the global framing.
Definition format_cap.c:446
struct ast_format * ast_format_cap_get_best_by_type(const struct ast_format_cap *cap, enum ast_media_type type)
Get the most preferred format for a particular media type.
Definition format_cap.c:425
int ast_format_cap_get_compatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
Find the compatible formats between two capabilities structures.
Definition format_cap.c:636
void ast_format_cap_remove_by_type(struct ast_format_cap *cap, enum ast_media_type type)
Remove all formats matching a specific format type.
Definition format_cap.c:531
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition format_cap.h:38
int ast_format_cap_append_from_cap(struct ast_format_cap *dst, const struct ast_format_cap *src, enum ast_media_type type)
Append the formats of provided type in src to dst.
Definition format_cap.c:269
const char * ast_format_cap_get_names(const struct ast_format_cap *cap, struct ast_str **buf)
Get the names of codecs of a set of formats.
Definition format_cap.c:742
int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_media_type type)
Find out if the capabilities structure has any formats of a specific type.
Definition format_cap.c:621
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition format_cap.h:99
void ast_format_cap_set_framing(struct ast_format_cap *cap, unsigned int framing)
Set the global framing.
Definition format_cap.c:136
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition format_cap.h:49
size_t ast_format_cap_count(const struct ast_format_cap *cap)
Get the number of formats present within the capabilities structure.
Definition format_cap.c:403
static const char name[]
Definition format_mp3.c:68
direction
#define SCOPE_EXIT_RTN(...)
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
#define SCOPE_ENTER(level,...)
@ AST_CONTROL_VIDUPDATE
@ AST_CONTROL_UPDATE_RTP_PEER
struct ast_frame ast_null_frame
Definition main/frame.c:79
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_NOTICE
#define LOG_WARNING
A set of macros to manage forward-linked lists.
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition module.h:331
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition module.h:557
@ AST_MODPRI_CHANNEL_DRIVER
Definition module.h:341
@ AST_MODULE_SUPPORT_CORE
Definition module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition module.h:78
Network socket handling.
char * ast_sockaddr_stringify_fmt(const struct ast_sockaddr *addr, int format)
Convert a socket address to a string.
Definition netsock2.c:65
#define AST_SOCKADDR_STR_ADDR
Definition netsock2.h:198
#define ast_sockaddr_port(addr)
Get the port number of a socket address.
Definition netsock2.h:517
int ast_sockaddr_is_any(const struct ast_sockaddr *addr)
Determine if the address type is unspecified, or "any" address.
Definition netsock2.c:534
int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str, int flags, int family)
Parses a string with an IPv4 or IPv6 address and place results into an array.
Definition netsock2.c:280
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
Definition netsock2.c:230
static int ast_sockaddr_isnull(const struct ast_sockaddr *addr)
Checks if the ast_sockaddr is null. "null" in this sense essentially means uninitialized,...
Definition netsock2.h:127
@ AST_AF_UNSPEC
Definition netsock2.h:54
static char * ast_sockaddr_stringify_port(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() to return a port only.
Definition netsock2.h:358
#define ast_sockaddr_set_port(addr, port)
Sets the port number of a socket address.
Definition netsock2.h:532
static char * ast_sockaddr_stringify_addr_remote(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() to return an address only.
Definition netsock2.h:313
const char * ast_sip_get_host_ip_string(int af)
Retrieve the local host address in string form.
Definition res_pjsip.c:2468
pjsip_media_type pjsip_media_type_application_media_control_xml
Definition res_pjsip.c:3905
ast_sip_session_media_encryption
Definition res_pjsip.h:735
@ AST_SIP_MEDIA_ENCRYPT_SDES
Definition res_pjsip.h:741
@ AST_SIP_MEDIA_TRANSPORT_INVALID
Definition res_pjsip.h:737
@ AST_SIP_MEDIA_ENCRYPT_NONE
Definition res_pjsip.h:739
@ AST_SIP_MEDIA_ENCRYPT_DTLS
Definition res_pjsip.h:743
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition res_pjsip.c:2176
int ast_sip_are_media_types_equal(pjsip_media_type *a, pjsip_media_type *b)
Compare pjsip media types.
Definition res_pjsip.c:2194
@ AST_SIP_DTMF_AUTO_INFO
Definition res_pjsip.h:560
@ AST_SIP_DTMF_AUTO
Definition res_pjsip.h:558
@ AST_SIP_DTMF_INBAND
Definition res_pjsip.h:554
@ AST_SIP_DTMF_RFC_4733
Definition res_pjsip.h:552
#define ast_sip_transport_is_nonlocal(transport_state, addr)
Definition res_pjsip.h:210
struct ast_sip_transport_state * ast_sip_get_transport_state(const char *transport_id)
Retrieve transport state.
@ AST_SIP_SECURITY_NEG_MEDIASEC
Definition res_pjsip.h:357
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
static int send_keepalive(const void *data)
static pjmedia_sdp_attr * generate_rtpmap_attr2(struct ast_sip_session *session, pjmedia_sdp_media *media, pj_pool_t *pool, int rtp_code, int asterisk_format, struct ast_format *format, int code, int sample_rate)
static void apply_dtls_attrib(struct ast_sip_session_media *session_media, pjmedia_sdp_attr *attr)
static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const pjmedia_sdp_session *sdp, int index, struct ast_stream *asterisk_stream)
Function which negotiates an incoming media stream.
static void set_session_media_remotely_held(struct ast_sip_session_media *session_media, const struct ast_sip_session *session, const pjmedia_sdp_media *media, const struct ast_stream *stream, const struct ast_sockaddr *addrs)
static void check_ice_support(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_media *remote_stream)
Function which checks for ice attributes in an audio stream.
static enum ast_sip_session_media_encryption check_endpoint_media_transport(struct ast_sip_endpoint *endpoint, const struct pjmedia_sdp_media *stream)
Checks whether the encryption offered in SDP is compatible with the endpoint's configuration.
static struct ast_sched_context * sched
Scheduler for RTCP purposes.
static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *local, const struct pjmedia_sdp_session *remote, int index, struct ast_stream *asterisk_stream)
static struct ast_frame * media_session_rtcp_read_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media)
static void process_ice_attributes(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream)
Function which processes ICE attributes in an audio stream.
static int set_caps(struct ast_sip_session *session, struct ast_sip_session_media *session_media, struct ast_sip_session_media *session_media_transport, const struct pjmedia_sdp_media *stream, int is_offer, struct ast_stream *asterisk_stream)
static int media_session_rtp_write_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media, struct ast_frame *frame)
static int rtp_check_timeout(const void *data)
Check whether RTP is being received or not.
static const char STR_AUDIO[]
static struct ast_sip_session_sdp_handler audio_sdp_handler
SDP handler for 'audio' media stream.
static int apply_cap_to_bundled(struct ast_sip_session_media *session_media, struct ast_sip_session_media *session_media_transport, struct ast_stream *asterisk_stream, struct ast_format_cap *joint)
static void add_ice_to_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media, unsigned int include_candidates)
Function which adds ICE attributes to a media stream.
static void add_extmap_to_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media)
static int setup_media_encryption(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
static void get_codecs(struct ast_sip_session *session, const struct pjmedia_sdp_media *stream, struct ast_rtp_codecs *codecs, struct ast_sip_session_media *session_media, struct ast_format_cap *astformats)
static void stream_stop(struct ast_sip_session_media *session_media)
Function which stops the RTP instance.
static struct ast_format_cap * set_incoming_call_offer_cap(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_media *stream)
static int setup_srtp(struct ast_sip_session_media *session_media)
static void stream_destroy(struct ast_sip_session_media *session_media)
Function which destroys the RTP instance when session ends.
static int parse_dtls_attrib(struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
static const char STR_VIDEO[]
static void change_outgoing_sdp_stream_media_address(pjsip_tx_data *tdata, struct pjmedia_sdp_media *stream, struct ast_sip_transport *transport)
Function which updates the media stream with external media address, if applicable.
static int media_stream_has_crypto(const struct pjmedia_sdp_media *stream)
figure out if media stream has crypto lines for sdes
static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_session *remote, struct ast_stream *stream)
Function which creates an outgoing stream.
static void process_extmap_attributes(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_media *remote_stream)
Function which processes extmap attributes in a stream.
static void process_ice_auth_attrb(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream)
static void add_rtcp_fb_to_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media)
static struct ast_sockaddr address_rtp
Address for RTP.
static void add_msid_to_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media, struct ast_stream *stream)
static struct ast_sip_session_sdp_handler video_sdp_handler
SDP handler for 'video' media stream.
static int load_module(void)
Load the module.
static pjmedia_sdp_attr * generate_rtpmap_attr(struct ast_sip_session *session, pjmedia_sdp_media *media, pj_pool_t *pool, int rtp_code, int asterisk_format, struct ast_format *format, int code)
static enum ast_sip_session_media_encryption get_media_encryption_type(pj_str_t transport, const struct pjmedia_sdp_media *stream, unsigned int *optimistic)
figure out media transport encryption type from the media transport string
static int unload_module(void)
Unloads the sdp RTP/AVP module from Asterisk.
static int video_info_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
static struct ast_sip_session_supplement video_info_supplement
static int add_crypto_to_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media)
static struct ast_frame * media_session_rtp_read_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media)
static void enable_rtp_extension(struct ast_sip_session *session, struct ast_sip_session_media *session_media, enum ast_rtp_extension extension, enum ast_rtp_extension_direction direction, const pjmedia_sdp_session *sdp)
Enable an RTP extension on an RTP session.
static void add_ssrc_to_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media)
Function which adds ssrc attributes to a media stream.
static pjmedia_sdp_attr * generate_fmtp_attr(pj_pool_t *pool, struct ast_format *format, int rtp_code)
static void enable_rtcp(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_media *remote_media)
Enable RTCP on an RTP session.
static int setup_sdes_srtp(struct ast_sip_session_media *session_media, const struct pjmedia_sdp_media *stream)
static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const pjmedia_sdp_session *sdp)
Internal function which creates an RTP instance.
static int setup_dtls_srtp(struct ast_sip_session *session, struct ast_sip_session_media *session_media)
static void set_ice_components(struct ast_sip_session *session, struct ast_sip_session_media *session_media)
static void process_ssrc_attributes(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_media *remote_stream)
Function which processes ssrc attributes in a stream.
void ast_sip_session_unregister_sdp_handler(struct ast_sip_session_sdp_handler *handler, const char *stream_type)
Unregister an SDP handler.
int ast_sip_session_register_sdp_handler(struct ast_sip_session_sdp_handler *handler, const char *stream_type)
Register an SDP handler.
int ast_sip_session_is_pending_stream_default(const struct ast_sip_session *session, const struct ast_stream *stream)
Determines if a provided pending stream will be the default stream or not.
int ast_sip_session_media_add_read_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media, int fd, ast_sip_session_media_read_cb callback)
Set a read callback for a media session with a specific file descriptor.
struct ast_sip_session_media * ast_sip_session_media_get_transport(struct ast_sip_session *session, struct ast_sip_session_media *session_media)
Retrieve the underlying media session that is acting as transport for a media session.
#define ast_sip_session_register_supplement(supplement)
void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement)
Unregister a an supplement to SIP session processing.
int ast_sip_session_media_set_write_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media, ast_sip_session_media_write_cb callback)
Set a write callback for a media session.
const char * ast_sip_session_get_name(const struct ast_sip_session *session)
Get the channel or endpoint name associated with the session.
struct ast_format_cap * ast_sip_session_create_joint_call_cap(const struct ast_sip_session *session, enum ast_media_type media_type, const struct ast_format_cap *remote)
Create joint capabilities.
@ AST_AES_CM_128_HMAC_SHA1_80
Definition res_srtp.h:58
@ AST_AES_CM_128_HMAC_SHA1_32
Definition res_srtp.h:59
#define NULL
Definition resample.c:96
Pluggable RTP Architecture.
ast_rtp_dtls_setup
DTLS setup types.
Definition rtp_engine.h:564
@ AST_RTP_DTLS_SETUP_PASSIVE
Definition rtp_engine.h:566
@ AST_RTP_DTLS_SETUP_HOLDCONN
Definition rtp_engine.h:568
@ AST_RTP_DTLS_SETUP_ACTPASS
Definition rtp_engine.h:567
@ AST_RTP_DTLS_SETUP_ACTIVE
Definition rtp_engine.h:565
unsigned int ast_rtp_lookup_sample_rate2(int asterisk_format, const struct ast_format *format, int code)
Get the sample rate associated with known RTP payload types.
@ AST_RTP_ICE_ROLE_CONTROLLING
Definition rtp_engine.h:521
@ AST_RTP_ICE_ROLE_CONTROLLED
Definition rtp_engine.h:520
struct ast_format * ast_rtp_codecs_get_payload_format(struct ast_rtp_codecs *codecs, int payload)
Retrieve the actual ast_format stored on the codecs structure for a specific tx payload type.
void ast_rtp_codecs_payloads_destroy(struct ast_rtp_codecs *codecs)
Destroy the contents of an RTP codecs structure (but not the structure itself)
int ast_rtp_instance_destroy(struct ast_rtp_instance *instance)
Destroy an RTP instance.
Definition rtp_engine.c:468
enum ast_rtp_dtmf_mode ast_rtp_instance_dtmf_mode_get(struct ast_rtp_instance *instance)
Get the DTMF mode of an RTP instance.
int ast_rtp_codecs_payload_set_rx(struct ast_rtp_codecs *codecs, int code, struct ast_format *format)
Set a payload code for use with a specific Asterisk format.
struct ast_rtp_instance * ast_rtp_instance_new(const char *engine_name, struct ast_sched_context *sched, const struct ast_sockaddr *sa, void *data)
Create a new RTP instance.
Definition rtp_engine.c:497
void ast_rtp_instance_set_last_rx(struct ast_rtp_instance *rtp, time_t time)
Set the last RTP reception time.
ast_rtp_dtls_hash
DTLS fingerprint hashes.
Definition rtp_engine.h:578
@ AST_RTP_DTLS_HASH_SHA1
Definition rtp_engine.h:580
@ AST_RTP_DTLS_HASH_SHA256
Definition rtp_engine.h:579
@ AST_RTP_DTMF_MODE_RFC2833
Definition rtp_engine.h:155
@ AST_RTP_DTMF_MODE_INBAND
Definition rtp_engine.h:157
@ AST_RTP_DTMF_MODE_NONE
Definition rtp_engine.h:153
int ast_rtp_instance_dtmf_mode_set(struct ast_rtp_instance *instance, enum ast_rtp_dtmf_mode dtmf_mode)
Set the DTMF mode that should be used.
void ast_rtp_instance_stop(struct ast_rtp_instance *instance)
Stop an RTP instance.
#define AST_RTP_DTMF
Definition rtp_engine.h:294
ast_rtp_instance_rtcp
Definition rtp_engine.h:283
@ AST_RTP_INSTANCE_RTCP_MUX
Definition rtp_engine.h:289
@ AST_RTP_INSTANCE_RTCP_STANDARD
Definition rtp_engine.h:287
void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance)
Copy payload information from one RTP instance to another.
size_t ast_rtp_instance_extmap_count(struct ast_rtp_instance *instance)
Get the number of known unique identifiers.
Definition rtp_engine.c:950
int ast_rtp_instance_extmap_enable(struct ast_rtp_instance *instance, int id, enum ast_rtp_extension extension, enum ast_rtp_extension_direction direction)
Enable support for an RTP extension on an instance.
Definition rtp_engine.c:783
@ AST_RTP_INSTANCE_STAT_REMOTE_SSRC
Definition rtp_engine.h:251
void ast_rtp_instance_set_stream_num(struct ast_rtp_instance *instance, int stream_num)
Set the stream number for an RTP instance.
int ast_rtp_instance_get_keepalive(struct ast_rtp_instance *instance)
Get the RTP keepalive interval.
const char * ast_rtp_instance_get_cname(struct ast_rtp_instance *rtp)
Retrieve the CNAME used in RTCP SDES items.
int ast_rtp_instance_get_timeout(struct ast_rtp_instance *instance)
Get the RTP timeout value.
struct ast_rtp_engine_dtls * ast_rtp_instance_get_dtls(struct ast_rtp_instance *instance)
Obtain a pointer to the DTLS support present on an RTP instance.
#define ast_debug_rtp(sublevel,...)
Log debug level RTP information.
struct ast_frame * ast_rtp_instance_read(struct ast_rtp_instance *instance, int rtcp)
Receive a frame over RTP.
Definition rtp_engine.c:629
int ast_rtp_instance_bundle(struct ast_rtp_instance *child, struct ast_rtp_instance *parent)
Request that an RTP instance be bundled with another.
void ast_rtp_codecs_set_framing(struct ast_rtp_codecs *codecs, unsigned int framing)
Set the framing used for a set of codecs.
time_t ast_rtp_instance_get_last_tx(const struct ast_rtp_instance *rtp)
Get the last RTP transmission time.
void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload)
Record tx payload type information that was seen in an m= SDP line.
void ast_rtp_instance_set_prop(struct ast_rtp_instance *instance, enum ast_rtp_property property, int value)
Set the value of an RTP instance property.
Definition rtp_engine.c:756
void ast_rtp_instance_get_local_address(struct ast_rtp_instance *instance, struct ast_sockaddr *address)
Get the local address that we are expecting RTP on.
Definition rtp_engine.c:694
struct ast_rtp_instance * ast_rtp_instance_new_with_options(const char *engine_name, struct ast_sched_context *sched, const struct ast_sockaddr *sa, void *data, const struct ast_rtp_instance_options *options)
Create a new RTP instance with additional options.
Definition rtp_engine.c:505
int ast_rtp_instance_get_stats(struct ast_rtp_instance *instance, struct ast_rtp_instance_stats *stats, enum ast_rtp_instance_stat stat)
Retrieve statistics about an RTP instance.
@ AST_RTP_ICE_CANDIDATE_TYPE_RELAYED
Definition rtp_engine.h:509
@ AST_RTP_ICE_CANDIDATE_TYPE_SRFLX
Definition rtp_engine.h:508
@ AST_RTP_ICE_CANDIDATE_TYPE_HOST
Definition rtp_engine.h:507
int ast_rtp_codecs_payload_code_sample_rate(struct ast_rtp_codecs *codecs, int asterisk_format, struct ast_format *format, int code, unsigned int sample_rate)
Retrieve a rx mapped payload type based on whether it is an Asterisk format, the code and the sample ...
enum ast_rtp_extension ast_rtp_instance_extmap_get_extension(struct ast_rtp_instance *instance, int id)
Retrieve the extension for an RTP extension id.
Definition rtp_engine.c:961
int ast_rtp_instance_write(struct ast_rtp_instance *instance, struct ast_frame *frame)
Send a frame out over RTP.
Definition rtp_engine.c:619
ast_rtp_extension
Known RTP extensions.
Definition rtp_engine.h:593
@ AST_RTP_EXTENSION_TRANSPORT_WIDE_CC
Definition rtp_engine.h:599
@ AST_RTP_EXTENSION_ABS_SEND_TIME
Definition rtp_engine.h:597
@ AST_RTP_EXTENSION_UNSUPPORTED
Definition rtp_engine.h:595
#define ast_rtp_instance_set_remote_address(instance, address)
Set the address of the remote endpoint that we are sending RTP to.
int ast_rtp_instance_sendcng(struct ast_rtp_instance *instance, int level)
Send a comfort noise packet to the RTP instance.
void ast_rtp_instance_set_remote_ssrc(struct ast_rtp_instance *rtp, unsigned int ssrc)
Set the remote SSRC for an RTP instance.
struct ast_rtp_engine_ice * ast_rtp_instance_get_ice(struct ast_rtp_instance *instance)
Obtain a pointer to the ICE support present on an RTP instance.
ast_rtp_options
Definition rtp_engine.h:145
@ AST_RTP_OPT_G726_NONSTANDARD
Definition rtp_engine.h:147
@ AST_RTP_DTLS_CONNECTION_NEW
Definition rtp_engine.h:573
@ AST_RTP_DTLS_CONNECTION_EXISTING
Definition rtp_engine.h:574
void ast_rtp_codecs_payloads_merge(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance)
Merge payload information from one RTP instance into another.
int ast_rtp_codecs_payloads_initialize(struct ast_rtp_codecs *codecs)
Initialize an RTP codecs structure.
@ AST_RTP_PROPERTY_NAT
Definition rtp_engine.h:118
@ AST_RTP_PROPERTY_RETRANS_RECV
Definition rtp_engine.h:130
@ AST_RTP_PROPERTY_RETRANS_SEND
Definition rtp_engine.h:132
@ AST_RTP_PROPERTY_RTCP
Definition rtp_engine.h:126
@ AST_RTP_PROPERTY_ASYMMETRIC_CODEC
Definition rtp_engine.h:128
@ AST_RTP_PROPERTY_DTMF
Definition rtp_engine.h:120
@ AST_RTP_PROPERTY_REMB
Definition rtp_engine.h:134
#define AST_RTP_PT_LAST_STATIC
Definition rtp_engine.h:89
#define ast_debug_ice(sublevel,...)
Log debug level ICE information.
int ast_rtp_instance_activate(struct ast_rtp_instance *instance)
Indicate to the RTP engine that packets are now expected to be sent/received on the RTP instance.
const char * ast_rtp_lookup_mime_subtype2(const int asterisk_format, const struct ast_format *format, int code, enum ast_rtp_options options)
Retrieve mime subtype information on a payload.
time_t ast_rtp_instance_get_last_rx(const struct ast_rtp_instance *rtp)
Get the last RTP reception time.
int ast_rtp_instance_set_qos(struct ast_rtp_instance *instance, int tos, int cos, const char *desc)
Set QoS parameters on an RTP session.
void ast_rtp_instance_set_channel_id(struct ast_rtp_instance *instance, const char *uniqueid)
Set the channel that owns this RTP instance.
Definition rtp_engine.c:604
ast_rtp_extension_direction
Directions for RTP extensions.
Definition rtp_engine.h:827
@ AST_RTP_EXTENSION_DIRECTION_SENDRECV
Definition rtp_engine.h:831
@ AST_RTP_EXTENSION_DIRECTION_NONE
Definition rtp_engine.h:829
@ AST_RTP_EXTENSION_DIRECTION_INACTIVE
Definition rtp_engine.h:837
@ AST_RTP_EXTENSION_DIRECTION_RECVONLY
Definition rtp_engine.h:835
@ AST_RTP_EXTENSION_DIRECTION_SENDONLY
Definition rtp_engine.h:833
int ast_rtp_codecs_payload_replace_format(struct ast_rtp_codecs *codecs, int payload, struct ast_format *format)
Update the format associated with a tx payload type in a codecs structure.
const char * ast_rtp_instance_extmap_get_uri(struct ast_rtp_instance *instance, int id)
Retrieve the URI for an RTP extension id.
Definition rtp_engine.c:997
int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int pt, char *mimetype, char *mimesubtype, enum ast_rtp_options options, unsigned int sample_rate)
Set tx payload type to a known MIME media type for a codec with a specific sample rate.
int ast_rtp_codecs_set_preferred_dtmf_format(struct ast_rtp_codecs *codecs, int pt, int rate)
Set the preferred dtmf format pt and sample rate.
#define AST_RTP_CODECS_NULL_INIT
Definition rtp_engine.h:773
int ast_rtp_instance_extmap_get_id(struct ast_rtp_instance *instance, enum ast_rtp_extension extension)
Retrieve the id for an RTP extension.
Definition rtp_engine.c:937
void ast_rtp_instance_change_source(struct ast_rtp_instance *instance)
Indicate a new source of audio has dropped in and the ssrc should change.
int ast_rtp_instance_extmap_negotiate(struct ast_rtp_instance *instance, int id, enum ast_rtp_extension_direction direction, const char *uri, const char *attributes)
Negotiate received RTP extension information.
Definition rtp_engine.c:869
void ast_rtp_instance_extmap_clear(struct ast_rtp_instance *instance)
Clear negotiated RTP extension information.
Definition rtp_engine.c:913
#define AST_RTP_MAX
Definition rtp_engine.h:300
struct ast_rtp_codecs * ast_rtp_instance_get_codecs(struct ast_rtp_instance *instance)
Get the codecs structure of an RTP instance.
Definition rtp_engine.c:778
const char * ast_rtp_instance_get_channel_id(struct ast_rtp_instance *instance)
Get the unique ID of the channel that owns this RTP instance.
Definition rtp_engine.c:599
int ast_rtp_instance_fd(struct ast_rtp_instance *instance, int rtcp)
Get the file descriptor for an RTP session (or RTCP)
unsigned int ast_rtp_codecs_get_framing(struct ast_rtp_codecs *codecs)
Get the framing used for a set of codecs.
void ast_rtp_instance_set_keepalive(struct ast_rtp_instance *instance, int timeout)
Set the RTP keepalive interval.
unsigned int ast_rtp_instance_get_ssrc(struct ast_rtp_instance *rtp)
Retrieve the local SSRC value that we will be using.
#define DEFAULT_DTMF_SAMPLE_RATE_MS
Definition rtp_engine.h:110
int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, int asterisk_format, struct ast_format *format, int code)
Retrieve a rx mapped payload type based on whether it is an Asterisk format and the code.
enum ast_rtp_extension_direction ast_rtp_instance_extmap_get_direction(struct ast_rtp_instance *instance, int id)
Retrieve the negotiated direction for an RTP extension id.
Definition rtp_engine.c:981
void ast_rtp_codecs_payloads_xover(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance)
Crossover copy the tx payload mapping of src to the rx payload mapping of dest.
void ast_rtp_instance_set_timeout(struct ast_rtp_instance *instance, int timeout)
Set the RTP timeout value.
int ast_rtp_codecs_set_preferred_format(struct ast_rtp_codecs *codecs, struct ast_format *format)
Set the preferred format.
Scheduler Routines (derived from cheops)
#define AST_SCHED_DEL(sched, id)
Remove a scheduler entry.
Definition sched.h:46
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
Definition sched.c:271
int ast_sched_start_thread(struct ast_sched_context *con)
Start a thread for processing scheduler entries.
Definition sched.c:197
int ast_sched_add_variable(struct ast_sched_context *con, int when, ast_sched_cb callback, const void *data, int variable) attribute_warn_unused_result
Adds a scheduled event with rescheduling support.
Definition sched.c:526
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
Definition sched.c:238
SRTP and SDP Security descriptions.
const char * ast_sdp_srtp_get_attrib(struct ast_sdp_srtp *srtp, int dtls_enabled, int default_taglen_32)
Get the crypto attribute line for the srtp structure.
Definition sdp_srtp.c:95
struct ast_sdp_crypto * ast_sdp_crypto_alloc(void)
Initialize an return an ast_sdp_crypto struct.
Definition sdp_srtp.c:71
struct ast_sdp_srtp * ast_sdp_srtp_alloc(void)
allocate a ast_sdp_srtp structure
Definition sdp_srtp.c:41
int ast_sdp_crypto_process(struct ast_rtp_instance *rtp, struct ast_sdp_srtp *srtp, const char *attr)
Parse the a=crypto line from SDP and set appropriate values on the ast_sdp_crypto struct.
Definition sdp_srtp.c:79
char * ast_sdp_get_rtp_profile(unsigned int sdes_active, struct ast_rtp_instance *instance, unsigned int using_avpf, unsigned int force_avp)
Get the RTP profile in use by a media session.
Definition sdp_srtp.c:103
#define AST_SRTP_CRYPTO_OFFER_OK
Definition sdp_srtp.h:45
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition sorcery.c:2381
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition sorcery.c:1917
Media Stream API.
const char * ast_stream_to_str(const struct ast_stream *stream, struct ast_str **buf)
Get a string representing the stream for debugging/display purposes.
Definition stream.c:337
const char * ast_stream_get_metadata(const struct ast_stream *stream, const char *m_key)
Get a stream metadata value.
Definition stream.c:423
int ast_stream_set_metadata(struct ast_stream *stream, const char *m_key, const char *value)
Set a stream metadata value.
Definition stream.c:460
@ AST_STREAM_STATE_RECVONLY
Set when the stream is receiving media only.
Definition stream.h:90
@ AST_STREAM_STATE_INACTIVE
Set when the stream is not sending OR receiving media.
Definition stream.h:94
@ AST_STREAM_STATE_REMOVED
Set when the stream has been removed/declined.
Definition stream.h:78
@ AST_STREAM_STATE_SENDONLY
Set when the stream is sending media only.
Definition stream.h:86
int ast_stream_get_position(const struct ast_stream *stream)
Get the position of the stream in the topology.
Definition stream.c:500
void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state)
Set the state of a stream.
Definition stream.c:380
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
Definition stream.c:373
int ast_stream_get_group(const struct ast_stream *stream)
Get the stream group that a stream is part of.
Definition stream.c:1080
enum ast_media_type ast_stream_get_type(const struct ast_stream *stream)
Get the media type of a stream.
Definition stream.c:316
void ast_stream_set_formats(struct ast_stream *stream, struct ast_format_cap *caps)
Set the current negotiated formats of a stream.
Definition stream.c:365
const struct ast_format_cap * ast_stream_get_formats(const struct ast_stream *stream)
Get the current negotiated formats of a stream.
Definition stream.c:330
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition strings.h:1139
size_t attribute_pure ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition strings.h:730
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
#define ast_str_tmp(init_len, __expr)
Provides a temporary ast_str and returns a copy of its buffer.
Definition strings.h:1189
#define ast_str_alloca(init_len)
Definition strings.h:848
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition strings.h:1113
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition astobj2.h:1821
Main Channel structure associated with a channel.
Format capabilities structure, holds formats + preference order + etc.
Definition format_cap.c:54
Definition of a media format.
Definition format.c:43
Data structure associated with a single frame of data.
Structure that represents the optional DTLS SRTP support within an RTP engine.
Definition rtp_engine.h:621
int(* set_configuration)(struct ast_rtp_instance *instance, const struct ast_rtp_dtls_cfg *dtls_cfg)
Definition rtp_engine.h:623
enum ast_rtp_dtls_setup(* get_setup)(struct ast_rtp_instance *instance)
Definition rtp_engine.h:633
enum ast_rtp_dtls_hash(* get_fingerprint_hash)(struct ast_rtp_instance *instance)
Definition rtp_engine.h:639
const char *(* get_fingerprint)(struct ast_rtp_instance *instance)
Definition rtp_engine.h:641
void(* reset)(struct ast_rtp_instance *instance)
Definition rtp_engine.h:629
void(* set_fingerprint)(struct ast_rtp_instance *instance, enum ast_rtp_dtls_hash hash, const char *fingerprint)
Definition rtp_engine.h:637
enum ast_rtp_dtls_connection(* get_connection)(struct ast_rtp_instance *instance)
Definition rtp_engine.h:631
void(* set_setup)(struct ast_rtp_instance *instance, enum ast_rtp_dtls_setup setup)
Definition rtp_engine.h:635
Structure for an ICE candidate.
Definition rtp_engine.h:525
struct ast_sockaddr address
Definition rtp_engine.h:530
enum ast_rtp_ice_component_type id
Definition rtp_engine.h:527
struct ast_sockaddr relay_address
Definition rtp_engine.h:531
enum ast_rtp_ice_candidate_type type
Definition rtp_engine.h:532
Structure that represents the optional ICE support within an RTP engine.
Definition rtp_engine.h:536
void(* ice_lite)(struct ast_rtp_instance *instance)
Definition rtp_engine.h:552
void(* stop)(struct ast_rtp_instance *instance)
Definition rtp_engine.h:544
void(* change_components)(struct ast_rtp_instance *instance, int num_components)
Definition rtp_engine.h:560
void(* set_authentication)(struct ast_rtp_instance *instance, const char *ufrag, const char *password)
Definition rtp_engine.h:538
void(* start)(struct ast_rtp_instance *instance)
Definition rtp_engine.h:542
const char *(* get_ufrag)(struct ast_rtp_instance *instance)
Definition rtp_engine.h:546
void(* add_remote_candidate)(struct ast_rtp_instance *instance, const struct ast_rtp_engine_ice_candidate *candidate)
Definition rtp_engine.h:540
const char *(* get_password)(struct ast_rtp_instance *instance)
Definition rtp_engine.h:548
void(* set_role)(struct ast_rtp_instance *instance, enum ast_rtp_ice_role role)
Definition rtp_engine.h:554
struct ao2_container *(* get_local_candidates)(struct ast_rtp_instance *instance)
Definition rtp_engine.h:550
Options for creating a new RTP instance.
Definition rtp_engine.h:994
unsigned int remote_ssrc
Definition rtp_engine.h:454
structure for secure RTP audio
Definition sdp_srtp.h:38
struct ast_sdp_srtp::@297 sdp_srtp_list
struct ast_sdp_crypto * crypto
Definition sdp_srtp.h:40
struct ast_sip_media_rtp_configuration rtp
Definition res_pjsip.h:1019
An entity with which Asterisk communicates.
Definition res_pjsip.h:1067
struct ast_sip_endpoint_media_configuration media
Definition res_pjsip.h:1100
enum ast_sip_session_media_encryption encryption
Definition res_pjsip.h:958
A structure containing SIP session media information.
struct ast_sdp_srtp * srtp
Holds SRTP information.
unsigned int remotely_held_changed
Stream is held by remote side changed during this negotiation.
char label[AST_UUID_STR_LEN]
Track label.
unsigned int remote_ice
Does remote support ice.
enum ast_media_type type
Media type of this session media.
unsigned int locally_held
Stream is on hold by local side.
unsigned int remote_rtcp_mux
Does remote support rtcp_mux.
int timeout_sched_id
Scheduler ID for RTP timeout.
int stream_num
The stream number to place into any resulting frames.
int bundle_group
The bundle group the stream belongs to.
unsigned int remotely_held
Stream is on hold by remote side.
struct ast_rtp_instance * rtp
RTP instance itself.
enum ast_sip_session_media_encryption encryption
What type of encryption is in use on this stream.
struct ast_sockaddr direct_media_addr
Direct media address.
char mslabel[AST_UUID_STR_LEN]
Media stream label.
pj_str_t transport
The media transport in use for this stream.
unsigned int bundled
Whether this stream is currently bundled or not.
unsigned int changed
The underlying session has been changed in some fashion.
int keepalive_sched_id
Scheduler ID for RTP keepalive.
A handler for SDPs in SIP sessions.
A supplement to SIP message processing.
struct ast_module *const char * method
A structure describing a SIP session.
Structure for SIP transport information.
Definition res_pjsip.h:117
struct pjsip_transport * transport
Transport itself.
Definition res_pjsip.h:119
Transport to bind to.
Definition res_pjsip.h:219
Socket address structure.
Definition netsock2.h:97
Support for dynamic strings.
Definition strings.h:623
structure to hold extensions
Definition sched.c:76
int value
Definition syslog.c:37
static struct test_options options
Utility functions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:981
#define ast_assert(a)
Definition utils.h:779
#define ast_set_flag(p, flag)
Definition utils.h:71
int ast_check_ipv6(void)
Test that an OS supports IPv6 Networking.
Definition utils.c:2826
#define AST_UUID_STR_LEN
Definition uuid.h:27
char * ast_uuid_generate_str(char *buf, size_t size)
Generate a UUID string.
Definition uuid.c:141
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition vector.h:637
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition vector.h:185
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition vector.h:124
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition vector.h:267
#define AST_VECTOR(name, type)
Define a vector structure.
Definition vector.h:44
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition vector.h:708