Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
core_local.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 * Richard Mudgett <rmudgett@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*!
20 * \file
21 * \brief Local proxy channel driver.
22 *
23 * \author Richard Mudgett <rmudgett@digium.com>
24 *
25 * See Also:
26 * \arg \ref AstCREDITS
27 */
28
29/*** MODULEINFO
30 <support_level>core</support_level>
31 ***/
32
33
34#include "asterisk.h"
35
36/* ------------------------------------------------------------------- */
37
38#include "asterisk/channel.h"
39#include "asterisk/pbx.h"
40#include "asterisk/cli.h"
41#include "asterisk/manager.h"
43#include "asterisk/astobj2.h"
44#include "asterisk/bridge.h"
46#include "asterisk/core_local.h"
47#include "asterisk/stasis.h"
49#include "asterisk/_private.h"
51#include "asterisk/stream.h"
52#include "asterisk/translate.h"
53
54/*** DOCUMENTATION
55 <manager name="LocalOptimizeAway" language="en_US">
56 <since>
57 <version>1.8.0</version>
58 </since>
59 <synopsis>
60 Optimize away a local channel when possible.
61 </synopsis>
62 <syntax>
63 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
64 <parameter name="Channel" required="true">
65 <para>The channel name to optimize away.</para>
66 </parameter>
67 </syntax>
68 <description>
69 <para>A local channel created with "/n" will not automatically optimize away.
70 Calling this command on the local channel will clear that flag and allow
71 it to optimize away if it's bridged or when it becomes bridged.</para>
72 </description>
73 </manager>
74 <managerEvent language="en_US" name="LocalBridge">
75 <managerEventInstance class="EVENT_FLAG_CALL">
76 <since>
77 <version>12.0.0</version>
78 </since>
79 <synopsis>Raised when two halves of a Local Channel form a bridge.</synopsis>
80 <syntax>
81 <channel_snapshot prefix="LocalOne"/>
82 <channel_snapshot prefix="LocalTwo"/>
83 <parameter name="Context">
84 <para>The context in the dialplan that Channel2 starts in.</para>
85 </parameter>
86 <parameter name="Exten">
87 <para>The extension in the dialplan that Channel2 starts in.</para>
88 </parameter>
89 <parameter name="LocalOptimization">
90 <enumlist>
91 <enum name="Yes"/>
92 <enum name="No"/>
93 </enumlist>
94 </parameter>
95 </syntax>
96 </managerEventInstance>
97 </managerEvent>
98 <managerEvent language="en_US" name="LocalOptimizationBegin">
99 <managerEventInstance class="EVENT_FLAG_CALL">
100 <since>
101 <version>12.0.0</version>
102 </since>
103 <synopsis>Raised when two halves of a Local Channel begin to optimize
104 themselves out of the media path.</synopsis>
105 <syntax>
106 <channel_snapshot prefix="LocalOne"/>
107 <channel_snapshot prefix="LocalTwo"/>
108 <channel_snapshot prefix="Source"/>
109 <parameter name="DestUniqueId">
110 <para>The unique ID of the bridge into which the local channel is optimizing.</para>
111 </parameter>
112 <parameter name="Id">
113 <para>Identification for the optimization operation.</para>
114 </parameter>
115 </syntax>
116 <see-also>
117 <ref type="managerEvent">LocalOptimizationEnd</ref>
118 <ref type="manager">LocalOptimizeAway</ref>
119 </see-also>
120 </managerEventInstance>
121 </managerEvent>
122 <managerEvent language="en_US" name="LocalOptimizationEnd">
123 <managerEventInstance class="EVENT_FLAG_CALL">
124 <since>
125 <version>12.0.0</version>
126 </since>
127 <synopsis>Raised when two halves of a Local Channel have finished optimizing
128 themselves out of the media path.</synopsis>
129 <syntax>
130 <channel_snapshot prefix="LocalOne"/>
131 <channel_snapshot prefix="LocalTwo"/>
132 <parameter name="Success">
133 <para>Indicates whether the local optimization succeeded.</para>
134 </parameter>
135 <parameter name="Id">
136 <para>Identification for the optimization operation. Matches the <replaceable>Id</replaceable>
137 from a previous <literal>LocalOptimizationBegin</literal></para>
138 </parameter>
139 </syntax>
140 <see-also>
141 <ref type="managerEvent">LocalOptimizationBegin</ref>
142 <ref type="manager">LocalOptimizeAway</ref>
143 </see-also>
144 </managerEventInstance>
145 </managerEvent>
146 ***/
147
148static const char tdesc[] = "Local Proxy Channel Driver";
149
150static struct ao2_container *locals;
151
152static struct ast_channel *local_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
153static struct ast_channel *local_request_with_stream_topology(const char *type, struct ast_stream_topology *topology, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
154static int local_call(struct ast_channel *ast, const char *dest, int timeout);
155static int local_hangup(struct ast_channel *ast);
156static int local_devicestate(const char *data);
157static void local_optimization_started_cb(struct ast_unreal_pvt *base, struct ast_channel *source,
158 enum ast_unreal_channel_indicator dest, unsigned int id);
159static void local_optimization_finished_cb(struct ast_unreal_pvt *base, int success, unsigned int id);
160static int local_setoption(struct ast_channel *chan, int option, void *data, int datalen);
161
163
164/*!
165 * @{ \brief Define local channel message types.
166 */
169 );
172 );
175 );
176/*! @} */
177
178/*! \brief Callbacks from the unreal core when channel optimization occurs */
181 .optimization_finished = local_optimization_finished_cb,
182};
183
184/* PBX interface structure for channel registration */
186 .type = "Local",
187 .description = tdesc,
188 .requester = local_request,
189 .requester_with_stream_topology = local_request_with_stream_topology,
190 .send_digit_begin = ast_unreal_digit_begin,
191 .send_digit_end = ast_unreal_digit_end,
192 .call = local_call,
193 .hangup = local_hangup,
194 .answer = ast_unreal_answer,
195 .read_stream = ast_unreal_read,
196 .write = ast_unreal_write,
197 .write_stream = ast_unreal_write_stream,
198 .exception = ast_unreal_read,
199 .indicate = ast_unreal_indicate,
200 .fixup = ast_unreal_fixup,
201 .send_html = ast_unreal_sendhtml,
202 .send_text = ast_unreal_sendtext,
203 .devicestate = local_devicestate,
204 .queryoption = ast_unreal_queryoption,
205 .setoption = local_setoption,
206};
207
208/*! What to do with the ;2 channel when ast_call() happens. */
210 /* The ast_call() will run dialplan on the ;2 channel. */
212 /* The ast_call() will impart the ;2 channel into a bridge. */
214 /* The ast_call() will masquerade the ;2 channel into a channel. */
216};
217
218/*! Join a bridge on ast_call() parameters. */
220 /*! Bridge to join. */
222 /*! Channel to swap with when joining bridge. */
224 /*! Features that are specific to this channel when pushed into the bridge. */
226};
227
228/*!
229 * \brief the local pvt structure for all channels
230 *
231 * The local channel pvt has two ast_chan objects - the "owner" and the "next channel", the outbound channel
232 *
233 * ast_chan owner -> local_pvt -> ast_chan chan
234 */
235struct local_pvt {
236 /*! Unreal channel driver base class values. */
238 /*! Additional action arguments */
239 union {
240 /*! Make ;2 join a bridge on ast_call(). */
242 /*! Make ;2 masquerade into this channel on ast_call(). */
245 /*! What to do with the ;2 channel on ast_call(). */
247 /*! Context to call */
249 /*! Extension to call */
251};
252
253void ast_local_lock_all(struct ast_channel *chan, void **tech_pvt,
254 struct ast_channel **base_chan, struct ast_channel **base_owner)
255{
256 struct local_pvt *p = ast_channel_tech_pvt(chan);
257
258 *tech_pvt = NULL;
259 *base_chan = NULL;
260 *base_owner = NULL;
261
262 if (p) {
263 *tech_pvt = ao2_bump(p);
264 ast_unreal_lock_all(&p->base, base_chan, base_owner);
265 }
266}
267
268void ast_local_unlock_all(void *tech_pvt, struct ast_channel *base_chan,
269 struct ast_channel *base_owner)
270{
271 if (base_chan) {
272 ast_channel_unlock(base_chan);
273 ast_channel_unref(base_chan);
274 }
275
276 if (base_owner) {
277 ast_channel_unlock(base_owner);
278 ast_channel_unref(base_owner);
279 }
280
281 if (tech_pvt) {
282 struct local_pvt *p = tech_pvt;
283 ao2_unlock(&p->base);
284 ao2_ref(tech_pvt, -1);
285 }
286}
287
289{
290 struct local_pvt *p = ast_channel_tech_pvt(ast);
291 struct local_pvt *found;
292 struct ast_channel *peer;
293
294 if (!p) {
295 return NULL;
296 }
297
298 found = p ? ao2_find(locals, p, 0) : NULL;
299 if (!found) {
300 /* ast is either not a local channel or it has already been hungup */
301 return NULL;
302 }
303 ao2_lock(found);
304 if (ast == p->base.owner) {
305 peer = p->base.chan;
306 } else if (ast == p->base.chan) {
307 peer = p->base.owner;
308 } else {
309 peer = NULL;
310 }
311 if (peer) {
312 ast_channel_ref(peer);
313 }
314 ao2_unlock(found);
315 ao2_ref(found, -1);
316 return peer;
317}
318
319/*! \brief Adds devicestate to local channels */
320static int local_devicestate(const char *data)
321{
322 int is_inuse = 0;
323 int res = AST_DEVICE_INVALID;
324 char *exten = ast_strdupa(data);
325 char *context;
326 char *opts;
327 struct local_pvt *lp;
328 struct ao2_iterator it;
329
330 context = strchr(exten, '@');
331 if (!context) {
333 "Someone used Local/%s somewhere without a @context. This is bad.\n", data);
334 return AST_DEVICE_INVALID;
335 }
336 *context++ = '\0';
337
338 /* Strip options if they exist.
339 * However, don't strip '/' before an '@' (exten could contain slashes).
340 * So only start looking for '/' in context, because options would be past
341 * this point if they exist, but anything before would be a '/' in the exten,
342 * not options. */
343 opts = strchr(context, '/');
344 if (opts) {
345 *opts = '\0';
346 }
347
348 it = ao2_iterator_init(locals, 0);
349 for (; (lp = ao2_iterator_next(&it)); ao2_ref(lp, -1)) {
350 ao2_lock(lp);
351 if (!strcmp(exten, lp->exten)
352 && !strcmp(context, lp->context)) {
354 if (lp->base.owner
356 is_inuse = 1;
357 }
358 }
359 ao2_unlock(lp);
360 if (is_inuse) {
361 res = AST_DEVICE_INUSE;
362 ao2_ref(lp, -1);
363 break;
364 }
365 }
367
368 if (res == AST_DEVICE_INVALID) {
369 ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
370 if (ast_exists_extension(NULL, context, exten, 1, NULL)) {
372 }
373 }
374
375 return res;
376}
377
379 struct ast_json *json_object)
380{
381 struct ast_multi_channel_blob *payload;
382 RAII_VAR(struct ast_channel_snapshot *, local_one_snapshot, NULL, ao2_cleanup);
383 RAII_VAR(struct ast_channel_snapshot *, local_two_snapshot, NULL, ao2_cleanup);
384
386 if (!local_one_snapshot) {
387 return NULL;
388 }
389
391 if (!local_two_snapshot) {
392 return NULL;
393 }
394
395 payload = ast_multi_channel_blob_create(json_object);
396 if (!payload) {
397 return NULL;
398 }
399 ast_multi_channel_blob_add_channel(payload, "1", local_one_snapshot);
400 ast_multi_channel_blob_add_channel(payload, "2", local_two_snapshot);
401
402 return payload;
403}
404
405/*! \brief Callback for \ref ast_unreal_pvt_callbacks \p optimization_started */
406static void local_optimization_started_cb(struct ast_unreal_pvt *base, struct ast_channel *source,
407 enum ast_unreal_channel_indicator dest, unsigned int id)
408{
409 RAII_VAR(struct ast_json *, json_object, ast_json_null(), ast_json_unref);
410 RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
411 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
412 struct local_pvt *p = (struct local_pvt *)base;
413
415 return;
416 }
417
418 json_object = ast_json_pack("{s: i, s: I}",
419 "dest", dest, "id", (ast_json_int_t)id);
420
421 if (!json_object) {
422 return;
423 }
424
425 payload = local_channel_optimization_blob(p, json_object);
426 if (!payload) {
427 return;
428 }
429
430 if (source) {
431 RAII_VAR(struct ast_channel_snapshot *, source_snapshot, NULL, ao2_cleanup);
432 source_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(source));
433 if (!source_snapshot) {
434 return;
435 }
436
437 ast_multi_channel_blob_add_channel(payload, "source", source_snapshot);
438 }
439
441 if (!msg) {
442 return;
443 }
444
446}
447
448/*! \brief Callback for \ref ast_unreal_pvt_callbacks \p optimization_finished */
449static void local_optimization_finished_cb(struct ast_unreal_pvt *base, int success, unsigned int id)
450{
451 RAII_VAR(struct ast_json *, json_object, ast_json_null(), ast_json_unref);
452 RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
453 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
454 struct local_pvt *p = (struct local_pvt *)base;
455
457 return;
458 }
459
460 json_object = ast_json_pack("{s: i, s: I}", "success", success, "id", (ast_json_int_t)id);
461
462 if (!json_object) {
463 return;
464 }
465
466 payload = local_channel_optimization_blob(p, json_object);
467 if (!payload) {
468 return;
469 }
470
472 if (!msg) {
473 return;
474 }
475
477}
478
480{
482 struct ast_json *blob = ast_multi_channel_blob_get_json(obj);
483 struct ast_channel_snapshot *local_snapshot_one;
484 struct ast_channel_snapshot *local_snapshot_two;
485 RAII_VAR(struct ast_str *, local_channel_one, NULL, ast_free);
486 RAII_VAR(struct ast_str *, local_channel_two, NULL, ast_free);
487 RAII_VAR(struct ast_str *, event_buffer, NULL, ast_free);
488 const char *event;
489
490 local_snapshot_one = ast_multi_channel_blob_get_channel(obj, "1");
491 local_snapshot_two = ast_multi_channel_blob_get_channel(obj, "2");
492 if (!local_snapshot_one || !local_snapshot_two) {
493 return NULL;
494 }
495
496 event_buffer = ast_str_create(1024);
497 local_channel_one = ast_manager_build_channel_state_string_prefix(local_snapshot_one, "LocalOne");
498 local_channel_two = ast_manager_build_channel_state_string_prefix(local_snapshot_two, "LocalTwo");
499 if (!event_buffer || !local_channel_one || !local_channel_two) {
500 return NULL;
501 }
502
504 struct ast_channel_snapshot *source_snapshot;
505 RAII_VAR(struct ast_str *, source_str, NULL, ast_free);
506 const char *dest_uniqueid;
507
508 source_snapshot = ast_multi_channel_blob_get_channel(obj, "source");
509 if (source_snapshot) {
510 source_str = ast_manager_build_channel_state_string_prefix(source_snapshot, "Source");
511 if (!source_str) {
512 return NULL;
513 }
514 }
515
516 dest_uniqueid = ast_json_object_get(blob, "dest") == AST_UNREAL_OWNER ?
517 local_snapshot_one->base->uniqueid : local_snapshot_two->base->uniqueid;
518
519 event = "LocalOptimizationBegin";
520 if (source_str) {
521 ast_str_append(&event_buffer, 0, "%s", ast_str_buffer(source_str));
522 }
523 ast_str_append(&event_buffer, 0, "DestUniqueId: %s\r\n", dest_uniqueid);
524 ast_str_append(&event_buffer, 0, "Id: %u\r\n", (unsigned int) ast_json_integer_get(ast_json_object_get(blob, "id")));
526 event = "LocalOptimizationEnd";
527 ast_str_append(&event_buffer, 0, "Success: %s\r\n", ast_json_integer_get(ast_json_object_get(blob, "success")) ? "Yes" : "No");
528 ast_str_append(&event_buffer, 0, "Id: %u\r\n", (unsigned int) ast_json_integer_get(ast_json_object_get(blob, "id")));
530 event = "LocalBridge";
531 ast_str_append(&event_buffer, 0, "Context: %s\r\n", ast_json_string_get(ast_json_object_get(blob, "context")));
532 ast_str_append(&event_buffer, 0, "Exten: %s\r\n", ast_json_string_get(ast_json_object_get(blob, "exten")));
533 ast_str_append(&event_buffer, 0, "LocalOptimization: %s\r\n", ast_json_is_true(ast_json_object_get(blob, "can_optimize")) ? "Yes" : "No");
534 } else {
535 return NULL;
536 }
537
539 "%s"
540 "%s"
541 "%s",
542 ast_str_buffer(local_channel_one),
543 ast_str_buffer(local_channel_two),
544 ast_str_buffer(event_buffer));
545}
546
547/*!
548 * \internal
549 * \brief Post the \ref ast_local_bridge_type \ref stasis message
550 * \since 12.0.0
551 *
552 * \param p local_pvt to raise the local bridge message
553 */
555{
556 RAII_VAR(struct ast_multi_channel_blob *, multi_blob, NULL, ao2_cleanup);
557 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
558 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
559 RAII_VAR(struct ast_channel_snapshot *, one_snapshot, NULL, ao2_cleanup);
560 RAII_VAR(struct ast_channel_snapshot *, two_snapshot, NULL, ao2_cleanup);
561 struct ast_channel *owner;
562 struct ast_channel *chan;
563
564 if (!ast_local_bridge_type()) {
565 return;
566 }
567
568 ast_unreal_lock_all(&p->base, &chan, &owner);
569
570 blob = ast_json_pack("{s: s, s: s, s: b}",
571 "context", p->context,
572 "exten", p->exten,
573 "can_optimize", !ast_test_flag(&p->base, AST_UNREAL_NO_OPTIMIZATION));
574 if (!blob) {
575 goto end;
576 }
577
578 multi_blob = ast_multi_channel_blob_create(blob);
579 if (!multi_blob) {
580 goto end;
581 }
582
584 if (!one_snapshot) {
585 goto end;
586 }
587
589 if (!two_snapshot) {
590 goto end;
591 }
592
593 ast_multi_channel_blob_add_channel(multi_blob, "1", one_snapshot);
594 ast_multi_channel_blob_add_channel(multi_blob, "2", two_snapshot);
595
596 msg = stasis_message_create(ast_local_bridge_type(), multi_blob);
597 if (!msg) {
598 goto end;
599 }
600
602
603end:
604 ast_channel_unlock(owner);
605 ast_channel_unref(owner);
606
607 ast_channel_unlock(chan);
608 ast_channel_unref(chan);
609
610 ao2_unlock(&p->base);
611}
612
613int ast_local_setup_bridge(struct ast_channel *ast, struct ast_bridge *bridge, struct ast_channel *swap, struct ast_bridge_features *features)
614{
615 struct local_pvt *p;
616 struct local_pvt *found;
617 int res = -1;
618
619 /* Sanity checks. */
620 if (!ast || !bridge) {
622 return -1;
623 }
624
625 ast_channel_lock(ast);
626 p = ast_channel_tech_pvt(ast);
628
629 found = p ? ao2_find(locals, p, 0) : NULL;
630 if (found) {
631 ao2_lock(found);
632 if (found->type == LOCAL_CALL_ACTION_DIALPLAN
633 && found->base.owner
634 && found->base.chan
636 ao2_ref(bridge, +1);
637 if (swap) {
638 ast_channel_ref(swap);
639 }
641 found->action.bridge.join = bridge;
642 found->action.bridge.swap = swap;
643 found->action.bridge.features = features;
644 res = 0;
645 } else {
647 }
648 ao2_unlock(found);
649 ao2_ref(found, -1);
650 }
651
652 return res;
653}
654
656{
657 struct local_pvt *p;
658 struct local_pvt *found;
659 int res = -1;
660
661 /* Sanity checks. */
662 if (!ast || !masq) {
663 return -1;
664 }
665
666 ast_channel_lock(ast);
667 p = ast_channel_tech_pvt(ast);
669
670 found = p ? ao2_find(locals, p, 0) : NULL;
671 if (found) {
672 ao2_lock(found);
673 if (found->type == LOCAL_CALL_ACTION_DIALPLAN
674 && found->base.owner
675 && found->base.chan
679 found->action.masq = masq;
680 res = 0;
681 }
682 ao2_unlock(found);
683 ao2_ref(found, -1);
684 }
685
686 return res;
687}
688
689/*! \brief Initiate new call, part of PBX interface
690 * dest is the dial string */
691static int local_call(struct ast_channel *ast, const char *dest, int timeout)
692{
693 struct local_pvt *p = ast_channel_tech_pvt(ast);
694 int pvt_locked = 0;
695
696 struct ast_channel *owner = NULL;
697 struct ast_channel *chan = NULL;
698 int res;
699 char *reduced_dest = ast_strdupa(dest);
700 char *slash;
701 const char *chan_cid;
702
703 if (!p) {
704 return -1;
705 }
706
707 /* since we are letting go of channel locks that were locked coming into
708 * this function, then we need to give the tech pvt a ref */
709 ao2_ref(p, 1);
711
712 ast_unreal_lock_all(&p->base, &chan, &owner);
713 pvt_locked = 1;
714
715 if (owner != ast) {
716 res = -1;
717 goto return_cleanup;
718 }
719
720 if (!owner || !chan) {
721 res = -1;
722 goto return_cleanup;
723 }
724
725 ast_unreal_call_setup(owner, chan);
726
727 /*
728 * If the local channel has /n on the end of it, we need to lop
729 * that off for our argument to setting up the CC_INTERFACES
730 * variable.
731 */
732 if ((slash = strrchr(reduced_dest, '/'))) {
733 *slash = '\0';
734 }
735 ast_set_cc_interfaces_chanvar(chan, reduced_dest);
736
737 ao2_unlock(p);
738 pvt_locked = 0;
739
740 ast_channel_unlock(owner);
741
742 chan_cid = S_COR(ast_channel_caller(chan)->id.number.valid,
743 ast_channel_caller(chan)->id.number.str, NULL);
744 if (chan_cid) {
745 chan_cid = ast_strdupa(chan_cid);
746 }
747 ast_channel_unlock(chan);
748
749 res = -1;
750 switch (p->type) {
752 if (!ast_exists_extension(NULL, p->context, p->exten, 1, chan_cid)) {
753 ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n",
754 p->exten, p->context);
755 } else {
757
758 /* Start switch on sub channel */
759 res = ast_pbx_start(chan);
760 }
761 break;
764 ast_answer(chan);
767 ao2_ref(p->action.bridge.join, -1);
768 p->action.bridge.join = NULL;
770 p->action.bridge.swap = NULL;
772 break;
775 ast_answer(chan);
776 res = ast_channel_move(p->action.masq, chan);
777 if (!res) {
778 /* Chan is now an orphaned zombie. Destroy it. */
779 ast_hangup(chan);
780 }
782 break;
783 }
784 if (!res) {
785 ao2_lock(p);
787 ao2_unlock(p);
788 }
789
790 /* we already unlocked them, clear them here so the cleanup label won't touch them. */
791 owner = ast_channel_unref(owner);
792 chan = ast_channel_unref(chan);
793
794return_cleanup:
795 if (p) {
796 if (pvt_locked) {
797 ao2_unlock(p);
798 }
799 ao2_ref(p, -1);
800 }
801 if (chan) {
802 ast_channel_unlock(chan);
803 ast_channel_unref(chan);
804 }
805
806 /*
807 * owner is supposed to be == to ast, if it is, don't unlock it
808 * because ast must exit locked
809 */
810 if (owner) {
811 if (owner != ast) {
812 ast_channel_unlock(owner);
813 ast_channel_lock(ast);
814 }
815 ast_channel_unref(owner);
816 } else {
817 /* we have to exit with ast locked */
818 ast_channel_lock(ast);
819 }
820
821 return res;
822}
823
824/*! \brief Hangup a call through the local proxy channel */
825static int local_hangup(struct ast_channel *ast)
826{
827 struct local_pvt *p = ast_channel_tech_pvt(ast);
828 int res;
829
830 if (!p) {
831 return -1;
832 }
833
834 /* give the pvt a ref to fulfill calling requirements. */
835 ao2_ref(p, +1);
836 res = ast_unreal_hangup(&p->base, ast);
837 if (!res) {
838 int unlink;
839
840 ao2_lock(p);
841 unlink = !p->base.owner && !p->base.chan;
842 ao2_unlock(p);
843 if (unlink) {
844 ao2_unlink(locals, p);
845 }
846 }
847 ao2_ref(p, -1);
848
849 return res;
850}
851
852/*!
853 * \internal
854 * \brief struct local_pvt destructor.
855 *
856 * \param vdoomed Object to destroy.
857 */
858static void local_pvt_destructor(void *vdoomed)
859{
860 struct local_pvt *doomed = vdoomed;
861
862 switch (doomed->type) {
864 break;
866 ao2_cleanup(doomed->action.bridge.join);
867 ao2_cleanup(doomed->action.bridge.swap);
869 break;
871 ao2_cleanup(doomed->action.masq);
872 break;
873 }
874 ast_unreal_destructor(&doomed->base);
875}
876
877/*! \brief Create a call structure */
878static struct local_pvt *local_alloc(const char *data, struct ast_stream_topology *topology)
879{
880 struct local_pvt *pvt;
881 char *parse;
882 char *context;
883 char *opts;
884
885 pvt = (struct local_pvt *) ast_unreal_alloc_stream_topology(sizeof(*pvt), local_pvt_destructor, topology);
886 if (!pvt) {
887 return NULL;
888 }
890
891 parse = ast_strdupa(data);
892
893 /*
894 * Local channels intercept MOH by default.
895 *
896 * This is a silly default because it represents state held by
897 * the local channels. Unless local channel optimization is
898 * disabled, the state will disappear when the local channels
899 * optimize out.
900 */
902
903 /* Look for options.
904 * Slashes can appear in channel names, so options are after the last match. */
905 if ((opts = strrchr(parse, '/'))) {
906 *opts++ = '\0';
907 if (strchr(opts, 'n')) {
909 }
910 if (strchr(opts, 'j')) {
913 } else {
914 ast_log(LOG_ERROR, "You must use the 'n' option with the 'j' option to enable the jitter buffer\n");
915 }
916 }
917 if (strchr(opts, 'm')) {
919 }
920 }
921
922 /* Look for a context */
923 if ((context = strchr(parse, '@'))) {
924 *context++ = '\0';
925 }
926
927 ast_copy_string(pvt->context, S_OR(context, "default"), sizeof(pvt->context));
928 ast_copy_string(pvt->exten, parse, sizeof(pvt->exten));
929 snprintf(pvt->base.name, sizeof(pvt->base.name), "%s@%s", pvt->exten, pvt->context);
930
931 return pvt; /* this is returned with a ref */
932}
933
934/*! \brief Part of PBX interface */
935static struct ast_channel *local_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
936{
937 struct ast_stream_topology *topology;
938 struct ast_channel *chan;
939
941 if (!topology) {
942 return NULL;
943 }
944
945 chan = local_request_with_stream_topology(type, topology, assignedids, requestor, data, cause);
946
947 ast_stream_topology_free(topology);
948
949 return chan;
950}
951
952/*! \brief Part of PBX interface */
953static struct ast_channel *local_request_with_stream_topology(const char *type, struct ast_stream_topology *topology, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
954{
955 struct ast_stream_topology *audio_filtered_topology;
956 int i;
957 struct local_pvt *p;
958 struct ast_channel *chan;
960
961 /* Create a copy of the requested topology as we don't have ownership over
962 * the one that is passed in.
963 */
964 audio_filtered_topology = ast_stream_topology_clone(topology);
965 if (!audio_filtered_topology) {
966 return NULL;
967 }
968
969 /* Some users of Local channels request every known format in the
970 * universe. The core itself automatically pruned this list down to a single
971 * "best" format for audio in non-multistream. We replicate the logic here to
972 * do the same thing.
973 */
974 for (i = 0; i < ast_stream_topology_get_count(audio_filtered_topology); ++i) {
975 struct ast_stream *stream;
976 int res;
977 struct ast_format *tmp_fmt = NULL;
978 struct ast_format *best_audio_fmt = NULL;
979 struct ast_format_cap *caps;
980
981 stream = ast_stream_topology_get_stream(audio_filtered_topology, i);
982
985 continue;
986 }
987
988 /* Respect the immutable state of formats on the stream and create a new
989 * format capabilities to replace the existing one.
990 */
992 if (!caps) {
993 ao2_ref(audio_filtered_topology, -1);
994 return NULL;
995 }
996
997 /* The ast_translator_best_choice function treats both caps as const
998 * but does not declare it in the API.
999 */
1001 &tmp_fmt, &best_audio_fmt);
1002 if (res < 0) {
1003 struct ast_str *tech_codecs = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
1004 struct ast_str *request_codecs = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
1005
1006 ast_log(LOG_WARNING, "No translator path exists for channel type %s (native %s) to %s\n", type,
1008 ast_format_cap_get_names(ast_stream_get_formats(stream), &request_codecs));
1009
1010 /* If there are no formats then we abort */
1011 ao2_ref(caps, -1);
1012 ao2_ref(audio_filtered_topology, -1);
1013 return NULL;
1014 }
1015
1016 ast_format_cap_append(caps, best_audio_fmt, 0);
1017 ast_stream_set_formats(stream, caps);
1018
1019 ao2_ref(caps, -1);
1020 ao2_ref(tmp_fmt, -1);
1021 ao2_ref(best_audio_fmt, -1);
1022 }
1023
1024 /* Allocate a new private structure and then Asterisk channels */
1025 p = local_alloc(data, audio_filtered_topology);
1026 ao2_ref(audio_filtered_topology, -1);
1027 if (!p) {
1028 return NULL;
1029 }
1032 p->exten, p->context, assignedids, requestor, callid);
1033 if (chan) {
1034 ao2_link(locals, p);
1035 }
1036 ao2_ref(p, -1); /* kill the ref from the alloc */
1037
1038 return chan;
1039}
1040
1041
1042/*! \brief CLI command "local show channels" */
1043static char *locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1044{
1045 struct local_pvt *p;
1046 struct ao2_iterator it;
1047
1048 switch (cmd) {
1049 case CLI_INIT:
1050 e->command = "local show channels";
1051 e->usage =
1052 "Usage: local show channels\n"
1053 " Provides summary information on active local proxy channels.\n";
1054 return NULL;
1055 case CLI_GENERATE:
1056 return NULL;
1057 }
1058
1059 if (a->argc != 3) {
1060 return CLI_SHOWUSAGE;
1061 }
1062
1063 if (ao2_container_count(locals) == 0) {
1064 ast_cli(a->fd, "No local channels in use\n");
1065 return RESULT_SUCCESS;
1066 }
1067
1068 it = ao2_iterator_init(locals, 0);
1069 while ((p = ao2_iterator_next(&it))) {
1070 ao2_lock(p);
1071 ast_cli(a->fd, "%s -- %s\n",
1072 p->base.owner ? ast_channel_name(p->base.owner) : "<unowned>",
1073 p->base.name);
1074 ao2_unlock(p);
1075 ao2_ref(p, -1);
1076 }
1078
1079 return CLI_SUCCESS;
1080}
1081
1082static struct ast_cli_entry cli_local[] = {
1083 AST_CLI_DEFINE(locals_show, "List status of local channels"),
1084};
1085
1086static int manager_optimize_away(struct mansession *s, const struct message *m)
1087{
1088 const char *channel;
1089 struct local_pvt *p;
1090 struct local_pvt *found;
1091 struct ast_channel *chan;
1092
1093 channel = astman_get_header(m, "Channel");
1094 if (ast_strlen_zero(channel)) {
1095 astman_send_error(s, m, "'Channel' not specified.");
1096 return 0;
1097 }
1098
1099 chan = ast_channel_get_by_name(channel);
1100 if (!chan) {
1101 astman_send_error(s, m, "Channel does not exist.");
1102 return 0;
1103 }
1104
1105 p = ast_channel_tech_pvt(chan);
1106 ast_channel_unref(chan);
1107
1108 found = p ? ao2_find(locals, p, 0) : NULL;
1109 if (found) {
1110 ao2_lock(found);
1112 ao2_unlock(found);
1113 ao2_ref(found, -1);
1114 astman_send_ack(s, m, "Queued channel to be optimized away");
1115 } else {
1116 astman_send_error(s, m, "Unable to find channel");
1117 }
1118
1119 return 0;
1120}
1121
1122
1123static int locals_cmp_cb(void *obj, void *arg, int flags)
1124{
1125 return (obj == arg) ? CMP_MATCH : 0;
1126}
1127
1128/*!
1129 * \internal
1130 * \brief Shutdown the local proxy channel.
1131 * \since 12.0.0
1132 */
1133static void local_shutdown(void)
1134{
1135 /* First, take us out of the channel loop */
1137 ast_manager_unregister("LocalOptimizeAway");
1139
1140 ao2_ref(locals, -1);
1141 locals = NULL;
1142
1145
1149}
1150
1152{
1154 return -1;
1155 }
1156
1158 return -1;
1159 }
1160
1162 return -1;
1163 }
1164
1166 return -1;
1167 }
1169
1171 if (!locals) {
1172 return -1;
1173 }
1174
1175 /* Make sure we can register our channel type */
1177 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
1178
1179 return -1;
1180 }
1183
1185 return 0;
1186}
1187
1188int local_setoption(struct ast_channel *ast, int option, void *data, int datalen)
1189{
1190 switch (option) {
1193 return 0; /* local calls (like forwardings) are secure always */
1194 default:
1195 return ast_unreal_setoption(ast, option, data, datalen);
1196 }
1197}
Prototypes for public functions only of internal interest,.
@ AST_JB_ENABLED
Definition: abstract_jb.h:45
Asterisk main include file. File version handling, generic pbx functions.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_log
Definition: astobj2.c:42
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ CMP_MATCH
Definition: astobj2.h:1027
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#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.
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
Bridging API.
int ast_bridge_impart(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features, enum ast_bridge_impart_flags flags) attribute_warn_unused_result
Impart a channel to a bridge (non-blocking)
Definition: bridge.c:1947
@ AST_BRIDGE_IMPART_CHAN_INDEPENDENT
Definition: bridge.h:594
void ast_bridge_features_destroy(struct ast_bridge_features *features)
Destroy an allocated bridge features struct.
Definition: bridge.c:3743
int ast_set_cc_interfaces_chanvar(struct ast_channel *chan, const char *const extension)
Set the CC_INTERFACES channel variable for a channel using an.
Definition: ccss.c:3639
static const char type[]
Definition: chan_ooh323.c:109
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)
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2570
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
#define ast_channel_lock(chan)
Definition: channel.h:2970
void ast_channel_unregister(const struct ast_channel_tech *tech)
Unregister a channel technology.
Definition: channel.c:570
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2995
const char * ast_channel_uniqueid(const struct ast_channel *chan)
int ast_channel_move(struct ast_channel *dest, struct ast_channel *source)
Move a channel from its current location to a new location.
Definition: channel.c:10692
int ast_channel_register(const struct ast_channel_tech *tech)
Register a channel technology (a new channel driver) Called by a channel module to register the kind ...
Definition: channel.c:539
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:3006
#define AST_MAX_CONTEXT
Definition: channel.h:135
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1481
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2834
#define ast_channel_unlock(chan)
Definition: channel.h:2971
#define AST_MAX_EXTENSION
Definition: channel.h:134
@ AST_STATE_RING
Definition: channelstate.h:40
@ AST_STATE_DOWN
Definition: channelstate.h:36
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
#define RESULT_SUCCESS
Definition: cli.h:40
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
@ AST_MEDIA_TYPE_AUDIO
Definition: codec.h:32
@ AST_MEDIA_TYPE_UNKNOWN
Definition: codec.h:31
static int manager_optimize_away(struct mansession *s, const struct message *m)
Definition: core_local.c:1086
struct ast_channel * ast_local_get_peer(struct ast_channel *ast)
Get the other local channel in the pair.
Definition: core_local.c:288
static int locals_cmp_cb(void *obj, void *arg, int flags)
Definition: core_local.c:1123
static int local_call(struct ast_channel *ast, const char *dest, int timeout)
Initiate new call, part of PBX interface dest is the dial string.
Definition: core_local.c:691
void ast_local_unlock_all(void *tech_pvt, struct ast_channel *base_chan, struct ast_channel *base_owner)
Remove a reference to the given local channel's private tech, unlock the given local channel's privat...
Definition: core_local.c:268
static int local_devicestate(const char *data)
Adds devicestate to local channels.
Definition: core_local.c:320
static void local_pvt_destructor(void *vdoomed)
Definition: core_local.c:858
int ast_local_setup_bridge(struct ast_channel *ast, struct ast_bridge *bridge, struct ast_channel *swap, struct ast_bridge_features *features)
Setup the outgoing local channel to join a bridge on ast_call().
Definition: core_local.c:613
STASIS_MESSAGE_TYPE_DEFN(ast_local_bridge_type,.to_ami=local_message_to_ami,)
Define local channel message types.
static struct ast_channel * local_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
Part of PBX interface.
Definition: core_local.c:935
static void local_optimization_started_cb(struct ast_unreal_pvt *base, struct ast_channel *source, enum ast_unreal_channel_indicator dest, unsigned int id)
Callback for ast_unreal_pvt_callbacks optimization_started.
Definition: core_local.c:406
static struct ast_channel_tech local_tech
Definition: core_local.c:185
static void publish_local_bridge_message(struct local_pvt *p)
Definition: core_local.c:554
static const char tdesc[]
Definition: core_local.c:148
int ast_local_init(void)
Initialize the local proxy channel.
Definition: core_local.c:1151
void ast_local_lock_all(struct ast_channel *chan, void **tech_pvt, struct ast_channel **base_chan, struct ast_channel **base_owner)
Add a reference to the local channel's private tech, lock the local channel's private base,...
Definition: core_local.c:253
static int local_setoption(struct ast_channel *chan, int option, void *data, int datalen)
Definition: core_local.c:1188
static struct ast_manager_event_blob * local_message_to_ami(struct stasis_message *msg)
Definition: core_local.c:479
static struct local_pvt * local_alloc(const char *data, struct ast_stream_topology *topology)
Create a call structure.
Definition: core_local.c:878
static struct ast_cli_entry cli_local[]
Definition: core_local.c:1082
static void local_shutdown(void)
Definition: core_local.c:1133
int ast_local_setup_masquerade(struct ast_channel *ast, struct ast_channel *masq)
Setup the outgoing local channel to masquerade into a channel on ast_call().
Definition: core_local.c:655
static struct ast_multi_channel_blob * local_channel_optimization_blob(struct local_pvt *p, struct ast_json *json_object)
Definition: core_local.c:378
static void local_optimization_finished_cb(struct ast_unreal_pvt *base, int success, unsigned int id)
Callback for ast_unreal_pvt_callbacks optimization_finished.
Definition: core_local.c:449
static char * locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command "local show channels".
Definition: core_local.c:1043
static int local_hangup(struct ast_channel *ast)
Hangup a call through the local proxy channel.
Definition: core_local.c:825
local_call_action
Definition: core_local.c:209
@ LOCAL_CALL_ACTION_BRIDGE
Definition: core_local.c:213
@ LOCAL_CALL_ACTION_MASQUERADE
Definition: core_local.c:215
@ LOCAL_CALL_ACTION_DIALPLAN
Definition: core_local.c:211
static struct ao2_container * locals
Definition: core_local.c:150
struct ast_unreal_pvt_callbacks local_unreal_callbacks
Callbacks from the unreal core when channel optimization occurs.
Definition: core_local.c:179
static struct ast_channel * local_request_with_stream_topology(const char *type, struct ast_stream_topology *topology, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
Part of PBX interface.
Definition: core_local.c:953
Local proxy channel special access.
struct stasis_message_type * ast_local_bridge_type(void)
Message type for when two local channel halves are bridged together.
struct stasis_message_type * ast_local_optimization_end_type(void)
Message type for when a local channel optimization completes.
struct stasis_message_type * ast_local_optimization_begin_type(void)
Message type for when a local channel optimization begins.
Unreal channel derivative framework.
int ast_unreal_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
Definition: core_unreal.c:801
int ast_unreal_setoption(struct ast_channel *chan, int option, void *data, int datalen)
Definition: core_unreal.c:97
int ast_unreal_queryoption(struct ast_channel *ast, int option, void *data, int *datalen)
Definition: core_unreal.c:166
#define AST_UNREAL_MOH_INTERCEPT
Definition: core_unreal.h:109
int ast_unreal_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
Definition: core_unreal.c:369
#define AST_UNREAL_NO_OPTIMIZATION
Definition: core_unreal.h:108
int ast_unreal_digit_begin(struct ast_channel *ast, char digit)
Definition: core_unreal.c:779
int ast_unreal_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
Definition: core_unreal.c:846
void ast_unreal_call_setup(struct ast_channel *semi1, struct ast_channel *semi2)
Setup unreal owner and chan channels before initiating call.
Definition: core_unreal.c:870
void ast_unreal_destructor(void *vdoomed)
struct ast_unreal_pvt destructor.
Definition: core_unreal.c:1097
int ast_unreal_hangup(struct ast_unreal_pvt *p, struct ast_channel *ast)
Hangup one end (maybe both ends) of an unreal channel derivative.
Definition: core_unreal.c:1018
int ast_unreal_write(struct ast_channel *ast, struct ast_frame *f)
Definition: core_unreal.c:318
struct ast_unreal_pvt * ast_unreal_alloc_stream_topology(size_t size, ao2_destructor_fn destructor, struct ast_stream_topology *topology)
Allocate the base unreal struct for a derivative.
Definition: core_unreal.c:1126
int ast_unreal_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
Definition: core_unreal.c:622
int ast_unreal_sendtext(struct ast_channel *ast, const char *text)
Definition: core_unreal.c:824
ast_unreal_channel_indicator
Definition: core_unreal.h:49
@ AST_UNREAL_OWNER
Definition: core_unreal.h:50
int ast_unreal_answer(struct ast_channel *ast)
Definition: core_unreal.c:254
int ast_unreal_write_stream(struct ast_channel *ast, int stream_num, struct ast_frame *f)
Definition: core_unreal.c:323
#define AST_UNREAL_CARETAKER_THREAD
Definition: core_unreal.h:107
void ast_unreal_lock_all(struct ast_unreal_pvt *p, struct ast_channel **outchan, struct ast_channel **outowner)
Send an unreal pvt in with no locks held and get all locks.
Definition: core_unreal.c:47
struct ast_channel * ast_unreal_new_channels(struct ast_unreal_pvt *p, const struct ast_channel_tech *tech, int semi1_state, int semi2_state, const char *exten, const char *context, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, ast_callid callid)
Create the semi1 and semi2 unreal channels.
Definition: core_unreal.c:1160
struct ast_frame * ast_unreal_read(struct ast_channel *ast)
Definition: core_unreal.c:313
Device state management.
@ AST_DEVICE_INUSE
Definition: devicestate.h:55
@ AST_DEVICE_INVALID
Definition: devicestate.h:57
@ AST_DEVICE_NOT_INUSE
Definition: devicestate.h:54
char * end
Definition: eagi_proxy.c:73
#define AST_FORMAT_CAP_NAMES_LEN
Definition: format_cap.h:324
int ast_format_cap_append_by_type(struct ast_format_cap *cap, enum ast_media_type type)
Add all codecs Asterisk knows about for a specific type to the capabilities structure.
Definition: format_cap.c:216
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition: format_cap.h:38
const char * ast_format_cap_get_names(const struct ast_format_cap *cap, struct ast_str **buf)
Get the names of codecs of a set of formats.
Definition: format_cap.c:734
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition: format_cap.h:99
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:1986
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:2018
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1647
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7697
struct ast_multi_channel_blob * ast_multi_channel_blob_create(struct ast_json *blob)
Create a ast_multi_channel_blob suitable for a stasis_message.
struct ast_channel_snapshot * ast_multi_channel_blob_get_channel(struct ast_multi_channel_blob *obj, const char *role)
Retrieve a channel snapshot associated with a specific role from a ast_multi_channel_blob.
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object,...
void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj, const char *role, struct ast_channel_snapshot *snapshot)
Add a ast_channel_snapshot to a ast_multi_channel_blob object.
struct ast_json * ast_multi_channel_blob_get_json(struct ast_multi_channel_blob *obj)
Retrieve the JSON blob from a ast_multi_channel_blob. Returned ast_json is still owned by obj.
#define AST_OPTION_SECURE_MEDIA
#define AST_OPTION_SECURE_SIGNALING
#define ast_debug(level,...)
Log a DEBUG message.
ast_callid ast_read_threadstorage_callid(void)
extracts the callerid from the thread
Definition: logger.c:2273
unsigned int ast_callid
#define LOG_ERROR
#define LOG_NOTICE
#define LOG_WARNING
struct ast_json * ast_json_null(void)
Get the JSON null value.
Definition: json.c:248
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:283
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:407
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
Definition: json.c:332
int ast_json_is_true(const struct ast_json *value)
Check if value is JSON true.
Definition: json.c:263
AST_JSON_INT_T ast_json_int_t
Primarily used to cast when packing to an "I" type.
Definition: json.h:87
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define ast_manager_register_xml_core(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:203
#define EVENT_FLAG_SYSTEM
Definition: manager.h:75
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
Definition: manager.c:10237
#define EVENT_FLAG_CALL
Definition: manager.h:76
struct ast_str * ast_manager_build_channel_state_string_prefix(const struct ast_channel_snapshot *snapshot, const char *prefix)
Generate the AMI message body from a channel snapshot.
Core PBX routines and definitions.
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4190
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Create a new thread and start the PBX.
Definition: pbx.c:4723
static void to_ami(struct ast_sip_subscription *sub, struct ast_str **buf)
#define NULL
Definition: resample.c:96
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1515
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1493
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition: stasis.c:1538
Media Stream API.
@ 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_topology_free(struct ast_stream_topology *topology)
Unreference and destroy a stream topology.
Definition: stream.c:746
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
struct ast_stream_topology * ast_stream_topology_create_from_format_cap(struct ast_format_cap *cap)
A helper function that, given a format capabilities structure, creates a topology and separates the m...
Definition: stream.c:851
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
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
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:87
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_alloca(init_len)
Definition: strings.h:848
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
Structure to pass both assignedid values to channel drivers.
Definition: channel.h:606
Structure that contains features information.
Structure that contains information about a bridge.
Definition: bridge.h:353
const ast_string_field uniqueid
Structure representing a snapshot of channel state.
struct ast_channel_snapshot_base * base
Structure to describe a channel "technology", ie a channel driver See for examples:
Definition: channel.h:648
struct ast_format_cap * capabilities
Definition: channel.h:652
const char *const type
Definition: channel.h:649
Main Channel structure associated with a channel.
struct ast_bridge * bridge
char exten[AST_MAX_EXTENSION]
const char * data
struct ast_flags flags
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
Definition of a media format.
Definition: format.c:43
Abstract JSON element (object, array, string, int, ...).
Struct containing info for an AMI event to send out.
Definition: manager.h:503
A multi channel blob data structure for multi_channel_blob stasis messages.
Support for dynamic strings.
Definition: strings.h:623
Callbacks that can be provided by concrete implementations of the unreal channel driver that will be ...
Definition: core_unreal.h:58
void(*const optimization_started)(struct ast_unreal_pvt *p, struct ast_channel *source, enum ast_unreal_channel_indicator dest, unsigned int id)
Called when an optimization attempt has started.
Definition: core_unreal.h:69
The base pvt structure for local channel derivatives.
Definition: core_unreal.h:91
struct ast_jb_conf jb_conf
Definition: core_unreal.h:96
struct ast_channel * chan
Definition: core_unreal.h:94
char name[AST_MAX_EXTENSION+AST_MAX_CONTEXT+2]
Definition: core_unreal.h:99
struct ast_unreal_pvt_callbacks * callbacks
Definition: core_unreal.h:92
struct ast_channel * owner
Definition: core_unreal.h:93
Definition: astman.c:222
struct ast_channel * swap
Definition: core_local.c:223
struct ast_bridge * join
Definition: core_local.c:221
struct ast_bridge_features * features
Definition: core_local.c:225
the local pvt structure for all channels
Definition: core_local.c:235
struct ast_unreal_pvt base
Definition: core_local.c:237
struct local_bridge bridge
Definition: core_local.c:241
char exten[AST_MAX_EXTENSION]
Definition: core_local.c:250
union local_pvt::@341 action
char context[AST_MAX_CONTEXT]
Definition: core_local.c:248
enum local_call_action type
Definition: core_local.c:246
struct ast_channel * masq
Definition: core_local.c:243
In case you didn't read that giant block of text above the mansession_session struct,...
Definition: manager.c:327
Number structure.
Definition: app_followme.c:157
static struct test_val a
Support for translation of data formats. translate.c.
int ast_translator_best_choice(struct ast_format_cap *dst_cap, struct ast_format_cap *src_cap, struct ast_format **dst_fmt_out, struct ast_format **src_fmt_out)
Chooses the best translation path.
Definition: translate.c:1402
#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
#define ast_clear_flag(p, flag)
Definition: utils.h:77
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define ARRAY_LEN(a)
Definition: utils.h:666