Asterisk - The Open Source Telephony Project GIT-master-7e7a603
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"
52
53/*!
54 * \brief String representations of the T.38 state enum
55 */
56static const char *t38state_to_string[T38_MAX_ENUM] = {
57 [T38_DISABLED] = "DISABLED",
58 [T38_LOCAL_REINVITE] = "LOCAL_REINVITE",
59 [T38_PEER_REINVITE] = "REMOTE_REINVITE",
60 [T38_ENABLED] = "ENABLED",
61 [T38_REJECTED] = "REJECTED",
62};
63
64/*!
65 * \internal \brief Handle reading RTP information
66 */
67static int channel_read_rtp(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen)
68{
69 struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
71 struct ast_sip_session_media *media;
72 struct ast_sockaddr addr;
73
74 if (!channel) {
75 ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
76 return -1;
77 }
78
79 session = channel->session;
80 if (!session) {
81 ast_log(AST_LOG_WARNING, "Channel %s has no session!\n", ast_channel_name(chan));
82 return -1;
83 }
84
85 if (ast_strlen_zero(type)) {
86 ast_log(AST_LOG_WARNING, "You must supply a type field for 'rtp' information\n");
87 return -1;
88 }
89
90 if (ast_strlen_zero(field) || !strcmp(field, "audio")) {
91 media = session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];
92 } else if (!strcmp(field, "video")) {
93 media = session->active_media_state->default_session[AST_MEDIA_TYPE_VIDEO];
94 } else {
95 ast_log(AST_LOG_WARNING, "Unknown media type field '%s' for 'rtp' information\n", field);
96 return -1;
97 }
98
99 if (!media || !media->rtp) {
100 ast_log(AST_LOG_WARNING, "Channel %s has no %s media/RTP session\n",
101 ast_channel_name(chan), S_OR(field, "audio"));
102 return -1;
103 }
104
105 if (!strcmp(type, "src")) {
108 } else if (!strcmp(type, "dest")) {
111 } else if (!strcmp(type, "direct")) {
113 } else if (!strcmp(type, "secure")) {
114 if (media->srtp) {
115 struct ast_sdp_srtp *srtp = media->srtp;
117 snprintf(buf, buflen, "%d", flag ? 1 : 0);
118 } else {
119 snprintf(buf, buflen, "%d", 0);
120 }
121 } else if (!strcmp(type, "hold")) {
122 snprintf(buf, buflen, "%d", media->remotely_held ? 1 : 0);
123 } else {
124 ast_log(AST_LOG_WARNING, "Unknown type field '%s' specified for 'rtp' information\n", type);
125 return -1;
126 }
127
128 return 0;
129}
130
131/*!
132 * \internal \brief Handle reading RTCP information
133 */
134static int channel_read_rtcp(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen)
135{
136 struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
137 struct ast_sip_session *session;
138 struct ast_sip_session_media *media;
139
140 if (!channel) {
141 ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
142 return -1;
143 }
144
145 session = channel->session;
146 if (!session) {
147 ast_log(AST_LOG_WARNING, "Channel %s has no session!\n", ast_channel_name(chan));
148 return -1;
149 }
150
151 if (ast_strlen_zero(type)) {
152 ast_log(AST_LOG_WARNING, "You must supply a type field for 'rtcp' information\n");
153 return -1;
154 }
155
156 if (ast_strlen_zero(field) || !strcmp(field, "audio")) {
157 media = session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];
158 } else if (!strcmp(field, "video")) {
159 media = session->active_media_state->default_session[AST_MEDIA_TYPE_VIDEO];
160 } else {
161 ast_log(AST_LOG_WARNING, "Unknown media type field '%s' for 'rtcp' information\n", field);
162 return -1;
163 }
164
165 if (!media || !media->rtp) {
166 ast_log(AST_LOG_WARNING, "Channel %s has no %s media/RTP session\n",
167 ast_channel_name(chan), S_OR(field, "audio"));
168 return -1;
169 }
170
171 if (!strncasecmp(type, "all", 3)) {
173
174 if (!strcasecmp(type, "all_jitter")) {
176 } else if (!strcasecmp(type, "all_rtt")) {
178 } else if (!strcasecmp(type, "all_loss")) {
180 } else if (!strcasecmp(type, "all_mes")) {
182 }
183
184 if (!ast_rtp_instance_get_quality(media->rtp, stat_field, buf, buflen)) {
185 ast_log(AST_LOG_WARNING, "Unable to retrieve 'rtcp' statistics for %s\n", ast_channel_name(chan));
186 return -1;
187 }
188 } else {
189 struct ast_rtp_instance_stats stats;
190 int i;
191 struct {
192 const char *name;
193 enum { INT, DBL } type;
194 union {
195 unsigned int *i4;
196 double *d8;
197 };
198 } lookup[] = {
199 { "txcount", INT, { .i4 = &stats.txcount, }, },
200 { "rxcount", INT, { .i4 = &stats.rxcount, }, },
201 { "txjitter", DBL, { .d8 = &stats.txjitter, }, },
202 { "rxjitter", DBL, { .d8 = &stats.rxjitter, }, },
203 { "remote_maxjitter", DBL, { .d8 = &stats.remote_maxjitter, }, },
204 { "remote_minjitter", DBL, { .d8 = &stats.remote_minjitter, }, },
205 { "remote_normdevjitter", DBL, { .d8 = &stats.remote_normdevjitter, }, },
206 { "remote_stdevjitter", DBL, { .d8 = &stats.remote_stdevjitter, }, },
207 { "local_maxjitter", DBL, { .d8 = &stats.local_maxjitter, }, },
208 { "local_minjitter", DBL, { .d8 = &stats.local_minjitter, }, },
209 { "local_normdevjitter", DBL, { .d8 = &stats.local_normdevjitter, }, },
210 { "local_stdevjitter", DBL, { .d8 = &stats.local_stdevjitter, }, },
211 { "txploss", INT, { .i4 = &stats.txploss, }, },
212 { "rxploss", INT, { .i4 = &stats.rxploss, }, },
213 { "remote_maxrxploss", DBL, { .d8 = &stats.remote_maxrxploss, }, },
214 { "remote_minrxploss", DBL, { .d8 = &stats.remote_minrxploss, }, },
215 { "remote_normdevrxploss", DBL, { .d8 = &stats.remote_normdevrxploss, }, },
216 { "remote_stdevrxploss", DBL, { .d8 = &stats.remote_stdevrxploss, }, },
217 { "local_maxrxploss", DBL, { .d8 = &stats.local_maxrxploss, }, },
218 { "local_minrxploss", DBL, { .d8 = &stats.local_minrxploss, }, },
219 { "local_normdevrxploss", DBL, { .d8 = &stats.local_normdevrxploss, }, },
220 { "local_stdevrxploss", DBL, { .d8 = &stats.local_stdevrxploss, }, },
221 { "rtt", DBL, { .d8 = &stats.rtt, }, },
222 { "maxrtt", DBL, { .d8 = &stats.maxrtt, }, },
223 { "minrtt", DBL, { .d8 = &stats.minrtt, }, },
224 { "normdevrtt", DBL, { .d8 = &stats.normdevrtt, }, },
225 { "stdevrtt", DBL, { .d8 = &stats.stdevrtt, }, },
226 { "local_ssrc", INT, { .i4 = &stats.local_ssrc, }, },
227 { "remote_ssrc", INT, { .i4 = &stats.remote_ssrc, }, },
228 { "txmes", DBL, { .d8 = &stats.txmes, }, },
229 { "rxmes", DBL, { .d8 = &stats.rxmes, }, },
230 { "remote_maxmes", DBL, { .d8 = &stats.remote_maxmes, }, },
231 { "remote_minmes", DBL, { .d8 = &stats.remote_minmes, }, },
232 { "remote_normdevmes", DBL, { .d8 = &stats.remote_normdevmes, }, },
233 { "remote_stdevmes", DBL, { .d8 = &stats.remote_stdevmes, }, },
234 { "local_maxmes", DBL, { .d8 = &stats.local_maxmes, }, },
235 { "local_minmes", DBL, { .d8 = &stats.local_minmes, }, },
236 { "local_normdevmes", DBL, { .d8 = &stats.local_normdevmes, }, },
237 { "local_stdevmes", DBL, { .d8 = &stats.local_stdevmes, }, },
238 { NULL, },
239 };
240
242 ast_log(AST_LOG_WARNING, "Unable to retrieve 'rtcp' statistics for %s\n", ast_channel_name(chan));
243 return -1;
244 }
245
246 for (i = 0; !ast_strlen_zero(lookup[i].name); i++) {
247 if (!strcasecmp(type, lookup[i].name)) {
248 if (lookup[i].type == INT) {
249 snprintf(buf, buflen, "%u", *lookup[i].i4);
250 } else {
251 snprintf(buf, buflen, "%f", *lookup[i].d8);
252 }
253 return 0;
254 }
255 }
256 ast_log(AST_LOG_WARNING, "Unrecognized argument '%s' for 'rtcp' information\n", type);
257 return -1;
258 }
259
260 return 0;
261}
262
263static int print_escaped_uri(struct ast_channel *chan, const char *type,
264 pjsip_uri_context_e context, const void *uri, char *buf, size_t size)
265{
266 int res;
267 char *buf_copy;
268
269 res = pjsip_uri_print(context, uri, buf, size);
270 if (res < 0) {
271 ast_log(LOG_ERROR, "Channel %s: Unescaped %s too long for %d byte buffer\n",
272 ast_channel_name(chan), type, (int) size);
273
274 /* Empty buffer that likely is not terminated. */
275 buf[0] = '\0';
276 return -1;
277 }
278
279 buf_copy = ast_strdupa(buf);
280 ast_escape_quoted(buf_copy, buf, size);
281 return 0;
282}
283
284/*!
285 * \internal \brief Handle reading signalling information
286 */
287static int channel_read_pjsip(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen)
288{
289 struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
290 char *buf_copy;
291 pjsip_dialog *dlg;
292 int res = 0;
293
294 if (!channel) {
295 ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
296 return -1;
297 }
298
299 dlg = channel->session->inv_session->dlg;
300
301 if (ast_strlen_zero(type)) {
302 ast_log(LOG_WARNING, "You must supply a type field for 'pjsip' information\n");
303 return -1;
304 } else if (!strcmp(type, "call-id")) {
305 snprintf(buf, buflen, "%.*s", (int) pj_strlen(&dlg->call_id->id), pj_strbuf(&dlg->call_id->id));
306 } else if (!strcmp(type, "secure")) {
307#ifdef HAVE_PJSIP_GET_DEST_INFO
308 pjsip_host_info dest;
309 pj_pool_t *pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "secure-check", 128, 128);
310 pjsip_get_dest_info(dlg->target, NULL, pool, &dest);
311 snprintf(buf, buflen, "%d", dest.flag & PJSIP_TRANSPORT_SECURE ? 1 : 0);
312 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
313#else
314 ast_log(LOG_WARNING, "Asterisk has been built against a version of pjproject which does not have the required functionality to support the 'secure' argument. Please upgrade to version 2.3 or later.\n");
315 return -1;
316#endif
317 } else if (!strcmp(type, "target_uri")) {
318 res = print_escaped_uri(chan, type, PJSIP_URI_IN_REQ_URI, dlg->target, buf,
319 buflen);
320 } else if (!strcmp(type, "local_uri")) {
321 res = print_escaped_uri(chan, type, PJSIP_URI_IN_FROMTO_HDR, dlg->local.info->uri,
322 buf, buflen);
323 } else if (!strcmp(type, "local_tag")) {
324 ast_copy_pj_str(buf, &dlg->local.info->tag, buflen);
325 buf_copy = ast_strdupa(buf);
326 ast_escape_quoted(buf_copy, buf, buflen);
327 } else if (!strcmp(type, "remote_uri")) {
328 res = print_escaped_uri(chan, type, PJSIP_URI_IN_FROMTO_HDR,
329 dlg->remote.info->uri, buf, buflen);
330 } else if (!strcmp(type, "remote_tag")) {
331 ast_copy_pj_str(buf, &dlg->remote.info->tag, buflen);
332 buf_copy = ast_strdupa(buf);
333 ast_escape_quoted(buf_copy, buf, buflen);
334 } else if (!strcmp(type, "request_uri")) {
335 if (channel->session->request_uri) {
336 res = print_escaped_uri(chan, type, PJSIP_URI_IN_REQ_URI,
337 channel->session->request_uri, buf, buflen);
338 }
339 } else if (!strcmp(type, "t38state")) {
341 } else if (!strcmp(type, "local_addr")) {
342 RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
343 struct transport_info_data *transport_data;
344
345 datastore = ast_sip_session_get_datastore(channel->session, "transport_info");
346 if (!datastore) {
347 ast_log(AST_LOG_WARNING, "No transport information for channel %s\n", ast_channel_name(chan));
348 return -1;
349 }
350 transport_data = datastore->data;
351
352 if (pj_sockaddr_has_addr(&transport_data->local_addr)) {
353 pj_sockaddr_print(&transport_data->local_addr, buf, buflen, 3);
354 }
355 } else if (!strcmp(type, "remote_addr")) {
356 RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
357 struct transport_info_data *transport_data;
358
359 datastore = ast_sip_session_get_datastore(channel->session, "transport_info");
360 if (!datastore) {
361 ast_log(AST_LOG_WARNING, "No transport information for channel %s\n", ast_channel_name(chan));
362 return -1;
363 }
364 transport_data = datastore->data;
365
366 if (pj_sockaddr_has_addr(&transport_data->remote_addr)) {
367 pj_sockaddr_print(&transport_data->remote_addr, buf, buflen, 3);
368 }
369 } else {
370 ast_log(AST_LOG_WARNING, "Unrecognized argument '%s' for 'pjsip' information\n", type);
371 return -1;
372 }
373
374 return res;
375}
376
377/*! \brief Struct used to push function arguments to task processor */
380 const char *param;
381 const char *type;
382 const char *field;
383 char *buf;
384 size_t len;
385 int ret;
386};
387
388/*! \internal \brief Taskprocessor callback that handles the read on a PJSIP thread */
389static int read_pjsip(void *data)
390{
391 struct pjsip_func_args *func_args = data;
392
393 if (!strcmp(func_args->param, "rtp")) {
394 if (!func_args->session->channel) {
395 func_args->ret = -1;
396 return 0;
397 }
398 func_args->ret = channel_read_rtp(func_args->session->channel, func_args->type,
399 func_args->field, func_args->buf,
400 func_args->len);
401 } else if (!strcmp(func_args->param, "rtcp")) {
402 if (!func_args->session->channel) {
403 func_args->ret = -1;
404 return 0;
405 }
406 func_args->ret = channel_read_rtcp(func_args->session->channel, func_args->type,
407 func_args->field, func_args->buf,
408 func_args->len);
409 } else if (!strcmp(func_args->param, "endpoint")) {
410 if (!func_args->session->endpoint) {
411 ast_log(AST_LOG_WARNING, "Channel %s has no endpoint!\n", func_args->session->channel ?
412 ast_channel_name(func_args->session->channel) : "<unknown>");
413 func_args->ret = -1;
414 return 0;
415 }
416 snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(func_args->session->endpoint));
417 } else if (!strcmp(func_args->param, "contact")) {
418 if (!func_args->session->contact) {
419 return 0;
420 }
421 snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(func_args->session->contact));
422 } else if (!strcmp(func_args->param, "aor")) {
423 if (!func_args->session->aor) {
424 return 0;
425 }
426 snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(func_args->session->aor));
427 } else if (!strcmp(func_args->param, "pjsip")) {
428 if (!func_args->session->channel) {
429 func_args->ret = -1;
430 return 0;
431 }
432 func_args->ret = channel_read_pjsip(func_args->session->channel, func_args->type,
433 func_args->field, func_args->buf,
434 func_args->len);
435 } else {
436 func_args->ret = -1;
437 }
438
439 return 0;
440}
441
442
443int pjsip_acf_channel_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
444{
445 struct pjsip_func_args func_args = { 0, };
446 struct ast_sip_channel_pvt *channel;
447 char *parse = ast_strdupa(data);
448
450 AST_APP_ARG(param);
452 AST_APP_ARG(field);
453 );
454
455 if (!chan) {
456 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
457 return -1;
458 }
459
460 /* Check for zero arguments */
461 if (ast_strlen_zero(parse)) {
462 ast_log(LOG_ERROR, "Cannot call %s without arguments\n", cmd);
463 return -1;
464 }
465
467
468 ast_channel_lock(chan);
469
470 /* Sanity check */
471 if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
472 ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
473 ast_channel_unlock(chan);
474 return 0;
475 }
476
477 channel = ast_channel_tech_pvt(chan);
478 if (!channel) {
479 ast_log(LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
480 ast_channel_unlock(chan);
481 return -1;
482 }
483
484 if (!channel->session) {
485 ast_log(LOG_WARNING, "Channel %s has no session\n", ast_channel_name(chan));
486 ast_channel_unlock(chan);
487 return -1;
488 }
489
490 func_args.session = ao2_bump(channel->session);
491 ast_channel_unlock(chan);
492
493 memset(buf, 0, len);
494
495 func_args.param = args.param;
496 func_args.type = args.type;
497 func_args.field = args.field;
498 func_args.buf = buf;
499 func_args.len = len;
501 ast_log(LOG_WARNING, "Unable to read properties of channel %s: failed to push task\n", ast_channel_name(chan));
502 ao2_ref(func_args.session, -1);
503 return -1;
504 }
505 ao2_ref(func_args.session, -1);
506
507 return func_args.ret;
508}
509
510int pjsip_acf_dial_contacts_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
511{
512 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
513 RAII_VAR(struct ast_str *, dial, NULL, ast_free_ptr);
514 const char *aor_name;
515 char *rest;
516
518 AST_APP_ARG(endpoint_name);
519 AST_APP_ARG(aor_name);
520 AST_APP_ARG(request_user);
521 );
522
524
525 if (ast_strlen_zero(args.endpoint_name)) {
526 ast_log(LOG_WARNING, "An endpoint name must be specified when using the '%s' dialplan function\n", cmd);
527 return -1;
528 } else if (!(endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", args.endpoint_name))) {
529 ast_log(LOG_WARNING, "Specified endpoint '%s' was not found\n", args.endpoint_name);
530 return -1;
531 }
532
533 aor_name = S_OR(args.aor_name, endpoint->aors);
534
535 if (ast_strlen_zero(aor_name)) {
536 ast_log(LOG_WARNING, "No AOR has been provided and no AORs are configured on endpoint '%s'\n", args.endpoint_name);
537 return -1;
538 } else if (!(dial = ast_str_create(len))) {
539 ast_log(LOG_WARNING, "Could not get enough buffer space for dialing contacts\n");
540 return -1;
541 } else if (!(rest = ast_strdupa(aor_name))) {
542 ast_log(LOG_WARNING, "Could not duplicate provided AORs\n");
543 return -1;
544 }
545
546 while ((aor_name = ast_strip(strsep(&rest, ",")))) {
548 RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
549 struct ao2_iterator it_contacts;
550 struct ast_sip_contact *contact;
551
552 if (!aor) {
553 /* If the AOR provided is not found skip it, there may be more */
554 continue;
556 /* No contacts are available, skip it as well */
557 continue;
558 } else if (!ao2_container_count(contacts)) {
559 /* We were given a container but no contacts are in it... */
560 continue;
561 }
562
563 it_contacts = ao2_iterator_init(contacts, 0);
564 for (; (contact = ao2_iterator_next(&it_contacts)); ao2_ref(contact, -1)) {
565 ast_str_append(&dial, -1, "PJSIP/");
566
567 if (!ast_strlen_zero(args.request_user)) {
568 ast_str_append(&dial, -1, "%s@", args.request_user);
569 }
570 ast_str_append(&dial, -1, "%s/%s&", args.endpoint_name, contact->uri);
571 }
572 ao2_iterator_destroy(&it_contacts);
573 }
574
575 /* Trim the '&' at the end off */
576 ast_str_truncate(dial, ast_str_strlen(dial) - 1);
577
579
580 return 0;
581}
582
583/*! \brief Session refresh state information */
585 /*! \brief Created proposed media state */
587};
588
589/*! \brief Destructor for session refresh information */
590static void session_refresh_state_destroy(void *obj)
591{
592 struct session_refresh_state *state = obj;
593
595 ast_free(obj);
596}
597
598/*! \brief Datastore for attaching session refresh state information */
600 .type = "pjsip_session_refresh",
602};
603
604/*! \brief Helper function which retrieves or allocates a session refresh state information datastore */
606{
607 RAII_VAR(struct ast_datastore *, datastore, ast_sip_session_get_datastore(session, "pjsip_session_refresh"), ao2_cleanup);
609
610 /* While the datastore refcount is decremented this is operating in the serializer so it will remain valid regardless */
611 if (datastore) {
612 return datastore->data;
613 }
614
615 if (!(datastore = ast_sip_session_alloc_datastore(&session_refresh_datastore, "pjsip_session_refresh"))
616 || !(datastore->data = ast_calloc(1, sizeof(struct session_refresh_state)))
617 || ast_sip_session_add_datastore(session, datastore)) {
618 return NULL;
619 }
620
621 state = datastore->data;
623 if (!state->media_state) {
624 ast_sip_session_remove_datastore(session, "pjsip_session_refresh");
625 return NULL;
626 }
627 state->media_state->topology = ast_stream_topology_clone(session->endpoint->media.topology);
628 if (!state->media_state->topology) {
629 ast_sip_session_remove_datastore(session, "pjsip_session_refresh");
630 return NULL;
631 }
632
633 datastore->data = state;
634
635 return state;
636}
637
638/*! \brief Struct used to push PJSIP_PARSE_URI function arguments to task processor */
640 const char *uri;
641 const char *type;
642 char *buf;
643 size_t buflen;
644 int ret;
645};
646
647/*! \internal \brief Taskprocessor callback that handles the PJSIP_PARSE_URI on a PJSIP thread */
648static int parse_uri_cb(void *data)
649{
650 struct parse_uri_args *args = data;
651 pj_pool_t *pool;
652 pjsip_name_addr *uri;
653 pjsip_sip_uri *sip_uri;
654 pj_str_t tmp;
655
656 args->ret = 0;
657
658 pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "ParseUri", 128, 128);
659 if (!pool) {
660 ast_log(LOG_ERROR, "Failed to allocate ParseUri endpoint pool.\n");
661 args->ret = -1;
662 return 0;
663 }
664
665 pj_strdup2_with_null(pool, &tmp, args->uri);
666 uri = (pjsip_name_addr *)pjsip_parse_uri(pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR);
667 if (!uri || (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) {
668 ast_log(LOG_WARNING, "Failed to parse URI '%s'\n", args->uri);
669 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
670 args->ret = -1;
671 return 0;
672 }
673
674 if (!strcmp(args->type, "scheme")) {
675 ast_copy_pj_str(args->buf, pjsip_uri_get_scheme(uri), args->buflen);
676 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
677 return 0;
678 } else if (!strcmp(args->type, "display")) {
679 ast_copy_pj_str(args->buf, &uri->display, args->buflen);
680 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
681 return 0;
682 }
683
684 sip_uri = pjsip_uri_get_uri(uri);
685 if (!sip_uri) {
686 ast_log(LOG_ERROR, "Failed to get an URI object for '%s'\n", args->uri);
687 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
688 args->ret = -1;
689 return 0;
690 }
691
692 if (!strcmp(args->type, "user")) {
693 ast_copy_pj_str(args->buf, &sip_uri->user, args->buflen);
694 } else if (!strcmp(args->type, "passwd")) {
695 ast_copy_pj_str(args->buf, &sip_uri->passwd, args->buflen);
696 } else if (!strcmp(args->type, "host")) {
697 ast_copy_pj_str(args->buf, &sip_uri->host, args->buflen);
698 } else if (!strcmp(args->type, "port")) {
699 snprintf(args->buf, args->buflen, "%d", sip_uri->port);
700 } else if (!strcmp(args->type, "user_param")) {
701 ast_copy_pj_str(args->buf, &sip_uri->user_param, args->buflen);
702 } else if (!strcmp(args->type, "method_param")) {
703 ast_copy_pj_str(args->buf, &sip_uri->method_param, args->buflen);
704 } else if (!strcmp(args->type, "transport_param")) {
705 ast_copy_pj_str(args->buf, &sip_uri->transport_param, args->buflen);
706 } else if (!strcmp(args->type, "ttl_param")) {
707 snprintf(args->buf, args->buflen, "%d", sip_uri->ttl_param);
708 } else if (!strcmp(args->type, "lr_param")) {
709 snprintf(args->buf, args->buflen, "%d", sip_uri->lr_param);
710 } else if (!strcmp(args->type, "maddr_param")) {
711 ast_copy_pj_str(args->buf, &sip_uri->maddr_param, args->buflen);
712 } else {
713 ast_log(AST_LOG_WARNING, "Unknown type part '%s' specified\n", args->type);
714 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
715 args->ret = -1;
716 return 0;
717 }
718
719 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
720
721 return 0;
722}
723
724int pjsip_acf_parse_uri_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
725{
726 struct parse_uri_args func_args = { 0, };
727
729 AST_APP_ARG(uri_str);
731 );
732
734
735 if (ast_strlen_zero(args.uri_str)) {
736 ast_log(LOG_WARNING, "An URI must be specified when using the '%s' dialplan function\n", cmd);
737 return -1;
738 }
739
740 if (ast_strlen_zero(args.type)) {
741 ast_log(LOG_WARNING, "A type part of the URI must be specified when using the '%s' dialplan function\n", cmd);
742 return -1;
743 }
744
745 memset(buf, 0, buflen);
746
747 func_args.uri = args.uri_str;
748 func_args.type = args.type;
749 func_args.buf = buf;
750 func_args.buflen = buflen;
752 ast_log(LOG_WARNING, "Unable to parse URI: failed to push task\n");
753 return -1;
754 }
755
756 return func_args.ret;
757}
758
760 size_t len, enum ast_media_type media_type)
761{
762 struct ast_stream_topology *topology;
763 int idx;
764 struct ast_stream *stream = NULL;
765 const struct ast_format_cap *caps;
766 size_t accum = 0;
767
768 if (session->inv_session->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED) {
770
771 /* As we've already answered we need to store our media state until we are ready to send it */
773 if (!state) {
774 return -1;
775 }
776 topology = state->media_state->topology;
777 } else {
778 /* The session is not yet up so we are initially answering or offering */
779 if (!session->pending_media_state->topology) {
780 session->pending_media_state->topology = ast_stream_topology_clone(session->endpoint->media.topology);
781 if (!session->pending_media_state->topology) {
782 return -1;
783 }
784 }
785 topology = session->pending_media_state->topology;
786 }
787
788 /* Find the first suitable stream */
789 for (idx = 0; idx < ast_stream_topology_get_count(topology); ++idx) {
790 stream = ast_stream_topology_get_stream(topology, idx);
791
792 if (ast_stream_get_type(stream) != media_type ||
794 stream = NULL;
795 continue;
796 }
797
798 break;
799 }
800
801 /* If no suitable stream then exit early */
802 if (!stream) {
803 buf[0] = '\0';
804 return 0;
805 }
806
807 caps = ast_stream_get_formats(stream);
808
809 /* Note: buf is not terminated while the string is being built. */
810 for (idx = 0; idx < ast_format_cap_count(caps); ++idx) {
811 struct ast_format *fmt;
812 size_t size;
813
814 fmt = ast_format_cap_get_format(caps, idx);
815
816 /* Add one for a comma or terminator */
817 size = strlen(ast_format_get_name(fmt)) + 1;
818 if (len < size) {
819 ao2_ref(fmt, -1);
820 break;
821 }
822
823 /* Append the format name */
824 strcpy(buf + accum, ast_format_get_name(fmt));/* Safe */
825 ao2_ref(fmt, -1);
826
827 accum += size;
828 len -= size;
829
830 /* The last comma on the built string will be set to the terminator. */
831 buf[accum - 1] = ',';
832 }
833
834 /* Remove the trailing comma or terminate an empty buffer. */
835 buf[accum ? accum - 1 : 0] = '\0';
836 return 0;
837}
838
842 const char *value;
843};
844
845static int media_offer_write_av(void *obj)
846{
847 struct media_offer_data *data = obj;
848 struct ast_stream_topology *topology;
849 struct ast_stream *stream;
850 struct ast_format_cap *caps;
851
852 if (data->session->inv_session->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED) {
854
855 /* As we've already answered we need to store our media state until we are ready to send it */
857 if (!state) {
858 return -1;
859 }
860 topology = state->media_state->topology;
861 } else {
862 /* The session is not yet up so we are initially answering or offering */
863 if (!data->session->pending_media_state->topology) {
865 if (!data->session->pending_media_state->topology) {
866 return -1;
867 }
868 }
869 topology = data->session->pending_media_state->topology;
870 }
871
872 /* XXX This method won't work when it comes time to do multistream support. The proper way to do this
873 * will either be to
874 * a) Alter all media streams of a particular type.
875 * b) Change the dialplan function to be able to specify which stream to alter and alter only that
876 * one stream
877 */
879 if (!stream) {
880 return 0;
881 }
882
884 if (!caps) {
885 return -1;
886 }
887
892 ast_stream_set_formats(stream, caps);
893 ast_stream_set_metadata(stream, "pjsip_session_refresh", "force");
894 ao2_ref(caps, -1);
895
896 return 0;
897}
898
899int pjsip_acf_media_offer_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
900{
901 struct ast_sip_channel_pvt *channel;
902
903 if (!chan) {
904 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
905 return -1;
906 }
907
908 if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
909 ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
910 return -1;
911 }
912
913 channel = ast_channel_tech_pvt(chan);
914
915 if (!strcmp(data, "audio")) {
917 } else if (!strcmp(data, "video")) {
919 } else {
920 /* Ensure that the buffer is empty */
921 buf[0] = '\0';
922 }
923
924 return 0;
925}
926
927int pjsip_acf_media_offer_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
928{
929 struct ast_sip_channel_pvt *channel;
930 struct media_offer_data mdata = {
931 .value = value
932 };
933
934 if (!chan) {
935 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
936 return -1;
937 }
938
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 return -1;
942 }
943
944 channel = ast_channel_tech_pvt(chan);
945 mdata.session = channel->session;
946
947 if (!strcmp(data, "audio")) {
949 } else if (!strcmp(data, "video")) {
951 }
952
954}
955
956int pjsip_acf_dtmf_mode_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
957{
958 struct ast_sip_channel_pvt *channel;
959
960 if (!chan) {
961 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
962 return -1;
963 }
964
965 ast_channel_lock(chan);
966 if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
967 ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
968 ast_channel_unlock(chan);
969 return -1;
970 }
971
972 channel = ast_channel_tech_pvt(chan);
973
974 if (ast_sip_dtmf_to_str(channel->session->dtmf, buf, len) < 0) {
975 ast_log(LOG_WARNING, "Unknown DTMF mode %d on PJSIP channel %s\n", channel->session->dtmf, ast_channel_name(chan));
976 ast_channel_unlock(chan);
977 return -1;
978 }
979
980 ast_channel_unlock(chan);
981 return 0;
982}
983
984int pjsip_acf_moh_passthrough_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
985{
986 struct ast_sip_channel_pvt *channel;
987
988 if (!chan) {
989 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
990 return -1;
991 }
992
993 if (len < 3) {
994 ast_log(LOG_WARNING, "%s: buffer too small\n", cmd);
995 return -1;
996 }
997
998 ast_channel_lock(chan);
999 if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
1000 ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
1001 ast_channel_unlock(chan);
1002 return -1;
1003 }
1004
1005 channel = ast_channel_tech_pvt(chan);
1006 strncpy(buf, AST_YESNO(channel->session->moh_passthrough), len);
1007
1008 ast_channel_unlock(chan);
1009 return 0;
1010}
1011
1015};
1016
1017static int sip_session_response_cb(struct ast_sip_session *session, pjsip_rx_data *rdata)
1018{
1019 struct ast_format *fmt;
1020
1021 if (!session->channel) {
1022 /* Egads! */
1023 return 0;
1024 }
1025
1027 if (!fmt) {
1028 /* No format? That's weird. */
1029 return 0;
1030 }
1031 ast_channel_set_writeformat(session->channel, fmt);
1033 ast_channel_set_readformat(session->channel, fmt);
1035 ao2_ref(fmt, -1);
1036
1037 return 0;
1038}
1039
1040static int dtmf_mode_refresh_cb(void *obj)
1041{
1042 struct refresh_data *data = obj;
1043
1044 if (data->session->inv_session->state == PJSIP_INV_STATE_CONFIRMED) {
1045 ast_debug(3, "Changing DTMF mode on channel %s after OFFER/ANSWER completion. Sending session refresh\n", ast_channel_name(data->session->channel));
1046
1049 } else if (data->session->inv_session->state == PJSIP_INV_STATE_INCOMING) {
1050 ast_debug(3, "Changing DTMF mode on channel %s during OFFER/ANSWER exchange. Updating SDP answer\n", ast_channel_name(data->session->channel));
1052 }
1053
1054 return 0;
1055}
1056
1057int pjsip_acf_dtmf_mode_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1058{
1059 struct ast_sip_channel_pvt *channel;
1060 struct ast_sip_session_media *media;
1061 int dsp_features = 0;
1062 int dtmf = -1;
1063 struct refresh_data rdata = {
1065 };
1066
1067 if (!chan) {
1068 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1069 return -1;
1070 }
1071
1072 ast_channel_lock(chan);
1073 if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
1074 ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
1075 ast_channel_unlock(chan);
1076 return -1;
1077 }
1078
1079 channel = ast_channel_tech_pvt(chan);
1080 rdata.session = channel->session;
1081
1082 dtmf = ast_sip_str_to_dtmf(value);
1083
1084 if (dtmf == -1) {
1085 ast_log(LOG_WARNING, "Cannot set DTMF mode to '%s' on channel '%s' as value is invalid.\n", value,
1086 ast_channel_name(chan));
1087 ast_channel_unlock(chan);
1088 return -1;
1089 }
1090
1091 if (channel->session->dtmf == dtmf) {
1092 /* DTMF mode unchanged, nothing to do! */
1093 ast_channel_unlock(chan);
1094 return 0;
1095 }
1096
1097 channel->session->dtmf = dtmf;
1098
1100
1101 if (media && media->rtp) {
1102 if (channel->session->dtmf == AST_SIP_DTMF_RFC_4733) {
1105 } else if (channel->session->dtmf == AST_SIP_DTMF_INFO) {
1108 } else if (channel->session->dtmf == AST_SIP_DTMF_INBAND) {
1111 } else if (channel->session->dtmf == AST_SIP_DTMF_NONE) {
1114 } else if (channel->session->dtmf == AST_SIP_DTMF_AUTO) {
1116 /* no RFC4733 negotiated, enable inband */
1118 }
1119 } else if (channel->session->dtmf == AST_SIP_DTMF_AUTO_INFO) {
1122 /* if inband, switch to INFO */
1124 }
1125 }
1126 }
1127
1128 if (channel->session->dsp) {
1129 dsp_features = ast_dsp_get_features(channel->session->dsp);
1130 }
1131 if (channel->session->dtmf == AST_SIP_DTMF_INBAND ||
1132 channel->session->dtmf == AST_SIP_DTMF_AUTO) {
1133 dsp_features |= DSP_FEATURE_DIGIT_DETECT;
1134 } else {
1135 dsp_features &= ~DSP_FEATURE_DIGIT_DETECT;
1136 }
1137 if (dsp_features) {
1138 if (!channel->session->dsp) {
1139 if (!(channel->session->dsp = ast_dsp_new())) {
1140 ast_channel_unlock(chan);
1141 return 0;
1142 }
1143 }
1144 ast_dsp_set_features(channel->session->dsp, dsp_features);
1145 } else if (channel->session->dsp) {
1146 ast_dsp_free(channel->session->dsp);
1147 channel->session->dsp = NULL;
1148 }
1149
1150 ast_channel_unlock(chan);
1151
1153}
1154
1155int pjsip_acf_moh_passthrough_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1156{
1157 struct ast_sip_channel_pvt *channel;
1158
1159 if (!chan) {
1160 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1161 return -1;
1162 }
1163
1164 ast_channel_lock(chan);
1165 if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
1166 ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
1167 ast_channel_unlock(chan);
1168 return -1;
1169 }
1170
1171 channel = ast_channel_tech_pvt(chan);
1173
1174 ast_channel_unlock(chan);
1175
1176 return 0;
1177}
1178
1179static int refresh_write_cb(void *obj)
1180{
1181 struct refresh_data *data = obj;
1183
1185 if (!state) {
1186 return -1;
1187 }
1188
1190 sip_session_response_cb, data->method, 1, state->media_state);
1191
1192 state->media_state = NULL;
1193 ast_sip_session_remove_datastore(data->session, "pjsip_session_refresh");
1194
1195 return 0;
1196}
1197
1198int pjsip_acf_session_refresh_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1199{
1200 struct ast_sip_channel_pvt *channel;
1201 struct refresh_data rdata = {
1203 };
1204
1205 if (!chan) {
1206 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1207 return -1;
1208 }
1209
1210 if (ast_channel_state(chan) != AST_STATE_UP) {
1211 ast_log(LOG_WARNING, "'%s' not allowed on unanswered channel '%s'.\n", cmd, ast_channel_name(chan));
1212 return -1;
1213 }
1214
1215 if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
1216 ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
1217 return -1;
1218 }
1219
1220 channel = ast_channel_tech_pvt(chan);
1221 rdata.session = channel->session;
1222
1223 if (!strcmp(value, "invite")) {
1225 } else if (!strcmp(value, "update")) {
1227 }
1228
1230}
1231
1232struct hangup_data {
1235};
1236
1237/*!
1238 * \brief Serializer task to hangup channel
1239 */
1240static int pjsip_hangup(void *obj)
1241{
1242 struct hangup_data *hdata = obj;
1243 pjsip_tx_data *packet = NULL;
1244
1245 if ((hdata->session->inv_session->state != PJSIP_INV_STATE_DISCONNECTED) &&
1246 (pjsip_inv_answer(hdata->session->inv_session, hdata->response_code, NULL, NULL, &packet) == PJ_SUCCESS)) {
1247 ast_sip_session_send_response(hdata->session, packet);
1248 }
1249
1250 return 0;
1251}
1252
1253/*!
1254 * \brief Callback that validates the response code
1255 */
1256static int response_code_validator(const char *channel_name,
1257 const char *response) {
1258 int response_code;
1259
1260 int rc = ast_str_to_int(response, &response_code);
1261 if (rc != 0) {
1262 response_code = ast_sip_str2rc(response);
1263 if (response_code < 0) {
1264 ast_log(LOG_WARNING, "%s: Unrecognized response code parameter '%s'."
1265 " Defaulting to 603 DECLINE\n",
1266 channel_name, response);
1267 return PJSIP_SC_DECLINE;
1268 }
1269 }
1270
1271 if (response_code < 400 || response_code > 699) {
1272 ast_log(LOG_WARNING, "%s: Response code %d is out of range 400 -> 699."
1273 " Defaulting to 603 DECLINE\n",
1274 channel_name, response_code);
1275 return PJSIP_SC_DECLINE;
1276 }
1277 return response_code;
1278}
1279
1280/*!
1281 * \brief Called by pjsip_app_hangup and pjsip_action_hangup
1282 * to actually perform the hangup
1283 */
1285{
1286 struct ast_sip_channel_pvt *channel;
1287 struct hangup_data hdata = { NULL, -1 };
1288 const char *tag = ast_channel_name(chan);
1289
1291
1293 if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
1294 ast_log(LOG_WARNING, "%s: Not a PJSIP channel\n", tag);
1296 return;
1297 }
1298
1299 channel = ast_channel_tech_pvt(chan);
1300 hdata.session = channel->session;
1301
1302 if (hdata.session->inv_session->role != PJSIP_ROLE_UAS || (
1303 hdata.session->inv_session->state != PJSIP_INV_STATE_INCOMING &&
1304 hdata.session->inv_session->state != PJSIP_INV_STATE_EARLY)) {
1305 ast_log(LOG_WARNING, "%s: Not an incoming channel or invalid state '%s'\n",
1306 tag, pjsip_inv_state_name(hdata.session->inv_session->state));
1308 return;
1309 }
1310
1312
1314 pjsip_hangup, &hdata) != 0) {
1315 ast_log(LOG_WARNING, "%s: failed to push hangup task to serializer\n", tag);
1316 }
1317
1318 return;
1319}
1320
1321/*!
1322 * \brief PJSIPHangup Dialplan App
1323 */
1324int pjsip_app_hangup(struct ast_channel *chan, const char *data)
1325{
1326 int response_code;
1327 const char *tag = ast_channel_name(chan);
1328
1329 if (ast_strlen_zero(data)) {
1330 ast_log(LOG_WARNING, "%s: Missing response code parameter\n", tag);
1331 return -1;
1332 }
1333
1335
1337
1338 return -1;
1339}
1340
1341/*!
1342 * \brief PJSIPHangup Manager Action
1343 */
1344int pjsip_action_hangup(struct mansession *s, const struct message *m)
1345{
1346 return ast_manager_hangup_helper(s, m,
1348}
Access Control of various sorts.
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
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
static int tmp()
Definition: bt_open.c:389
enum cc_state state
Definition: ccss.c:393
static const char type[]
Definition: chan_ooh323.c:109
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:2922
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)
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2923
void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format)
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42
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 read_pjsip(void *data)
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_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 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 sip_session_response_cb(struct ast_sip_session *session, pjsip_rx_data *rdata)
static int channel_read_rtp(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen)
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.
static int print_escaped_uri(struct ast_channel *chan, const char *type, pjsip_uri_context_e context, const void *uri, char *buf, size_t size)
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.
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, 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 channel_read_rtcp(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen)
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:1783
#define DSP_FEATURE_DIGIT_DETECT
Definition: dsp.h:28
int ast_dsp_get_features(struct ast_dsp *dsp)
Get features.
Definition: dsp.c:1777
void ast_dsp_set_features(struct ast_dsp *dsp, int features)
Select feature set.
Definition: dsp.c:1768
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition: dsp.c:1758
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
long int flag
Definition: f2c.h:83
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:400
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:320
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:417
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:523
@ 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:395
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:4754
int ast_sip_push_task_wait_serializer(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to the serializer and wait for it to complete.
Definition: res_pjsip.c:2179
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.
char * strsep(char **str, const char *delims)
#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.
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:520
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:2504
int ast_sip_str2rc(const char *name)
Convert name to SIP response code.
Definition: res_pjsip.c:3714
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:2201
@ AST_SIP_CONTACT_FILTER_REACHABLE
Return only reachable or unknown contacts.
Definition: res_pjsip.h:1306
@ AST_SIP_DTMF_NONE
Definition: res_pjsip.h:545
@ AST_SIP_DTMF_AUTO_INFO
Definition: res_pjsip.h:556
@ AST_SIP_DTMF_AUTO
Definition: res_pjsip.h:554
@ AST_SIP_DTMF_INBAND
Definition: res_pjsip.h:550
@ AST_SIP_DTMF_INFO
Definition: res_pjsip.h:552
@ AST_SIP_DTMF_RFC_4733
Definition: res_pjsip.h:548
int ast_sip_str_to_dtmf(const char *dtmf_mode)
Convert the DTMF mode name into an enum.
Definition: res_pjsip.c:2533
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:625
@ AST_SIP_SESSION_REFRESH_METHOD_UPDATE
Definition: res_pjsip.h:629
@ AST_SIP_SESSION_REFRESH_METHOD_INVITE
Definition: res_pjsip.h:627
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_ENABLED
@ T38_REJECTED
@ T38_DISABLED
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.
#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.
Definition: rtp_engine.c:2150
@ AST_RTP_DTMF_MODE_RFC2833
Definition: rtp_engine.h:152
@ AST_RTP_DTMF_MODE_INBAND
Definition: rtp_engine.h:154
@ AST_RTP_DTMF_MODE_NONE
Definition: rtp_engine.h:150
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.
Definition: rtp_engine.c:2136
ast_rtp_instance_stat_field
Definition: rtp_engine.h:168
@ AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS
Definition: rtp_engine.h:174
@ AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT
Definition: rtp_engine.h:176
@ AST_RTP_INSTANCE_STAT_FIELD_QUALITY
Definition: rtp_engine.h:170
@ AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER
Definition: rtp_engine.h:172
@ AST_RTP_INSTANCE_STAT_FIELD_QUALITY_MES
Definition: rtp_engine.h:178
@ AST_RTP_INSTANCE_STAT_ALL
Definition: rtp_engine.h:184
#define ast_rtp_instance_get_remote_address(instance, address)
Get the address of the remote endpoint that we are sending RTP to.
Definition: rtp_engine.h:1238
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.
Definition: rtp_engine.c:2477
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:726
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:664
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.
Definition: rtp_engine.c:2459
@ AST_RTP_PROPERTY_DTMF
Definition: rtp_engine.h:117
#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:2317
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:1853
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:788
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition: stream.c:765
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:667
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:964
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
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#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:2199
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
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
#define AST_YESNO(x)
return Yes or No depending on the argument.
Definition: strings.h:143
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
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:449
unsigned int rxcount
Definition: rtp_engine.h:395
unsigned int local_ssrc
Definition: rtp_engine.h:447
unsigned int rxploss
Definition: rtp_engine.h:419
unsigned int txcount
Definition: rtp_engine.h:393
unsigned int txploss
Definition: rtp_engine.h:417
structure for secure RTP audio
Definition: sdp_srtp.h:38
A SIP address of record.
Definition: res_pjsip.h:478
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:923
An entity with which Asterisk communicates.
Definition: res_pjsip.h:963
struct ast_sip_endpoint_media_configuration media
Definition: res_pjsip.h:996
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_sdp_srtp * srtp
Holds SRTP information.
unsigned int remotely_held
Stream is on hold by remote side.
struct ast_rtp_instance * rtp
RTP instance itself.
struct ast_sockaddr direct_media_addr
Direct media address.
A structure describing a SIP session.
pjsip_uri * request_uri
struct ast_sip_endpoint * endpoint
enum ast_sip_session_t38state t38state
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_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
Definition: chan_pjsip.c:2484
In case you didn't read that giant block of text above the mansession_session struct,...
Definition: manager.c:1777
enum ast_media_type media_type
struct ast_sip_session * session
Struct used to push PJSIP_PARSE_URI function arguments to task processor.
Struct used to push function arguments to task processor.
struct ast_sip_session * session
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
const char * args
#define ast_test_flag(p, flag)
Definition: utils.h:63
#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:941
char * ast_escape_quoted(const char *string, char *outbuf, int buflen)
Escape characters found in a quoted string.
Definition: utils.c:781