2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2013, Digium, Inc.
6 * See http://www.asterisk.org for more information about
7 * the Asterisk project. Please do not directly contact
8 * any of the maintainers of this project for assistance;
9 * the project provides a web site, mailing lists and IRC
10 * channels for your use.
12 * This program is free software, distributed under the terms of
13 * the GNU General Public License Version 2. See the LICENSE file
14 * at the top of the source tree.
20 * \author \verbatim Joshua Colp <jcolp@digium.com> \endverbatim
21 * \author \verbatim Matt Jordan <mjordan@digium.com> \endverbatim
25 * \brief PJSIP channel dialplan functions
29 <support_level>core</support_level>
33 <function name="PJSIP_DIAL_CONTACTS" language="en_US">
35 Return a dial string for dialing all contacts on an AOR.
38 <parameter name="endpoint" required="true">
39 <para>Name of the endpoint</para>
41 <parameter name="aor" required="false">
42 <para>Name of an AOR to use, if not specified the configured AORs on the endpoint are used</para>
44 <parameter name="request_user" required="false">
45 <para>Optional request user to use in the request URI</para>
49 <para>Returns a properly formatted dial string for dialing all contacts on an AOR.</para>
52 <function name="PJSIP_MEDIA_OFFER" language="en_US">
54 Media and codec offerings to be set on an outbound SIP channel prior to dialing.
57 <parameter name="media" required="true">
58 <para>types of media offered</para>
62 <para>Returns the codecs offered based upon the media choice</para>
65 <info name="PJSIPCHANNEL" language="en_US" tech="PJSIP">
68 <para>R/O Retrieve media related information.</para>
69 <parameter name="type" required="true">
70 <para>When <replaceable>rtp</replaceable> is specified, the
71 <literal>type</literal> parameter must be provided. It specifies
72 which RTP parameter to read.</para>
75 <para>Retrieve the local address for RTP.</para>
78 <para>Retrieve the remote address for RTP.</para>
81 <para>If direct media is enabled, this address is the remote address
85 <para>Whether or not the media stream is encrypted.</para>
88 <para>The media stream is not encrypted.</para>
91 <para>The media stream is encrypted.</para>
96 <para>Whether or not the media stream is currently restricted
97 due to a call hold.</para>
100 <para>The media stream is not held.</para>
103 <para>The media stream is held.</para>
109 <parameter name="media_type" required="false">
110 <para>When <replaceable>rtp</replaceable> is specified, the
111 <literal>media_type</literal> parameter may be provided. It specifies
112 which media stream the chosen RTP parameter should be retrieved
116 <para>Retrieve information from the audio media stream.</para>
117 <note><para>If not specified, <literal>audio</literal> is used
118 by default.</para></note>
121 <para>Retrieve information from the video media stream.</para>
127 <para>R/O Retrieve RTCP statistics.</para>
128 <parameter name="statistic" required="true">
129 <para>When <replaceable>rtcp</replaceable> is specified, the
130 <literal>statistic</literal> parameter must be provided. It specifies
131 which RTCP statistic parameter to read.</para>
134 <para>Retrieve a summary of all RTCP statistics.</para>
135 <para>The following data items are returned in a semi-colon
136 delineated list:</para>
139 <para>Our Synchronization Source identifier</para>
141 <enum name="themssrc">
142 <para>Their Synchronization Source identifier</para>
145 <para>Our lost packet count</para>
147 <enum name="rxjitter">
148 <para>Received packet jitter</para>
150 <enum name="rxcount">
151 <para>Received packet count</para>
153 <enum name="txjitter">
154 <para>Transmitted packet jitter</para>
156 <enum name="txcount">
157 <para>Transmitted packet count</para>
160 <para>Remote lost packet count</para>
163 <para>Round trip time</para>
167 <enum name="all_jitter">
168 <para>Retrieve a summary of all RTCP Jitter statistics.</para>
169 <para>The following data items are returned in a semi-colon
170 delineated list:</para>
172 <enum name="minrxjitter">
173 <para>Our minimum jitter</para>
175 <enum name="maxrxjitter">
176 <para>Our max jitter</para>
178 <enum name="avgrxjitter">
179 <para>Our average jitter</para>
181 <enum name="stdevrxjitter">
182 <para>Our jitter standard deviation</para>
184 <enum name="reported_minjitter">
185 <para>Their minimum jitter</para>
187 <enum name="reported_maxjitter">
188 <para>Their max jitter</para>
190 <enum name="reported_avgjitter">
191 <para>Their average jitter</para>
193 <enum name="reported_stdevjitter">
194 <para>Their jitter standard deviation</para>
198 <enum name="all_loss">
199 <para>Retrieve a summary of all RTCP packet loss statistics.</para>
200 <para>The following data items are returned in a semi-colon
201 delineated list:</para>
203 <enum name="minrxlost">
204 <para>Our minimum lost packets</para>
206 <enum name="maxrxlost">
207 <para>Our max lost packets</para>
209 <enum name="avgrxlost">
210 <para>Our average lost packets</para>
212 <enum name="stdevrxlost">
213 <para>Our lost packets standard deviation</para>
215 <enum name="reported_minlost">
216 <para>Their minimum lost packets</para>
218 <enum name="reported_maxlost">
219 <para>Their max lost packets</para>
221 <enum name="reported_avglost">
222 <para>Their average lost packets</para>
224 <enum name="reported_stdevlost">
225 <para>Their lost packets standard deviation</para>
229 <enum name="all_rtt">
230 <para>Retrieve a summary of all RTCP round trip time information.</para>
231 <para>The following data items are returned in a semi-colon
232 delineated list:</para>
235 <para>Minimum round trip time</para>
238 <para>Maximum round trip time</para>
241 <para>Average round trip time</para>
243 <enum name="stdevrtt">
244 <para>Standard deviation round trip time</para>
248 <enum name="txcount"><para>Transmitted packet count</para></enum>
249 <enum name="rxcount"><para>Received packet count</para></enum>
250 <enum name="txjitter"><para>Transmitted packet jitter</para></enum>
251 <enum name="rxjitter"><para>Received packet jitter</para></enum>
252 <enum name="remote_maxjitter"><para>Their max jitter</para></enum>
253 <enum name="remote_minjitter"><para>Their minimum jitter</para></enum>
254 <enum name="remote_normdevjitter"><para>Their average jitter</para></enum>
255 <enum name="remote_stdevjitter"><para>Their jitter standard deviation</para></enum>
256 <enum name="local_maxjitter"><para>Our max jitter</para></enum>
257 <enum name="local_minjitter"><para>Our minimum jitter</para></enum>
258 <enum name="local_normdevjitter"><para>Our average jitter</para></enum>
259 <enum name="local_stdevjitter"><para>Our jitter standard deviation</para></enum>
260 <enum name="txploss"><para>Transmitted packet loss</para></enum>
261 <enum name="rxploss"><para>Received packet loss</para></enum>
262 <enum name="remote_maxrxploss"><para>Their max lost packets</para></enum>
263 <enum name="remote_minrxploss"><para>Their minimum lost packets</para></enum>
264 <enum name="remote_normdevrxploss"><para>Their average lost packets</para></enum>
265 <enum name="remote_stdevrxploss"><para>Their lost packets standard deviation</para></enum>
266 <enum name="local_maxrxploss"><para>Our max lost packets</para></enum>
267 <enum name="local_minrxploss"><para>Our minimum lost packets</para></enum>
268 <enum name="local_normdevrxploss"><para>Our average lost packets</para></enum>
269 <enum name="local_stdevrxploss"><para>Our lost packets standard deviation</para></enum>
270 <enum name="rtt"><para>Round trip time</para></enum>
271 <enum name="maxrtt"><para>Maximum round trip time</para></enum>
272 <enum name="minrtt"><para>Minimum round trip time</para></enum>
273 <enum name="normdevrtt"><para>Average round trip time</para></enum>
274 <enum name="stdevrtt"><para>Standard deviation round trip time</para></enum>
275 <enum name="local_ssrc"><para>Our Synchronization Source identifier</para></enum>
276 <enum name="remote_ssrc"><para>Their Synchronization Source identifier</para></enum>
279 <parameter name="media_type" required="false">
280 <para>When <replaceable>rtcp</replaceable> is specified, the
281 <literal>media_type</literal> parameter may be provided. It specifies
282 which media stream the chosen RTCP parameter should be retrieved
286 <para>Retrieve information from the audio media stream.</para>
287 <note><para>If not specified, <literal>audio</literal> is used
288 by default.</para></note>
291 <para>Retrieve information from the video media stream.</para>
296 <enum name="endpoint">
297 <para>R/O The name of the endpoint associated with this channel.
298 Use the <replaceable>PJSIP_ENDPOINT</replaceable> function to obtain
299 further endpoint related information.</para>
302 <para>R/O Obtain information about the current PJSIP channel and its
304 <parameter name="type" required="true">
305 <para>When <replaceable>pjsip</replaceable> is specified, the
306 <literal>type</literal> parameter must be provided. It specifies
307 which signalling parameter to read.</para>
310 <para>Whether or not the signalling uses a secure transport.</para>
312 <enum name="0"><para>The signalling uses a non-secure transport.</para></enum>
313 <enum name="1"><para>The signalling uses a secure transport.</para></enum>
316 <enum name="target_uri">
317 <para>The request URI of the <literal>INVITE</literal> request associated with the creation of this channel.</para>
319 <enum name="local_uri">
320 <para>The local URI.</para>
322 <enum name="remote_uri">
323 <para>The remote URI.</para>
325 <enum name="t38state">
326 <para>The current state of any T.38 fax on this channel.</para>
328 <enum name="DISABLED"><para>T.38 faxing is disabled on this channel.</para></enum>
329 <enum name="LOCAL_REINVITE"><para>Asterisk has sent a <literal>re-INVITE</literal> to the remote end to initiate a T.38 fax.</para></enum>
330 <enum name="REMOTE_REINVITE"><para>The remote end has sent a <literal>re-INVITE</literal> to Asterisk to initiate a T.38 fax.</para></enum>
331 <enum name="ENABLED"><para>A T.38 fax session has been enabled.</para></enum>
332 <enum name="REJECTED"><para>A T.38 fax session was attempted but was rejected.</para></enum>
335 <enum name="local_addr">
336 <para>On inbound calls, the full IP address and port number that
337 the <literal>INVITE</literal> request was received on. On outbound
338 calls, the full IP address and port number that the <literal>INVITE</literal>
339 request was transmitted from.</para>
341 <enum name="remote_addr">
342 <para>On inbound calls, the full IP address and port number that
343 the <literal>INVITE</literal> request was received from. On outbound
344 calls, the full IP address and port number that the <literal>INVITE</literal>
345 request was transmitted to.</para>
354 #include "asterisk.h"
358 #include <pjsip_ua.h>
360 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
362 #include "asterisk/astobj2.h"
363 #include "asterisk/module.h"
364 #include "asterisk/acl.h"
365 #include "asterisk/app.h"
366 #include "asterisk/channel.h"
367 #include "asterisk/format.h"
368 #include "asterisk/pbx.h"
369 #include "asterisk/res_pjsip.h"
370 #include "asterisk/res_pjsip_session.h"
371 #include "include/chan_pjsip.h"
372 #include "include/dialplan_functions.h"
375 * \brief String representations of the T.38 state enum
377 static const char *t38state_to_string[T38_MAX_ENUM] = {
378 [T38_DISABLED] = "DISABLED",
379 [T38_LOCAL_REINVITE] = "LOCAL_REINVITE",
380 [T38_PEER_REINVITE] = "REMOTE_REINVITE",
381 [T38_ENABLED] = "ENABLED",
382 [T38_REJECTED] = "REJECTED",
386 * \internal \brief Handle reading RTP information
388 static int channel_read_rtp(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen)
390 struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
391 struct chan_pjsip_pvt *pvt;
392 struct ast_sip_session_media *media = NULL;
393 struct ast_sockaddr addr;
396 ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
402 ast_log(AST_LOG_WARNING, "Channel %s has no chan_pjsip pvt!\n", ast_channel_name(chan));
406 if (ast_strlen_zero(type)) {
407 ast_log(AST_LOG_WARNING, "You must supply a type field for 'rtp' information\n");
411 if (ast_strlen_zero(field) || !strcmp(field, "audio")) {
412 media = pvt->media[SIP_MEDIA_AUDIO];
413 } else if (!strcmp(field, "video")) {
414 media = pvt->media[SIP_MEDIA_VIDEO];
416 ast_log(AST_LOG_WARNING, "Unknown media type field '%s' for 'rtp' information\n", field);
420 if (!media || !media->rtp) {
421 ast_log(AST_LOG_WARNING, "Channel %s has no %s media/RTP session\n",
422 ast_channel_name(chan), S_OR(field, "audio"));
426 if (!strcmp(type, "src")) {
427 ast_rtp_instance_get_local_address(media->rtp, &addr);
428 ast_copy_string(buf, ast_sockaddr_stringify(&addr), buflen);
429 } else if (!strcmp(type, "dest")) {
430 ast_rtp_instance_get_remote_address(media->rtp, &addr);
431 ast_copy_string(buf, ast_sockaddr_stringify(&addr), buflen);
432 } else if (!strcmp(type, "direct")) {
433 ast_copy_string(buf, ast_sockaddr_stringify(&media->direct_media_addr), buflen);
434 } else if (!strcmp(type, "secure")) {
435 snprintf(buf, buflen, "%u", media->srtp ? 1 : 0);
436 } else if (!strcmp(type, "hold")) {
437 snprintf(buf, buflen, "%u", media->held ? 1 : 0);
439 ast_log(AST_LOG_WARNING, "Unknown type field '%s' specified for 'rtp' information\n", type);
447 * \internal \brief Handle reading RTCP information
449 static int channel_read_rtcp(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen)
451 struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
452 struct chan_pjsip_pvt *pvt;
453 struct ast_sip_session_media *media = NULL;
456 ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
462 ast_log(AST_LOG_WARNING, "Channel %s has no chan_pjsip pvt!\n", ast_channel_name(chan));
466 if (ast_strlen_zero(type)) {
467 ast_log(AST_LOG_WARNING, "You must supply a type field for 'rtcp' information\n");
471 if (ast_strlen_zero(field) || !strcmp(field, "audio")) {
472 media = pvt->media[SIP_MEDIA_AUDIO];
473 } else if (!strcmp(field, "video")) {
474 media = pvt->media[SIP_MEDIA_VIDEO];
476 ast_log(AST_LOG_WARNING, "Unknown media type field '%s' for 'rtcp' information\n", field);
480 if (!media || !media->rtp) {
481 ast_log(AST_LOG_WARNING, "Channel %s has no %s media/RTP session\n",
482 ast_channel_name(chan), S_OR(field, "audio"));
486 if (!strncasecmp(type, "all", 3)) {
487 enum ast_rtp_instance_stat_field stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY;
489 if (!strcasecmp(type, "all_jitter")) {
490 stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER;
491 } else if (!strcasecmp(type, "all_rtt")) {
492 stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT;
493 } else if (!strcasecmp(type, "all_loss")) {
494 stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS;
497 if (!ast_rtp_instance_get_quality(media->rtp, stat_field, buf, buflen)) {
498 ast_log(AST_LOG_WARNING, "Unable to retrieve 'rtcp' statistics for %s\n", ast_channel_name(chan));
502 struct ast_rtp_instance_stats stats;
506 enum { INT, DBL } type;
512 { "txcount", INT, { .i4 = &stats.txcount, }, },
513 { "rxcount", INT, { .i4 = &stats.rxcount, }, },
514 { "txjitter", DBL, { .d8 = &stats.txjitter, }, },
515 { "rxjitter", DBL, { .d8 = &stats.rxjitter, }, },
516 { "remote_maxjitter", DBL, { .d8 = &stats.remote_maxjitter, }, },
517 { "remote_minjitter", DBL, { .d8 = &stats.remote_minjitter, }, },
518 { "remote_normdevjitter", DBL, { .d8 = &stats.remote_normdevjitter, }, },
519 { "remote_stdevjitter", DBL, { .d8 = &stats.remote_stdevjitter, }, },
520 { "local_maxjitter", DBL, { .d8 = &stats.local_maxjitter, }, },
521 { "local_minjitter", DBL, { .d8 = &stats.local_minjitter, }, },
522 { "local_normdevjitter", DBL, { .d8 = &stats.local_normdevjitter, }, },
523 { "local_stdevjitter", DBL, { .d8 = &stats.local_stdevjitter, }, },
524 { "txploss", INT, { .i4 = &stats.txploss, }, },
525 { "rxploss", INT, { .i4 = &stats.rxploss, }, },
526 { "remote_maxrxploss", DBL, { .d8 = &stats.remote_maxrxploss, }, },
527 { "remote_minrxploss", DBL, { .d8 = &stats.remote_minrxploss, }, },
528 { "remote_normdevrxploss", DBL, { .d8 = &stats.remote_normdevrxploss, }, },
529 { "remote_stdevrxploss", DBL, { .d8 = &stats.remote_stdevrxploss, }, },
530 { "local_maxrxploss", DBL, { .d8 = &stats.local_maxrxploss, }, },
531 { "local_minrxploss", DBL, { .d8 = &stats.local_minrxploss, }, },
532 { "local_normdevrxploss", DBL, { .d8 = &stats.local_normdevrxploss, }, },
533 { "local_stdevrxploss", DBL, { .d8 = &stats.local_stdevrxploss, }, },
534 { "rtt", DBL, { .d8 = &stats.rtt, }, },
535 { "maxrtt", DBL, { .d8 = &stats.maxrtt, }, },
536 { "minrtt", DBL, { .d8 = &stats.minrtt, }, },
537 { "normdevrtt", DBL, { .d8 = &stats.normdevrtt, }, },
538 { "stdevrtt", DBL, { .d8 = &stats.stdevrtt, }, },
539 { "local_ssrc", INT, { .i4 = &stats.local_ssrc, }, },
540 { "remote_ssrc", INT, { .i4 = &stats.remote_ssrc, }, },
544 if (ast_rtp_instance_get_stats(media->rtp, &stats, AST_RTP_INSTANCE_STAT_ALL)) {
545 ast_log(AST_LOG_WARNING, "Unable to retrieve 'rtcp' statistics for %s\n", ast_channel_name(chan));
549 for (i = 0; !ast_strlen_zero(lookup[i].name); i++) {
550 if (!strcasecmp(type, lookup[i].name)) {
551 if (lookup[i].type == INT) {
552 snprintf(buf, buflen, "%u", *lookup[i].i4);
554 snprintf(buf, buflen, "%f", *lookup[i].d8);
559 ast_log(AST_LOG_WARNING, "Unrecognized argument '%s' for 'rtcp' information\n", type);
567 * \internal \brief Handle reading signalling information
569 static int channel_read_pjsip(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen)
571 struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
576 ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
580 dlg = channel->session->inv_session->dlg;
582 if (!strcmp(type, "secure")) {
583 snprintf(buf, buflen, "%u", dlg->secure ? 1 : 0);
584 } else if (!strcmp(type, "target_uri")) {
585 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, dlg->target, buf, buflen);
586 buf_copy = ast_strdupa(buf);
587 ast_escape_quoted(buf_copy, buf, buflen);
588 } else if (!strcmp(type, "local_uri")) {
589 pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, dlg->local.info->uri, buf, buflen);
590 buf_copy = ast_strdupa(buf);
591 ast_escape_quoted(buf_copy, buf, buflen);
592 } else if (!strcmp(type, "remote_uri")) {
593 pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, dlg->remote.info->uri, buf, buflen);
594 buf_copy = ast_strdupa(buf);
595 ast_escape_quoted(buf_copy, buf, buflen);
596 } else if (!strcmp(type, "t38state")) {
597 ast_copy_string(buf, t38state_to_string[channel->session->t38state], buflen);
598 } else if (!strcmp(type, "local_addr")) {
599 RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
600 struct transport_info_data *transport_data;
602 datastore = ast_sip_session_get_datastore(channel->session, "transport_info");
604 ast_log(AST_LOG_WARNING, "No transport information for channel %s\n", ast_channel_name(chan));
607 transport_data = datastore->data;
609 if (pj_sockaddr_has_addr(&transport_data->local_addr)) {
610 pj_sockaddr_print(&transport_data->local_addr, buf, buflen, 3);
612 } else if (!strcmp(type, "remote_addr")) {
613 RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
614 struct transport_info_data *transport_data;
616 datastore = ast_sip_session_get_datastore(channel->session, "transport_info");
618 ast_log(AST_LOG_WARNING, "No transport information for channel %s\n", ast_channel_name(chan));
621 transport_data = datastore->data;
623 if (pj_sockaddr_has_addr(&transport_data->remote_addr)) {
624 pj_sockaddr_print(&transport_data->remote_addr, buf, buflen, 3);
627 ast_log(AST_LOG_WARNING, "Unrecognized argument '%s' for 'pjsip' information\n", type);
634 /*! \brief Struct used to push function arguments to task processor */
635 struct pjsip_func_args {
636 struct ast_channel *chan;
645 /*! \internal \brief Taskprocessor callback that handles the read on a PJSIP thread */
646 static int read_pjsip(void *data)
648 struct pjsip_func_args *func_args = data;
650 if (!strcmp(func_args->param, "rtp")) {
651 func_args->ret = channel_read_rtp(func_args->chan, func_args->type,
652 func_args->field, func_args->buf,
654 } else if (!strcmp(func_args->param, "rtcp")) {
655 func_args->ret = channel_read_rtcp(func_args->chan, func_args->type,
656 func_args->field, func_args->buf,
658 } else if (!strcmp(func_args->param, "endpoint")) {
659 struct ast_sip_channel_pvt *pvt = ast_channel_tech_pvt(func_args->chan);
662 ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(func_args->chan));
665 if (!pvt->session || !pvt->session->endpoint) {
666 ast_log(AST_LOG_WARNING, "Channel %s has no endpoint!\n", ast_channel_name(func_args->chan));
669 snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(pvt->session->endpoint));
670 } else if (!strcmp(func_args->param, "pjsip")) {
671 func_args->ret = channel_read_pjsip(func_args->chan, func_args->type,
672 func_args->field, func_args->buf,
682 int pjsip_acf_channel_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
684 struct pjsip_func_args func_args = { 0, };
685 struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
686 char *parse = ast_strdupa(data);
688 AST_DECLARE_APP_ARGS(args,
694 /* Check for zero arguments */
695 if (ast_strlen_zero(parse)) {
696 ast_log(LOG_ERROR, "Cannot call %s without arguments\n", cmd);
700 AST_STANDARD_APP_ARGS(args, parse);
703 if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
704 ast_log(LOG_ERROR, "Cannot call %s on a non-PJSIP channel\n", cmd);
709 ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
715 func_args.chan = chan;
716 func_args.param = args.param;
717 func_args.type = args.type;
718 func_args.field = args.field;
721 if (ast_sip_push_task_synchronous(channel->session->serializer, read_pjsip, &func_args)) {
722 ast_log(LOG_WARNING, "Unable to read properties of channel %s: failed to push task\n", ast_channel_name(chan));
726 return func_args.ret;
729 int pjsip_acf_dial_contacts_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
731 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
732 RAII_VAR(struct ast_str *, dial, NULL, ast_free_ptr);
733 const char *aor_name;
736 AST_DECLARE_APP_ARGS(args,
737 AST_APP_ARG(endpoint_name);
738 AST_APP_ARG(aor_name);
739 AST_APP_ARG(request_user);
742 AST_STANDARD_APP_ARGS(args, data);
744 if (ast_strlen_zero(args.endpoint_name)) {
745 ast_log(LOG_WARNING, "An endpoint name must be specified when using the '%s' dialplan function\n", cmd);
747 } else if (!(endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", args.endpoint_name))) {
748 ast_log(LOG_WARNING, "Specified endpoint '%s' was not found\n", args.endpoint_name);
752 aor_name = S_OR(args.aor_name, endpoint->aors);
754 if (ast_strlen_zero(aor_name)) {
755 ast_log(LOG_WARNING, "No AOR has been provided and no AORs are configured on endpoint '%s'\n", args.endpoint_name);
757 } else if (!(dial = ast_str_create(len))) {
758 ast_log(LOG_WARNING, "Could not get enough buffer space for dialing contacts\n");
760 } else if (!(rest = ast_strdupa(aor_name))) {
761 ast_log(LOG_WARNING, "Could not duplicate provided AORs\n");
765 while ((aor_name = strsep(&rest, ","))) {
766 RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup);
767 RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
768 struct ao2_iterator it_contacts;
769 struct ast_sip_contact *contact;
772 /* If the AOR provided is not found skip it, there may be more */
774 } else if (!(contacts = ast_sip_location_retrieve_aor_contacts(aor))) {
775 /* No contacts are available, skip it as well */
777 } else if (!ao2_container_count(contacts)) {
778 /* We were given a container but no contacts are in it... */
782 it_contacts = ao2_iterator_init(contacts, 0);
783 for (; (contact = ao2_iterator_next(&it_contacts)); ao2_ref(contact, -1)) {
784 ast_str_append(&dial, -1, "PJSIP/");
786 if (!ast_strlen_zero(args.request_user)) {
787 ast_str_append(&dial, -1, "%s@", args.request_user);
789 ast_str_append(&dial, -1, "%s/%s&", args.endpoint_name, contact->uri);
791 ao2_iterator_destroy(&it_contacts);
794 /* Trim the '&' at the end off */
795 ast_str_truncate(dial, ast_str_strlen(dial) - 1);
797 ast_copy_string(buf, ast_str_buffer(dial), len);
802 static int media_offer_read_av(struct ast_sip_session *session, char *buf,
803 size_t len, enum ast_format_type media_type)
806 struct ast_format fmt;
809 for (i = 0; ast_codec_pref_index(&session->override_prefs, i, &fmt); ++i) {
810 if (AST_FORMAT_GET_TYPE(fmt.id) != media_type) {
814 name = ast_getformatname(&fmt);
816 if (ast_strlen_zero(name)) {
817 ast_log(LOG_WARNING, "PJSIP_MEDIA_OFFER unrecognized format %s\n", name);
821 /* add one since we'll include a comma */
822 size = strlen(name) + 1;
828 /* no reason to use strncat here since we have already ensured buf has
829 enough space, so strcat can be safely used */
835 /* remove the extra comma */
836 buf[strlen(buf) - 1] = '\0';
841 struct media_offer_data {
842 struct ast_sip_session *session;
843 enum ast_format_type media_type;
847 static int media_offer_write_av(void *obj)
849 struct media_offer_data *data = obj;
851 struct ast_format fmt;
852 /* remove all of the given media type first */
853 for (i = 0; ast_codec_pref_index(&data->session->override_prefs, i, &fmt); ++i) {
854 if (AST_FORMAT_GET_TYPE(fmt.id) == data->media_type) {
855 ast_codec_pref_remove(&data->session->override_prefs, &fmt);
858 ast_format_cap_remove_bytype(data->session->req_caps, data->media_type);
859 ast_parse_allow_disallow(&data->session->override_prefs, data->session->req_caps, data->value, 1);
864 int pjsip_acf_media_offer_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
866 struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
868 if (!strcmp(data, "audio")) {
869 return media_offer_read_av(channel->session, buf, len, AST_FORMAT_TYPE_AUDIO);
870 } else if (!strcmp(data, "video")) {
871 return media_offer_read_av(channel->session, buf, len, AST_FORMAT_TYPE_VIDEO);
877 int pjsip_acf_media_offer_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
879 struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
881 struct media_offer_data mdata = {
882 .session = channel->session,
886 if (!strcmp(data, "audio")) {
887 mdata.media_type = AST_FORMAT_TYPE_AUDIO;
888 } else if (!strcmp(data, "video")) {
889 mdata.media_type = AST_FORMAT_TYPE_VIDEO;
892 return ast_sip_push_task_synchronous(channel->session->serializer, media_offer_write_av, &mdata);