Asterisk - The Open Source Telephony Project GIT-master-57e2743
Loading...
Searching...
No Matches
dialplan_functions.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 * 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.
11 *
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.
15 */
16
17/*!
18 * \file
19 *
20 * \author \verbatim Joshua Colp <jcolp@digium.com> \endverbatim
21 * \author \verbatim Matt Jordan <mjordan@digium.com> \endverbatim
22 *
23 * \ingroup functions
24 *
25 * \brief PJSIP channel dialplan functions
26 */
27
28/*** MODULEINFO
29 <support_level>core</support_level>
30 ***/
31
32#include "asterisk.h"
33
34#include <pjsip.h>
35#include <pjlib.h>
36#include <pjsip_ua.h>
37
38#include "asterisk/astobj2.h"
39#include "asterisk/module.h"
40#include "asterisk/acl.h"
41#include "asterisk/app.h"
43#include "asterisk/channel.h"
44#include "asterisk/stream.h"
45#include "asterisk/format.h"
46#include "asterisk/dsp.h"
47#include "asterisk/pbx.h"
48#include "asterisk/res_pjsip.h"
50#include "include/chan_pjsip.h"
53
54/*!
55 * \brief String representations of the T.38 state enum
56 */
57static const char *t38state_to_string[T38_MAX_ENUM] = {
58 [T38_DISABLED] = "DISABLED",
59 [T38_LOCAL_REINVITE] = "LOCAL_REINVITE",
60 [T38_PEER_REINVITE] = "REMOTE_REINVITE",
61 [T38_ENABLED] = "ENABLED",
62 [T38_REJECTED] = "REJECTED",
63};
64
65/*!
66 * \internal \brief Escape a captured URI into the dialplan result buffer
67 */
68static int copy_escaped_uri(struct ast_channel *chan, const char *type,
69 const struct pjsip_channel_uri *uri, char *buf, size_t size)
70{
71 if (uri->length < 0 || uri->length >= size) {
72 ast_log(LOG_ERROR, "Channel %s: Unescaped %s too long for %zu byte buffer\n",
73 ast_channel_name(chan), type, size);
74 buf[0] = '\0';
75 return -1;
76 }
77 ast_escape_quoted(uri->value, buf, size);
78 return 0;
79}
80
81/*!
82 * \internal \brief Handle reading RTP information
83 */
84static int channel_read_rtp(struct ast_channel *chan, struct ast_rtp_instance *rtp,
85 const struct ast_sockaddr *direct_media_addr, unsigned int secure,
86 unsigned int held, const char *type, const char *field, char *buf, size_t buflen)
87{
88 struct ast_sockaddr addr;
89
90 if (ast_strlen_zero(type)) {
91 ast_log(AST_LOG_WARNING, "You must supply a type field for 'rtp' information\n");
92 return -1;
93 }
94
95 if (!ast_strlen_zero(field) && strcmp(field, "audio") && strcmp(field, "video")) {
96 ast_log(AST_LOG_WARNING, "Unknown media type field '%s' for 'rtp' information\n", field);
97 return -1;
98 }
99
100 if (!rtp) {
101 ast_log(AST_LOG_WARNING, "Channel %s has no %s media/RTP session\n",
102 ast_channel_name(chan), S_OR(field, "audio"));
103 return -1;
104 }
105
106 if (!strcmp(type, "src")) {
109 } else if (!strcmp(type, "dest")) {
112 } else if (!strcmp(type, "direct")) {
113 ast_copy_string(buf, ast_sockaddr_stringify(direct_media_addr), buflen);
114 } else if (!strcmp(type, "secure")) {
115 snprintf(buf, buflen, "%u", secure);
116 } else if (!strcmp(type, "hold")) {
117 snprintf(buf, buflen, "%u", held);
118 } else {
119 ast_log(AST_LOG_WARNING, "Unknown type field '%s' specified for 'rtp' information\n", type);
120 return -1;
121 }
122
123 return 0;
124}
125
126/*!
127 * \internal \brief Handle reading RTCP information
128 */
129static int channel_read_rtcp(struct ast_channel *chan, struct ast_rtp_instance *rtp,
130 const char *type, const char *field, char *buf, size_t buflen)
131{
132 if (ast_strlen_zero(type)) {
133 ast_log(AST_LOG_WARNING, "You must supply a type field for 'rtcp' information\n");
134 return -1;
135 }
136
137 if (!ast_strlen_zero(field) && strcmp(field, "audio") && strcmp(field, "video")) {
138 ast_log(AST_LOG_WARNING, "Unknown media type field '%s' for 'rtcp' information\n", field);
139 return -1;
140 }
141
142 if (!rtp) {
143 ast_log(AST_LOG_WARNING, "Channel %s has no %s media/RTP session\n",
144 ast_channel_name(chan), S_OR(field, "audio"));
145 return -1;
146 }
147
148 if (!strncasecmp(type, "all", 3)) {
150
151 if (!strcasecmp(type, "all_jitter")) {
153 } else if (!strcasecmp(type, "all_rtt")) {
155 } else if (!strcasecmp(type, "all_loss")) {
157 } else if (!strcasecmp(type, "all_mes")) {
159 }
160
161 if (!ast_rtp_instance_get_quality(rtp, stat_field, buf, buflen)) {
162 ast_log(AST_LOG_WARNING, "Unable to retrieve 'rtcp' statistics for %s\n", ast_channel_name(chan));
163 return -1;
164 }
165 } else {
166 struct ast_rtp_instance_stats stats;
167 int i;
168 struct {
169 const char *name;
170 enum { INT, DBL } type;
171 union {
172 unsigned int *i4;
173 double *d8;
174 };
175 } lookup[] = {
176 { "txcount", INT, { .i4 = &stats.txcount, }, },
177 { "rxcount", INT, { .i4 = &stats.rxcount, }, },
178 { "txjitter", DBL, { .d8 = &stats.txjitter, }, },
179 { "rxjitter", DBL, { .d8 = &stats.rxjitter, }, },
180 { "remote_maxjitter", DBL, { .d8 = &stats.remote_maxjitter, }, },
181 { "remote_minjitter", DBL, { .d8 = &stats.remote_minjitter, }, },
182 { "remote_normdevjitter", DBL, { .d8 = &stats.remote_normdevjitter, }, },
183 { "remote_stdevjitter", DBL, { .d8 = &stats.remote_stdevjitter, }, },
184 { "local_maxjitter", DBL, { .d8 = &stats.local_maxjitter, }, },
185 { "local_minjitter", DBL, { .d8 = &stats.local_minjitter, }, },
186 { "local_normdevjitter", DBL, { .d8 = &stats.local_normdevjitter, }, },
187 { "local_stdevjitter", DBL, { .d8 = &stats.local_stdevjitter, }, },
188 { "txploss", INT, { .i4 = &stats.txploss, }, },
189 { "rxploss", INT, { .i4 = &stats.rxploss, }, },
190 { "remote_maxrxploss", DBL, { .d8 = &stats.remote_maxrxploss, }, },
191 { "remote_minrxploss", DBL, { .d8 = &stats.remote_minrxploss, }, },
192 { "remote_normdevrxploss", DBL, { .d8 = &stats.remote_normdevrxploss, }, },
193 { "remote_stdevrxploss", DBL, { .d8 = &stats.remote_stdevrxploss, }, },
194 { "local_maxrxploss", DBL, { .d8 = &stats.local_maxrxploss, }, },
195 { "local_minrxploss", DBL, { .d8 = &stats.local_minrxploss, }, },
196 { "local_normdevrxploss", DBL, { .d8 = &stats.local_normdevrxploss, }, },
197 { "local_stdevrxploss", DBL, { .d8 = &stats.local_stdevrxploss, }, },
198 { "rtt", DBL, { .d8 = &stats.rtt, }, },
199 { "maxrtt", DBL, { .d8 = &stats.maxrtt, }, },
200 { "minrtt", DBL, { .d8 = &stats.minrtt, }, },
201 { "normdevrtt", DBL, { .d8 = &stats.normdevrtt, }, },
202 { "stdevrtt", DBL, { .d8 = &stats.stdevrtt, }, },
203 { "local_ssrc", INT, { .i4 = &stats.local_ssrc, }, },
204 { "remote_ssrc", INT, { .i4 = &stats.remote_ssrc, }, },
205 { "txmes", DBL, { .d8 = &stats.txmes, }, },
206 { "rxmes", DBL, { .d8 = &stats.rxmes, }, },
207 { "remote_maxmes", DBL, { .d8 = &stats.remote_maxmes, }, },
208 { "remote_minmes", DBL, { .d8 = &stats.remote_minmes, }, },
209 { "remote_normdevmes", DBL, { .d8 = &stats.remote_normdevmes, }, },
210 { "remote_stdevmes", DBL, { .d8 = &stats.remote_stdevmes, }, },
211 { "local_maxmes", DBL, { .d8 = &stats.local_maxmes, }, },
212 { "local_minmes", DBL, { .d8 = &stats.local_minmes, }, },
213 { "local_normdevmes", DBL, { .d8 = &stats.local_normdevmes, }, },
214 { "local_stdevmes", DBL, { .d8 = &stats.local_stdevmes, }, },
215 { NULL, },
216 };
217
219 ast_log(AST_LOG_WARNING, "Unable to retrieve 'rtcp' statistics for %s\n", ast_channel_name(chan));
220 return -1;
221 }
222
223 for (i = 0; !ast_strlen_zero(lookup[i].name); i++) {
224 if (!strcasecmp(type, lookup[i].name)) {
225 if (lookup[i].type == INT) {
226 snprintf(buf, buflen, "%u", *lookup[i].i4);
227 } else {
228 snprintf(buf, buflen, "%f", *lookup[i].d8);
229 }
230 return 0;
231 }
232 }
233 ast_log(AST_LOG_WARNING, "Unrecognized argument '%s' for 'rtcp' information\n", type);
234 return -1;
235 }
236
237 return 0;
238}
239
240/* The original Request-URI is cloned before channel creation and never changed. */
241static int read_request_uri(struct ast_channel *chan, struct ast_sip_session *session,
242 char *buf, size_t size)
243{
244 int length;
245 char *copy;
246
247 if (!session->request_uri) {
248 return 0;
249 }
250 length = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, session->request_uri, buf, size);
251 if (length < 0 || length >= size) {
252 ast_log(LOG_ERROR, "Channel %s: Request URI too long for %zu byte buffer\n",
253 ast_channel_name(chan), size);
254 buf[0] = '\0';
255 return -1;
256 }
257 buf[length] = '\0';
259 ast_escape_quoted(copy, buf, size);
260 return 0;
261}
262
263/* The caller holds the channel lock. No dialog lock or serializer wait is allowed. */
264static int channel_read_pjsip(struct ast_channel *chan, struct ast_sip_session *session,
265 const char *type, char *buf, size_t len)
266{
267 const struct pjsip_channel_info *info;
268
269 if (ast_strlen_zero(type)) {
270 ast_log(LOG_WARNING, "You must supply a type field for 'pjsip' information\n");
271 return -1;
272 }
273
274 if (!strcmp(type, "call-id") || !strcmp(type, "local_tag")) {
275 pjsip_dialog *dlg = session->inv_session ? session->inv_session->dlg : NULL;
276
277 if (!dlg) {
278 return -1;
279 }
280 /* These identities are fixed for the lifetime of the retained dialog. */
281 if (!strcmp(type, "call-id")) {
282 ast_copy_pj_str(buf, &dlg->call_id->id, len);
283 } else {
284 char *copy;
285
286 ast_copy_pj_str(buf, &dlg->local.info->tag, len);
289 }
290 return 0;
291 }
292 if (!strcmp(type, "request_uri")) {
293 return read_request_uri(chan, session, buf, len);
294 }
295 if (!strcmp(type, "t38state")) {
296 if (session->t38state < 0 || session->t38state >= T38_MAX_ENUM) {
297 return -1;
298 }
300 return 0;
301 }
302 if (!strcmp(type, "local_addr") || !strcmp(type, "remote_addr")) {
305 struct transport_info_data *transport;
306 const pj_sockaddr *addr;
307
308 if (!datastore) {
309 ast_log(LOG_WARNING, "No transport information for channel %s\n",
310 ast_channel_name(chan));
311 return -1;
312 }
313 /* The transport payload is fully initialized before publication and immutable. */
314 transport = datastore->data;
315 addr = !strcmp(type, "local_addr") ? &transport->local_addr : &transport->remote_addr;
316 if (pj_sockaddr_has_addr(addr)) {
317 pj_sockaddr_print(addr, buf, len, 3);
318 }
319 return 0;
320 }
321
322 info = pjsip_channel_info_get(chan);
323 if (!info) {
324 ast_log(LOG_WARNING, "Channel %s has no PJSIP channel information\n",
325 ast_channel_name(chan));
326 return -1;
327 }
328 if (!strcmp(type, "secure")) {
329#ifdef HAVE_PJSIP_GET_DEST_INFO
330 if (info->secure < 0) {
331 return -1;
332 }
333 snprintf(buf, len, "%d", info->secure);
334#else
335 ast_log(LOG_WARNING, "Asterisk was built without support for CHANNEL(pjsip,secure)\n");
336 return -1;
337#endif
338 } else if (!strcmp(type, "target_uri")) {
339 return copy_escaped_uri(chan, type, &info->target_uri, buf, len);
340 } else if (!strcmp(type, "local_uri")) {
341 return copy_escaped_uri(chan, type, &info->local_uri, buf, len);
342 } else if (!strcmp(type, "remote_uri")) {
343 return copy_escaped_uri(chan, type, &info->remote_uri, buf, len);
344 } else if (!strcmp(type, "remote_tag")) {
345 if (!info->remote_tag) {
346 return -1;
347 }
348 ast_escape_quoted(info->remote_tag, buf, len);
349 } else {
350 ast_log(LOG_WARNING, "Unrecognized argument '%s' for 'pjsip' information\n", type);
351 return -1;
352 }
353 return 0;
354}
355
356int pjsip_acf_channel_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
357{
358 struct ast_sip_channel_pvt *channel;
359 char *parse = ast_strdupa(data);
360 int res = 0;
361
363 AST_APP_ARG(param);
365 AST_APP_ARG(field);
366 );
367
368 if (!chan) {
369 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
370 return -1;
371 }
372
373 /* Check for zero arguments */
374 if (ast_strlen_zero(parse)) {
375 ast_log(LOG_ERROR, "Cannot call %s without arguments\n", cmd);
376 return -1;
377 }
378
379 if (!len) {
380 ast_log(LOG_ERROR, "Cannot call %s without an output buffer\n", cmd);
381 return -1;
382 }
383
385
386 ast_channel_lock(chan);
387
388 /* Sanity check */
389 if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
390 ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
391 ast_channel_unlock(chan);
392 return 0;
393 }
394
395 channel = ast_channel_tech_pvt(chan);
396 if (!channel) {
397 ast_log(LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
398 ast_channel_unlock(chan);
399 return -1;
400 }
401
402 if (!channel->session) {
403 ast_log(LOG_WARNING, "Channel %s has no session\n", ast_channel_name(chan));
404 ast_channel_unlock(chan);
405 return -1;
406 }
407
408 memset(buf, 0, len);
409
410 if (!strcmp(args.param, "endpoint")) {
411 if (!channel->session->endpoint) {
412 res = -1;
413 } else {
415 }
416 } else if (!strcmp(args.param, "contact")) {
417 if (channel->session->contact) {
419 }
420 } else if (!strcmp(args.param, "aor")) {
421 if (channel->session->aor) {
423 }
424 } else if (!strcmp(args.param, "pjsip")) {
425 res = channel_read_pjsip(chan, channel->session, args.type, buf, len);
426 } else if (!strcmp(args.param, "rtp") || !strcmp(args.param, "rtcp")) {
427 const struct pjsip_channel_info *info = pjsip_channel_info_get(chan);
428 struct ast_rtp_instance *rtp;
429 struct ast_sip_session_media *media;
430 struct ast_sockaddr no_address = { { 0, } };
431 const struct ast_sockaddr *direct_media_addr;
432 unsigned int secure;
433 unsigned int held;
434 int video = !strcmp(S_OR(args.field, "audio"), "video");
435
436 if (!info) {
437 res = -1;
438 } else {
439 /* The channel lock keeps these retained instances alive throughout the read. */
440 rtp = video ? info->video_rtp : info->audio_rtp;
441 media = channel->session->active_media_state
444 direct_media_addr = media ? &media->direct_media_addr : &no_address;
445 secure = video ? info->video_secure : info->audio_secure;
446 held = video ? info->video_held : info->audio_held;
447 if (!strcmp(args.param, "rtp")) {
448 res = channel_read_rtp(chan, rtp, direct_media_addr, secure, held,
449 args.type, args.field, buf, len);
450 } else {
451 res = channel_read_rtcp(chan, rtp, args.type, args.field, buf, len);
452 }
453 }
454 } else {
455 res = -1;
456 }
457 ast_channel_unlock(chan);
458 return res;
459}
460
461int pjsip_acf_dial_contacts_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
462{
463 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
464 RAII_VAR(struct ast_str *, dial, NULL, ast_free_ptr);
465 const char *aor_name;
466 char *rest;
467
469 AST_APP_ARG(endpoint_name);
470 AST_APP_ARG(aor_name);
471 AST_APP_ARG(request_user);
472 );
473
475
476 if (ast_strlen_zero(args.endpoint_name)) {
477 ast_log(LOG_WARNING, "An endpoint name must be specified when using the '%s' dialplan function\n", cmd);
478 return -1;
479 } else if (!(endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", args.endpoint_name))) {
480 ast_log(LOG_WARNING, "Specified endpoint '%s' was not found\n", args.endpoint_name);
481 return -1;
482 }
483
484 aor_name = S_OR(args.aor_name, endpoint->aors);
485
486 if (ast_strlen_zero(aor_name)) {
487 ast_log(LOG_WARNING, "No AOR has been provided and no AORs are configured on endpoint '%s'\n", args.endpoint_name);
488 return -1;
489 } else if (!(dial = ast_str_create(len))) {
490 ast_log(LOG_WARNING, "Could not get enough buffer space for dialing contacts\n");
491 return -1;
492 } else if (!(rest = ast_strdupa(aor_name))) {
493 ast_log(LOG_WARNING, "Could not duplicate provided AORs\n");
494 return -1;
495 }
496
497 while ((aor_name = ast_strip(strsep(&rest, ",")))) {
499 RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
500 struct ao2_iterator it_contacts;
501 struct ast_sip_contact *contact;
502
503 if (!aor) {
504 /* If the AOR provided is not found skip it, there may be more */
505 continue;
507 /* No contacts are available, skip it as well */
508 continue;
509 } else if (!ao2_container_count(contacts)) {
510 /* We were given a container but no contacts are in it... */
511 continue;
512 }
513
514 it_contacts = ao2_iterator_init(contacts, 0);
515 for (; (contact = ao2_iterator_next(&it_contacts)); ao2_ref(contact, -1)) {
516 ast_str_append(&dial, -1, "PJSIP/");
517
518 if (!ast_strlen_zero(args.request_user)) {
519 ast_str_append(&dial, -1, "%s@", args.request_user);
520 }
521 ast_str_append(&dial, -1, "%s/%s&", args.endpoint_name, contact->uri);
522 }
523 ao2_iterator_destroy(&it_contacts);
524 }
525
526 /* Trim the '&' at the end off */
527 ast_str_truncate(dial, ast_str_strlen(dial) - 1);
528
530
531 return 0;
532}
533
534/*! \brief Session refresh state information */
536 /*! \brief Created proposed media state */
538};
539
540/*! \brief Destructor for session refresh information */
541static void session_refresh_state_destroy(void *obj)
542{
543 struct session_refresh_state *state = obj;
544
546 ast_free(obj);
547}
548
549/*! \brief Datastore for attaching session refresh state information */
551 .type = "pjsip_session_refresh",
553};
554
555/*! \brief Helper function which retrieves or allocates a session refresh state information datastore */
557{
558 RAII_VAR(struct ast_datastore *, datastore, ast_sip_session_get_datastore(session, "pjsip_session_refresh"), ao2_cleanup);
560
561 /* While the datastore refcount is decremented this is operating in the serializer so it will remain valid regardless */
562 if (datastore) {
563 return datastore->data;
564 }
565
566 if (!(datastore = ast_sip_session_alloc_datastore(&session_refresh_datastore, "pjsip_session_refresh"))
567 || !(datastore->data = ast_calloc(1, sizeof(struct session_refresh_state)))
568 || ast_sip_session_add_datastore(session, datastore)) {
569 return NULL;
570 }
571
572 state = datastore->data;
574 if (!state->media_state) {
575 ast_sip_session_remove_datastore(session, "pjsip_session_refresh");
576 return NULL;
577 }
578 state->media_state->topology = ast_stream_topology_clone(session->endpoint->media.topology);
579 if (!state->media_state->topology) {
580 ast_sip_session_remove_datastore(session, "pjsip_session_refresh");
581 return NULL;
582 }
583
584 datastore->data = state;
585
586 return state;
587}
588
589/*! \brief Struct used to push PJSIP_PARSE_URI function arguments to task processor */
591 const char *uri;
592 const char *type;
593 char *buf;
594 size_t buflen;
595 int ret;
596};
597
598/*! \internal \brief Taskprocessor callback that handles the PJSIP_PARSE_URI on a PJSIP thread */
599static int parse_uri_cb(void *data)
600{
601 struct parse_uri_args *args = data;
602 pj_pool_t *pool;
603 pjsip_name_addr *uri;
604 pjsip_sip_uri *sip_uri;
605 pj_str_t tmp;
606
607 args->ret = 0;
608
609 pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "ParseUri", 128, 128);
610 if (!pool) {
611 ast_log(LOG_ERROR, "Failed to allocate ParseUri endpoint pool.\n");
612 args->ret = -1;
613 return 0;
614 }
615
616 pj_strdup2_with_null(pool, &tmp, args->uri);
617 uri = (pjsip_name_addr *)pjsip_parse_uri(pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR);
618 if (!uri || (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) {
619 ast_log(LOG_WARNING, "Failed to parse URI '%s'\n", args->uri);
620 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
621 args->ret = -1;
622 return 0;
623 }
624
625 if (!strcmp(args->type, "scheme")) {
626 ast_copy_pj_str(args->buf, pjsip_uri_get_scheme(uri), args->buflen);
627 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
628 return 0;
629 } else if (!strcmp(args->type, "display")) {
630 ast_copy_pj_str(args->buf, &uri->display, args->buflen);
631 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
632 return 0;
633 }
634
635 sip_uri = pjsip_uri_get_uri(uri);
636 if (!sip_uri) {
637 ast_log(LOG_ERROR, "Failed to get an URI object for '%s'\n", args->uri);
638 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
639 args->ret = -1;
640 return 0;
641 }
642
643 if (!strcmp(args->type, "user")) {
644 ast_copy_pj_str(args->buf, &sip_uri->user, args->buflen);
645 } else if (!strcmp(args->type, "passwd")) {
646 ast_copy_pj_str(args->buf, &sip_uri->passwd, args->buflen);
647 } else if (!strcmp(args->type, "host")) {
648 ast_copy_pj_str(args->buf, &sip_uri->host, args->buflen);
649 } else if (!strcmp(args->type, "port")) {
650 snprintf(args->buf, args->buflen, "%d", sip_uri->port);
651 } else if (!strcmp(args->type, "user_param")) {
652 ast_copy_pj_str(args->buf, &sip_uri->user_param, args->buflen);
653 } else if (!strcmp(args->type, "method_param")) {
654 ast_copy_pj_str(args->buf, &sip_uri->method_param, args->buflen);
655 } else if (!strcmp(args->type, "transport_param")) {
656 ast_copy_pj_str(args->buf, &sip_uri->transport_param, args->buflen);
657 } else if (!strcmp(args->type, "ttl_param")) {
658 snprintf(args->buf, args->buflen, "%d", sip_uri->ttl_param);
659 } else if (!strcmp(args->type, "lr_param")) {
660 snprintf(args->buf, args->buflen, "%d", sip_uri->lr_param);
661 } else if (!strcmp(args->type, "maddr_param")) {
662 ast_copy_pj_str(args->buf, &sip_uri->maddr_param, args->buflen);
663 } else {
664 ast_log(AST_LOG_WARNING, "Unknown type part '%s' specified\n", args->type);
665 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
666 args->ret = -1;
667 return 0;
668 }
669
670 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
671
672 return 0;
673}
674
675int pjsip_acf_parse_uri_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
676{
677 struct parse_uri_args func_args = { 0, };
678 int reading_uri_from_var;
679
681 AST_APP_ARG(uri_str);
683 );
684
686
687 reading_uri_from_var = !strcasecmp(cmd, "PJSIP_PARSE_URI_FROM");
688
689 if (reading_uri_from_var) {
690 const char *var;
691
692 if (ast_strlen_zero(args.uri_str)) {
693 ast_log(LOG_WARNING, "The name of a variable containing a URI must be specified when using the '%s' dialplan function\n", cmd);
694 return -1;
695 }
696
697 ast_channel_lock(chan);
698 if ((var = pbx_builtin_getvar_helper(chan, args.uri_str))) {
699 args.uri_str = ast_strdupa(var);
700 }
701 ast_channel_unlock(chan);
702 }
703
704 if (ast_strlen_zero(args.uri_str)) {
705 if (reading_uri_from_var) {
706 ast_log(LOG_WARNING, "The variable provided to the '%s' dialplan function must contain a URI\n", cmd);
707 } else {
708 ast_log(LOG_WARNING, "A URI must be specified when using the '%s' dialplan function\n", cmd);
709 }
710 return -1;
711 }
712
713 if (ast_strlen_zero(args.type)) {
714 ast_log(LOG_WARNING, "A type part of the URI must be specified when using the '%s' dialplan function\n", cmd);
715 return -1;
716 }
717
718 memset(buf, 0, buflen);
719
720 func_args.uri = args.uri_str;
721 func_args.type = args.type;
722 func_args.buf = buf;
723 func_args.buflen = buflen;
725 ast_log(LOG_WARNING, "Unable to parse URI: failed to push task\n");
726 return -1;
727 }
728
729 return func_args.ret;
730}
731
733 size_t len, enum ast_media_type media_type)
734{
735 struct ast_stream_topology *topology;
736 int idx;
737 struct ast_stream *stream = NULL;
738 const struct ast_format_cap *caps;
739 size_t accum = 0;
740
741 if (session->inv_session->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED) {
743
744 /* As we've already answered we need to store our media state until we are ready to send it */
746 if (!state) {
747 return -1;
748 }
749 topology = state->media_state->topology;
750 } else {
751 /* The session is not yet up so we are initially answering or offering */
752 if (!session->pending_media_state->topology) {
753 session->pending_media_state->topology = ast_stream_topology_clone(session->endpoint->media.topology);
754 if (!session->pending_media_state->topology) {
755 return -1;
756 }
757 }
758 topology = session->pending_media_state->topology;
759 }
760
761 /* Find the first suitable stream */
762 for (idx = 0; idx < ast_stream_topology_get_count(topology); ++idx) {
763 stream = ast_stream_topology_get_stream(topology, idx);
764
765 if (ast_stream_get_type(stream) != media_type ||
767 stream = NULL;
768 continue;
769 }
770
771 break;
772 }
773
774 /* If no suitable stream then exit early */
775 if (!stream) {
776 buf[0] = '\0';
777 return 0;
778 }
779
780 caps = ast_stream_get_formats(stream);
781
782 /* Note: buf is not terminated while the string is being built. */
783 for (idx = 0; idx < ast_format_cap_count(caps); ++idx) {
784 struct ast_format *fmt;
785 size_t size;
786
787 fmt = ast_format_cap_get_format(caps, idx);
788
789 /* Add one for a comma or terminator */
790 size = strlen(ast_format_get_name(fmt)) + 1;
791 if (len < size) {
792 ao2_ref(fmt, -1);
793 break;
794 }
795
796 /* Append the format name */
797 strcpy(buf + accum, ast_format_get_name(fmt));/* Safe */
798 ao2_ref(fmt, -1);
799
800 accum += size;
801 len -= size;
802
803 /* The last comma on the built string will be set to the terminator. */
804 buf[accum - 1] = ',';
805 }
806
807 /* Remove the trailing comma or terminate an empty buffer. */
808 buf[accum ? accum - 1 : 0] = '\0';
809 return 0;
810}
811
817
818static int media_offer_write_av(void *obj)
819{
820 struct media_offer_data *data = obj;
821 struct ast_stream_topology *topology;
822 struct ast_stream *stream;
823 struct ast_format_cap *caps;
824
825 if (data->session->inv_session->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED) {
827
828 /* As we've already answered we need to store our media state until we are ready to send it */
830 if (!state) {
831 return -1;
832 }
833 topology = state->media_state->topology;
834 } else {
835 /* The session is not yet up so we are initially answering or offering */
836 if (!data->session->pending_media_state->topology) {
838 if (!data->session->pending_media_state->topology) {
839 return -1;
840 }
841 }
842 topology = data->session->pending_media_state->topology;
843 }
844
845 /* XXX This method won't work when it comes time to do multistream support. The proper way to do this
846 * will either be to
847 * a) Alter all media streams of a particular type.
848 * b) Change the dialplan function to be able to specify which stream to alter and alter only that
849 * one stream
850 */
852 if (!stream) {
853 return 0;
854 }
855
857 if (!caps) {
858 return -1;
859 }
860
865 ast_stream_set_formats(stream, caps);
866 ast_stream_set_metadata(stream, "pjsip_session_refresh", "force");
867 ao2_ref(caps, -1);
868
869 return 0;
870}
871
872int pjsip_acf_media_offer_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
873{
874 struct ast_sip_channel_pvt *channel;
875
876 if (!chan) {
877 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
878 return -1;
879 }
880
881 if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
882 ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
883 return -1;
884 }
885
886 channel = ast_channel_tech_pvt(chan);
887
888 if (!strcmp(data, "audio")) {
890 } else if (!strcmp(data, "video")) {
892 } else {
893 /* Ensure that the buffer is empty */
894 buf[0] = '\0';
895 }
896
897 return 0;
898}
899
900int pjsip_acf_media_offer_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
901{
902 struct ast_sip_channel_pvt *channel;
903 struct media_offer_data mdata = {
904 .value = value
905 };
906
907 if (!chan) {
908 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
909 return -1;
910 }
911
912 if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
913 ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
914 return -1;
915 }
916
917 channel = ast_channel_tech_pvt(chan);
918 mdata.session = channel->session;
919
920 if (!strcmp(data, "audio")) {
922 } else if (!strcmp(data, "video")) {
924 }
925
927}
928
929int pjsip_acf_dtmf_mode_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
930{
931 struct ast_sip_channel_pvt *channel;
932
933 if (!chan) {
934 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
935 return -1;
936 }
937
938 ast_channel_lock(chan);
939 if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
940 ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
941 ast_channel_unlock(chan);
942 return -1;
943 }
944
945 channel = ast_channel_tech_pvt(chan);
946
947 if (ast_sip_dtmf_to_str(channel->session->dtmf, buf, len) < 0) {
948 ast_log(LOG_WARNING, "Unknown DTMF mode %d on PJSIP channel %s\n", channel->session->dtmf, ast_channel_name(chan));
949 ast_channel_unlock(chan);
950 return -1;
951 }
952
953 ast_channel_unlock(chan);
954 return 0;
955}
956
957int pjsip_acf_moh_passthrough_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
958{
959 struct ast_sip_channel_pvt *channel;
960
961 if (!chan) {
962 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
963 return -1;
964 }
965
966 if (len < 3) {
967 ast_log(LOG_WARNING, "%s: buffer too small\n", cmd);
968 return -1;
969 }
970
971 ast_channel_lock(chan);
972 if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
973 ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
974 ast_channel_unlock(chan);
975 return -1;
976 }
977
978 channel = ast_channel_tech_pvt(chan);
979 strncpy(buf, AST_YESNO(channel->session->moh_passthrough), len);
980
981 ast_channel_unlock(chan);
982 return 0;
983}
984
989
990static int sip_session_response_cb(struct ast_sip_session *session, pjsip_rx_data *rdata)
991{
992 struct ast_format *fmt;
993
994 if (!session->channel) {
995 /* Egads! */
996 return 0;
997 }
998
1000 if (!fmt) {
1001 /* No format? That's weird. */
1002 return 0;
1003 }
1004 ast_channel_set_writeformat(session->channel, fmt);
1006 ast_channel_set_readformat(session->channel, fmt);
1008 ao2_ref(fmt, -1);
1009
1010 return 0;
1011}
1012
1013static int dtmf_mode_refresh_cb(void *obj)
1014{
1015 struct refresh_data *data = obj;
1016
1017 if (data->session->inv_session->state == PJSIP_INV_STATE_CONFIRMED) {
1018 ast_debug(3, "Changing DTMF mode on channel %s after OFFER/ANSWER completion. Sending session refresh\n", ast_channel_name(data->session->channel));
1019
1022 } else if (data->session->inv_session->state == PJSIP_INV_STATE_INCOMING) {
1023 ast_debug(3, "Changing DTMF mode on channel %s during OFFER/ANSWER exchange. Updating SDP answer\n", ast_channel_name(data->session->channel));
1025 }
1026
1027 return 0;
1028}
1029
1030int pjsip_acf_dtmf_mode_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1031{
1032 struct ast_sip_channel_pvt *channel;
1033 struct ast_sip_session_media *media;
1034 int dsp_features = 0;
1035 int dtmf = -1;
1036 struct refresh_data rdata = {
1038 };
1039
1040 if (!chan) {
1041 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1042 return -1;
1043 }
1044
1045 ast_channel_lock(chan);
1046 if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
1047 ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
1048 ast_channel_unlock(chan);
1049 return -1;
1050 }
1051
1052 channel = ast_channel_tech_pvt(chan);
1053 rdata.session = channel->session;
1054
1055 dtmf = ast_sip_str_to_dtmf(value);
1056
1057 if (dtmf == -1) {
1058 ast_log(LOG_WARNING, "Cannot set DTMF mode to '%s' on channel '%s' as value is invalid.\n", value,
1059 ast_channel_name(chan));
1060 ast_channel_unlock(chan);
1061 return -1;
1062 }
1063
1064 if (channel->session->dtmf == dtmf) {
1065 /* DTMF mode unchanged, nothing to do! */
1066 ast_channel_unlock(chan);
1067 return 0;
1068 }
1069
1070 channel->session->dtmf = dtmf;
1071
1073
1074 if (media && media->rtp) {
1075 if (channel->session->dtmf == AST_SIP_DTMF_RFC_4733) {
1078 } else if (channel->session->dtmf == AST_SIP_DTMF_INFO) {
1081 } else if (channel->session->dtmf == AST_SIP_DTMF_INBAND) {
1084 } else if (channel->session->dtmf == AST_SIP_DTMF_NONE) {
1087 } else if (channel->session->dtmf == AST_SIP_DTMF_AUTO) {
1089 /* no RFC4733 negotiated, enable inband */
1091 }
1092 } else if (channel->session->dtmf == AST_SIP_DTMF_AUTO_INFO) {
1095 /* if inband, switch to INFO */
1097 }
1098 }
1099 }
1100
1101 if (channel->session->dsp) {
1102 dsp_features = ast_dsp_get_features(channel->session->dsp);
1103 }
1104 if (channel->session->dtmf == AST_SIP_DTMF_INBAND ||
1105 channel->session->dtmf == AST_SIP_DTMF_AUTO) {
1106 dsp_features |= DSP_FEATURE_DIGIT_DETECT;
1107 } else {
1108 dsp_features &= ~DSP_FEATURE_DIGIT_DETECT;
1109 }
1110 if (dsp_features) {
1111 if (!channel->session->dsp) {
1112 if (!(channel->session->dsp = ast_dsp_new())) {
1113 ast_channel_unlock(chan);
1114 return 0;
1115 }
1116 }
1117 ast_dsp_set_features(channel->session->dsp, dsp_features);
1118 } else if (channel->session->dsp) {
1119 ast_dsp_free(channel->session->dsp);
1120 channel->session->dsp = NULL;
1121 }
1122
1123 ast_channel_unlock(chan);
1124
1126}
1127
1128int pjsip_acf_moh_passthrough_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1129{
1130 struct ast_sip_channel_pvt *channel;
1131
1132 if (!chan) {
1133 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1134 return -1;
1135 }
1136
1137 ast_channel_lock(chan);
1138 if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
1139 ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
1140 ast_channel_unlock(chan);
1141 return -1;
1142 }
1143
1144 channel = ast_channel_tech_pvt(chan);
1146
1147 ast_channel_unlock(chan);
1148
1149 return 0;
1150}
1151
1152static int refresh_write_cb(void *obj)
1153{
1154 struct refresh_data *data = obj;
1156
1158 if (!state) {
1159 return -1;
1160 }
1161
1163 sip_session_response_cb, data->method, 1, state->media_state);
1164
1165 state->media_state = NULL;
1166 ast_sip_session_remove_datastore(data->session, "pjsip_session_refresh");
1167
1168 return 0;
1169}
1170
1171int pjsip_acf_session_refresh_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1172{
1173 struct ast_sip_channel_pvt *channel;
1174 struct refresh_data rdata = {
1176 };
1177
1178 if (!chan) {
1179 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1180 return -1;
1181 }
1182
1183 if (ast_channel_state(chan) != AST_STATE_UP) {
1184 ast_log(LOG_WARNING, "'%s' not allowed on unanswered channel '%s'.\n", cmd, ast_channel_name(chan));
1185 return -1;
1186 }
1187
1188 if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
1189 ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
1190 return -1;
1191 }
1192
1193 channel = ast_channel_tech_pvt(chan);
1194 rdata.session = channel->session;
1195
1196 if (!strcmp(value, "invite")) {
1198 } else if (!strcmp(value, "update")) {
1200 }
1201
1203}
1204
1205struct hangup_data {
1208};
1209
1210/*!
1211 * \brief Serializer task to hangup channel
1212 */
1213static int pjsip_hangup(void *obj)
1214{
1215 struct hangup_data *hdata = obj;
1216 pjsip_tx_data *packet = NULL;
1217
1218 if ((hdata->session->inv_session->state != PJSIP_INV_STATE_DISCONNECTED) &&
1219 (pjsip_inv_answer(hdata->session->inv_session, hdata->response_code, NULL, NULL, &packet) == PJ_SUCCESS)) {
1220 ast_sip_session_send_response(hdata->session, packet);
1221 }
1222
1223 return 0;
1224}
1225
1226/*!
1227 * \brief Callback that validates the response code
1228 */
1229static int response_code_validator(const char *channel_name,
1230 const char *response) {
1231 int response_code;
1232
1233 int rc = ast_str_to_int(response, &response_code);
1234 if (rc != 0) {
1235 response_code = ast_sip_str2rc(response);
1236 if (response_code < 0) {
1237 ast_log(LOG_WARNING, "%s: Unrecognized response code parameter '%s'."
1238 " Defaulting to 603 DECLINE\n",
1239 channel_name, response);
1240 return PJSIP_SC_DECLINE;
1241 }
1242 }
1243
1244 if (response_code < 400 || response_code > 699) {
1245 ast_log(LOG_WARNING, "%s: Response code %d is out of range 400 -> 699."
1246 " Defaulting to 603 DECLINE\n",
1247 channel_name, response_code);
1248 return PJSIP_SC_DECLINE;
1249 }
1250 return response_code;
1251}
1252
1253/*!
1254 * \brief Called by pjsip_app_hangup and pjsip_action_hangup
1255 * to actually perform the hangup
1256 */
1258{
1259 struct ast_sip_channel_pvt *channel;
1260 struct hangup_data hdata = { NULL, -1 };
1261 const char *tag = ast_channel_name(chan);
1262
1264
1266 if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
1267 ast_log(LOG_WARNING, "%s: Not a PJSIP channel\n", tag);
1269 return;
1270 }
1271
1272 channel = ast_channel_tech_pvt(chan);
1273 hdata.session = channel->session;
1274
1275 if (hdata.session->inv_session->role != PJSIP_ROLE_UAS || (
1276 hdata.session->inv_session->state != PJSIP_INV_STATE_INCOMING &&
1277 hdata.session->inv_session->state != PJSIP_INV_STATE_EARLY)) {
1278 ast_log(LOG_WARNING, "%s: Not an incoming channel or invalid state '%s'\n",
1279 tag, pjsip_inv_state_name(hdata.session->inv_session->state));
1281 return;
1282 }
1283
1285
1287 pjsip_hangup, &hdata) != 0) {
1288 ast_log(LOG_WARNING, "%s: failed to push hangup task to serializer\n", tag);
1289 }
1290
1291 return;
1292}
1293
1294/*!
1295 * \brief PJSIPHangup Dialplan App
1296 */
1297int pjsip_app_hangup(struct ast_channel *chan, const char *data)
1298{
1299 int response_code;
1300 const char *tag = ast_channel_name(chan);
1301
1302 if (ast_strlen_zero(data)) {
1303 ast_log(LOG_WARNING, "%s: Missing response code parameter\n", tag);
1304 return -1;
1305 }
1306
1308
1310
1311 return -1;
1312}
1313
1314/*!
1315 * \brief PJSIPHangup Manager Action
1316 */
1317int pjsip_action_hangup(struct mansession *s, const struct message *m)
1318{
1319 return ast_manager_hangup_helper(s, m,
1321}
1322
1323int pjsip_transfer_handling_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1324{
1325 struct ast_sip_channel_pvt *channel;
1326 int ret = 0;
1327
1328 if (!chan) {
1329 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1330 return -1;
1331 }
1332
1333 ast_channel_lock(chan);
1334 if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
1335 ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel %s\n", cmd, ast_channel_name(chan));
1336 ast_channel_unlock(chan);
1337 return -1;
1338 }
1339
1340 channel = ast_channel_tech_pvt(chan);
1341
1342 if (ast_strlen_zero(value) || !strcmp(value, "core")) {
1343 channel->session->transferhandling_ari = 0;
1344 } else if (!strcmp(value, "ari-only")) {
1345 channel->session->transferhandling_ari = 1;
1346 } else {
1347 ast_log(AST_LOG_WARNING, "Cannot set unknown transfer handling '%s' on channel '%s', transfer handling will remain unchanged.",
1348 value, ast_channel_name(chan));
1349 ret = -1;
1350 }
1351
1352 ast_channel_unlock(chan);
1353 return ret;
1354}
Access Control of various sorts.
static int copy(char *infile, char *outfile)
Utility function to copy a file.
#define var
Definition ast_expr2f.c:605
char * strsep(char **str, const char *delims)
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_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
void ast_free_ptr(void *ptr)
free() wrapper
Definition astmm.c:1739
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
#define ast_log
Definition astobj2.c:42
#define ao2_iterator_next(iter)
Definition astobj2.h:1911
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#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.
static const char type[]
#define T38_ENABLED
#define T38_DISABLED
PJSIP Channel Driver shared data structures.
General Asterisk PBX channel definitions.
const char * ast_channel_name(const struct ast_channel *chan)
void * ast_channel_tech_pvt(const struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition channel.h:2983
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
void ast_channel_set_rawreadformat(struct ast_channel *chan, struct ast_format *format)
void ast_channel_set_rawwriteformat(struct ast_channel *chan, struct ast_format *format)
void ast_channel_set_readformat(struct ast_channel *chan, struct ast_format *format)
#define ast_channel_unlock(chan)
Definition channel.h:2984
void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format)
struct pjsip_channel_info * pjsip_channel_info_get(struct ast_channel *chan)
Find the channel's information, or NULL if it has none.
Channel-locked PJSIP information interface.
ast_channel_state
ast_channel states
@ AST_STATE_UP
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
Conversion utility functions.
int ast_str_to_int(const char *str, int *res)
Convert the given string to a signed integer.
Definition conversions.c:44
int pjsip_acf_moh_passthrough_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
PJSIP_MOH_PASSTHROUGH function read callback.
int pjsip_acf_media_offer_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
PJSIP_MEDIA_OFFER function read callback.
int pjsip_acf_media_offer_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
PJSIP_MEDIA_OFFER function write callback.
static int pjsip_hangup(void *obj)
Serializer task to hangup channel.
static int response_code_validator(const char *channel_name, const char *response)
Callback that validates the response code.
static int refresh_write_cb(void *obj)
int pjsip_acf_dtmf_mode_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
PJSIP_DTMF_MODE function write callback.
int pjsip_transfer_handling_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
PJSIP_TRANSFER_HANDLING function write callback.
int pjsip_acf_session_refresh_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
PJSIP_SEND_SESSION_REFRESH function write callback.
static int media_offer_read_av(struct ast_sip_session *session, char *buf, size_t len, enum ast_media_type media_type)
static int read_request_uri(struct ast_channel *chan, struct ast_sip_session *session, char *buf, size_t size)
static int media_offer_write_av(void *obj)
static void pjsip_app_hangup_handler(struct ast_channel *chan, int response_code)
Called by pjsip_app_hangup and pjsip_action_hangup to actually perform the hangup.
static int channel_read_rtcp(struct ast_channel *chan, struct ast_rtp_instance *rtp, const char *type, const char *field, char *buf, size_t buflen)
static int sip_session_response_cb(struct ast_sip_session *session, pjsip_rx_data *rdata)
static void session_refresh_state_destroy(void *obj)
Destructor for session refresh information.
static struct session_refresh_state * session_refresh_state_get_or_alloc(struct ast_sip_session *session)
Helper function which retrieves or allocates a session refresh state information datastore.
int pjsip_app_hangup(struct ast_channel *chan, const char *data)
PJSIPHangup Dialplan App.
static const char * t38state_to_string[T38_MAX_ENUM]
String representations of the T.38 state enum.
int pjsip_acf_moh_passthrough_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
PJSIP_MOH_PASSTHROUGH function write callback.
static int dtmf_mode_refresh_cb(void *obj)
int pjsip_action_hangup(struct mansession *s, const struct message *m)
PJSIPHangup Manager Action.
static int copy_escaped_uri(struct ast_channel *chan, const char *type, const struct pjsip_channel_uri *uri, char *buf, size_t size)
int pjsip_acf_channel_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
CHANNEL function read callback.
static int channel_read_pjsip(struct ast_channel *chan, struct ast_sip_session *session, const char *type, char *buf, size_t len)
static int channel_read_rtp(struct ast_channel *chan, struct ast_rtp_instance *rtp, const struct ast_sockaddr *direct_media_addr, unsigned int secure, unsigned int held, const char *type, const char *field, char *buf, size_t buflen)
int pjsip_acf_dtmf_mode_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
PJSIP_DTMF_MODE function read callback.
int pjsip_acf_dial_contacts_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
PJSIP_DIAL_CONTACTS function read callback.
static const struct ast_datastore_info session_refresh_datastore
Datastore for attaching session refresh state information.
int pjsip_acf_parse_uri_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
PJSIP_PARSE_URI function read callback.
static int parse_uri_cb(void *data)
PJSIP dialplan functions header file.
Convenient Signal Processing routines.
void ast_dsp_free(struct ast_dsp *dsp)
Definition dsp.c:1968
#define DSP_FEATURE_DIGIT_DETECT
Definition dsp.h:28
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
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition dsp.c:1943
char buf[BUFSIZE]
Definition eagi_proxy.c:66
Media Format API.
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition format.c:334
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
int ast_format_cap_update_by_allow_disallow(struct ast_format_cap *cap, const char *list, int allowing)
Parse an "allow" or "deny" list and modify a format capabilities structure accordingly.
Definition format_cap.c:328
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
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
#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
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int ast_manager_hangup_helper(struct mansession *s, const struct message *m, manager_hangup_handler_t handler, manager_hangup_cause_validator_t cause_validator)
A manager helper function that hangs up a channel using a supplied channel type specific hangup funct...
Definition manager.c:3469
#define ast_sip_push_task_wait_serializer(serializer, sip_task, task_data)
Definition res_pjsip.h:2221
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define AST_LOG_WARNING
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_WARNING
Asterisk module definitions.
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition netsock2.h:256
Core PBX routines and definitions.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
static char * func_args(char *function)
return a pointer to the arguments of the function, and terminates the function name with '\0'
struct ast_sip_aor * ast_sip_location_retrieve_aor(const char *aor_name)
Retrieve a named AOR.
Definition location.c:147
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition res_pjsip.c:518
int ast_sip_dtmf_to_str(const enum ast_sip_dtmf_mode dtmf, char *buf, size_t buf_len)
Convert the DTMF mode enum value into a string.
Definition res_pjsip.c:2524
int ast_sip_str2rc(const char *name)
Convert name to SIP response code.
Definition res_pjsip.c:3754
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:2221
@ AST_SIP_CONTACT_FILTER_REACHABLE
Return only reachable or unknown contacts.
Definition res_pjsip.h:1443
@ AST_SIP_DTMF_NONE
Definition res_pjsip.h:549
@ 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_INFO
Definition res_pjsip.h:556
@ AST_SIP_DTMF_RFC_4733
Definition res_pjsip.h:552
int ast_sip_str_to_dtmf(const char *dtmf_mode)
Convert the DTMF mode name into an enum.
Definition res_pjsip.c:2553
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
struct ao2_container * ast_sip_location_retrieve_aor_contacts_filtered(const struct ast_sip_aor *aor, unsigned int flags)
Retrieve all contacts currently available for an AOR and filter based on flags.
Definition location.c:252
ast_sip_session_refresh_method
Definition res_pjsip.h:715
@ AST_SIP_SESSION_REFRESH_METHOD_UPDATE
Definition res_pjsip.h:719
@ AST_SIP_SESSION_REFRESH_METHOD_INVITE
Definition res_pjsip.h:717
int ast_sip_session_regenerate_answer(struct ast_sip_session *session, ast_sip_session_sdp_creation_cb on_sdp_creation)
Regenerate SDP Answer.
struct ast_datastore * ast_sip_session_get_datastore(struct ast_sip_session *session, const char *name)
Retrieve a session datastore.
@ T38_PEER_REINVITE
@ T38_LOCAL_REINVITE
@ T38_MAX_ENUM
@ T38_REJECTED
struct ast_sip_session_media_state * ast_sip_session_media_state_alloc(void)
Allocate a session media state structure.
int ast_sip_session_add_datastore(struct ast_sip_session *session, struct ast_datastore *datastore)
Add a datastore to a SIP session.
void ast_sip_session_remove_datastore(struct ast_sip_session *session, const char *name)
Remove a session datastore from the session.
void ast_sip_session_media_state_free(struct ast_sip_session_media_state *media_state)
Free a session media state structure.
struct ast_datastore * ast_sip_session_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
Alternative for ast_datastore_alloc()
int ast_sip_session_refresh(struct ast_sip_session *session, ast_sip_session_request_creation_cb on_request_creation, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, enum ast_sip_session_refresh_method method, int generate_new_sdp, struct ast_sip_session_media_state *media_state)
Send a reinvite or UPDATE on a session.
void ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
Send a SIP response.
static struct @523 args
#define NULL
Definition resample.c:96
enum ast_rtp_dtmf_mode ast_rtp_instance_dtmf_mode_get(struct ast_rtp_instance *instance)
Get the DTMF mode of an RTP instance.
@ 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.
ast_rtp_instance_stat_field
Definition rtp_engine.h:171
@ AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS
Definition rtp_engine.h:177
@ AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT
Definition rtp_engine.h:179
@ AST_RTP_INSTANCE_STAT_FIELD_QUALITY
Definition rtp_engine.h:173
@ AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER
Definition rtp_engine.h:175
@ AST_RTP_INSTANCE_STAT_FIELD_QUALITY_MES
Definition rtp_engine.h:181
@ AST_RTP_INSTANCE_STAT_ALL
Definition rtp_engine.h:187
#define ast_rtp_instance_get_remote_address(instance, address)
Get the address of the remote endpoint that we are sending RTP to.
char * ast_rtp_instance_get_quality(struct ast_rtp_instance *instance, enum ast_rtp_instance_stat_field field, char *buf, size_t size)
Retrieve quality statistics about an RTP instance.
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
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_PROPERTY_DTMF
Definition rtp_engine.h:120
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.
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_REMOVED
Set when the stream has been removed/declined.
Definition stream.h:78
struct ast_stream * ast_stream_topology_get_stream(const struct ast_stream_topology *topology, unsigned int position)
Get a specific stream from the topology.
Definition stream.c:791
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition stream.c:768
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
Definition stream.c:373
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
struct ast_stream_topology * ast_stream_topology_clone(const struct ast_stream_topology *topology)
Create a deep clone of an existing stream topology.
Definition stream.c:670
struct ast_stream * ast_stream_topology_get_first_stream_by_type(const struct ast_stream_topology *topology, enum ast_media_type type)
Gets the first active stream of a specific type from the topology.
Definition stream.c:967
char * ast_str_truncate(struct ast_str *buf, ssize_t len)
Truncates the enclosed string to the given length.
Definition strings.h:786
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
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition utils.c:2233
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition strings.h:659
#define AST_YESNO(x)
return Yes or No depending on the argument.
Definition strings.h:143
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
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition strings.h:223
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
Structure to describe a channel "technology", ie a channel driver See for examples:
Definition channel.h:648
Main Channel structure associated with a channel.
Structure for a data store type.
Definition datastore.h:31
const char * type
Definition datastore.h:32
Structure for a data store object.
Definition datastore.h:64
Format capabilities structure, holds formats + preference order + etc.
Definition format_cap.c:54
Definition of a media format.
Definition format.c:43
unsigned int remote_ssrc
Definition rtp_engine.h:454
unsigned int local_ssrc
Definition rtp_engine.h:452
A SIP address of record.
Definition res_pjsip.h:480
A structure which contains a channel implementation and session.
struct ast_sip_session * session
Pointer to session.
Contact associated with an address of record.
Definition res_pjsip.h:392
const ast_string_field uri
Definition res_pjsip.h:414
const ast_string_field aor
Definition res_pjsip.h:414
struct ast_stream_topology * topology
Definition res_pjsip.h:1027
An entity with which Asterisk communicates.
Definition res_pjsip.h:1067
struct ast_sip_endpoint_media_configuration media
Definition res_pjsip.h:1100
Structure which contains media state information (streams, sessions)
struct ast_stream_topology * topology
The media stream topology.
struct ast_sip_session_media * default_session[AST_MEDIA_TYPE_END]
Default media sessions for each type.
A structure containing SIP session media information.
struct ast_rtp_instance * rtp
RTP instance itself.
struct ast_sockaddr direct_media_addr
Direct media address.
A structure describing a SIP session.
struct ast_sip_contact * contact
struct ast_sip_endpoint * endpoint
unsigned int transferhandling_ari
struct ast_channel * channel
unsigned int moh_passthrough
struct ast_sip_session_media_state * active_media_state
struct ast_sip_session_media_state * pending_media_state
struct ast_dsp * dsp
struct pjsip_inv_session * inv_session
enum ast_sip_dtmf_mode dtmf
struct ast_sip_aor * aor
struct ast_taskprocessor * serializer
Socket address structure.
Definition netsock2.h:97
Support for dynamic strings.
Definition strings.h:623
struct ast_sip_session * session
struct ast_channel * chan
In case you didn't read that giant block of text above the mansession_session struct,...
Definition manager.c:314
enum ast_media_type media_type
struct ast_sip_session * session
Struct used to push PJSIP_PARSE_URI function arguments to task processor.
struct ast_datastore * datastore
char value[PJSIP_MAX_URL_SIZE]
struct ast_sip_session * session
enum ast_sip_session_refresh_method method
Session refresh state information.
struct ast_sip_session_media_state * media_state
Created proposed media state.
Transport information stored in transport_info datastore.
Definition chan_pjsip.h:30
pj_sockaddr local_addr
Our address that received the request.
Definition chan_pjsip.h:34
pj_sockaddr remote_addr
The address that sent the request.
Definition chan_pjsip.h:32
int value
Definition syslog.c:37
#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
char * ast_escape_quoted(const char *string, char *outbuf, int buflen)
Escape characters found in a quoted string.
Definition utils.c:815