Asterisk - The Open Source Telephony Project GIT-master-91e368c
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 <synopsis>
57 Optimize away a local channel when possible.
58 </synopsis>
59 <syntax>
60 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
61 <parameter name="Channel" required="true">
62 <para>The channel name to optimize away.</para>
63 </parameter>
64 </syntax>
65 <description>
66 <para>A local channel created with "/n" will not automatically optimize away.
67 Calling this command on the local channel will clear that flag and allow
68 it to optimize away if it's bridged or when it becomes bridged.</para>
69 </description>
70 </manager>
71 <managerEvent language="en_US" name="LocalBridge">
72 <managerEventInstance class="EVENT_FLAG_CALL">
73 <synopsis>Raised when two halves of a Local Channel form a bridge.</synopsis>
74 <syntax>
75 <channel_snapshot prefix="LocalOne"/>
76 <channel_snapshot prefix="LocalTwo"/>
77 <parameter name="Context">
78 <para>The context in the dialplan that Channel2 starts in.</para>
79 </parameter>
80 <parameter name="Exten">
81 <para>The extension in the dialplan that Channel2 starts in.</para>
82 </parameter>
83 <parameter name="LocalOptimization">
84 <enumlist>
85 <enum name="Yes"/>
86 <enum name="No"/>
87 </enumlist>
88 </parameter>
89 </syntax>
90 </managerEventInstance>
91 </managerEvent>
92 <managerEvent language="en_US" name="LocalOptimizationBegin">
93 <managerEventInstance class="EVENT_FLAG_CALL">
94 <synopsis>Raised when two halves of a Local Channel begin to optimize
95 themselves out of the media path.</synopsis>
96 <syntax>
97 <channel_snapshot prefix="LocalOne"/>
98 <channel_snapshot prefix="LocalTwo"/>
99 <channel_snapshot prefix="Source"/>
100 <parameter name="DestUniqueId">
101 <para>The unique ID of the bridge into which the local channel is optimizing.</para>
102 </parameter>
103 <parameter name="Id">
104 <para>Identification for the optimization operation.</para>
105 </parameter>
106 </syntax>
107 <see-also>
108 <ref type="managerEvent">LocalOptimizationEnd</ref>
109 <ref type="manager">LocalOptimizeAway</ref>
110 </see-also>
111 </managerEventInstance>
112 </managerEvent>
113 <managerEvent language="en_US" name="LocalOptimizationEnd">
114 <managerEventInstance class="EVENT_FLAG_CALL">
115 <synopsis>Raised when two halves of a Local Channel have finished optimizing
116 themselves out of the media path.</synopsis>
117 <syntax>
118 <channel_snapshot prefix="LocalOne"/>
119 <channel_snapshot prefix="LocalTwo"/>
120 <parameter name="Success">
121 <para>Indicates whether the local optimization succeeded.</para>
122 </parameter>
123 <parameter name="Id">
124 <para>Identification for the optimization operation. Matches the <replaceable>Id</replaceable>
125 from a previous <literal>LocalOptimizationBegin</literal></para>
126 </parameter>
127 </syntax>
128 <see-also>
129 <ref type="managerEvent">LocalOptimizationBegin</ref>
130 <ref type="manager">LocalOptimizeAway</ref>
131 </see-also>
132 </managerEventInstance>
133 </managerEvent>
134 ***/
135
136static const char tdesc[] = "Local Proxy Channel Driver";
137
138static struct ao2_container *locals;
139
140static 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);
141static 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);
142static int local_call(struct ast_channel *ast, const char *dest, int timeout);
143static int local_hangup(struct ast_channel *ast);
144static int local_devicestate(const char *data);
145static void local_optimization_started_cb(struct ast_unreal_pvt *base, struct ast_channel *source,
146 enum ast_unreal_channel_indicator dest, unsigned int id);
147static void local_optimization_finished_cb(struct ast_unreal_pvt *base, int success, unsigned int id);
148static int local_setoption(struct ast_channel *chan, int option, void *data, int datalen);
149
151
152/*!
153 * @{ \brief Define local channel message types.
154 */
157 );
160 );
163 );
164/*! @} */
165
166/*! \brief Callbacks from the unreal core when channel optimization occurs */
169 .optimization_finished = local_optimization_finished_cb,
170};
171
172/* PBX interface structure for channel registration */
174 .type = "Local",
175 .description = tdesc,
176 .requester = local_request,
177 .requester_with_stream_topology = local_request_with_stream_topology,
178 .send_digit_begin = ast_unreal_digit_begin,
179 .send_digit_end = ast_unreal_digit_end,
180 .call = local_call,
181 .hangup = local_hangup,
182 .answer = ast_unreal_answer,
183 .read_stream = ast_unreal_read,
184 .write = ast_unreal_write,
185 .write_stream = ast_unreal_write_stream,
186 .exception = ast_unreal_read,
187 .indicate = ast_unreal_indicate,
188 .fixup = ast_unreal_fixup,
189 .send_html = ast_unreal_sendhtml,
190 .send_text = ast_unreal_sendtext,
191 .devicestate = local_devicestate,
192 .queryoption = ast_unreal_queryoption,
193 .setoption = local_setoption,
194};
195
196/*! What to do with the ;2 channel when ast_call() happens. */
198 /* The ast_call() will run dialplan on the ;2 channel. */
200 /* The ast_call() will impart the ;2 channel into a bridge. */
202 /* The ast_call() will masquerade the ;2 channel into a channel. */
204};
205
206/*! Join a bridge on ast_call() parameters. */
208 /*! Bridge to join. */
210 /*! Channel to swap with when joining bridge. */
212 /*! Features that are specific to this channel when pushed into the bridge. */
214};
215
216/*!
217 * \brief the local pvt structure for all channels
218 *
219 * The local channel pvt has two ast_chan objects - the "owner" and the "next channel", the outbound channel
220 *
221 * ast_chan owner -> local_pvt -> ast_chan chan
222 */
223struct local_pvt {
224 /*! Unreal channel driver base class values. */
226 /*! Additional action arguments */
227 union {
228 /*! Make ;2 join a bridge on ast_call(). */
230 /*! Make ;2 masquerade into this channel on ast_call(). */
233 /*! What to do with the ;2 channel on ast_call(). */
235 /*! Context to call */
237 /*! Extension to call */
239};
240
241void ast_local_lock_all(struct ast_channel *chan, void **tech_pvt,
242 struct ast_channel **base_chan, struct ast_channel **base_owner)
243{
244 struct local_pvt *p = ast_channel_tech_pvt(chan);
245
246 *tech_pvt = NULL;
247 *base_chan = NULL;
248 *base_owner = NULL;
249
250 if (p) {
251 *tech_pvt = ao2_bump(p);
252 ast_unreal_lock_all(&p->base, base_chan, base_owner);
253 }
254}
255
256void ast_local_unlock_all(void *tech_pvt, struct ast_channel *base_chan,
257 struct ast_channel *base_owner)
258{
259 if (base_chan) {
260 ast_channel_unlock(base_chan);
261 ast_channel_unref(base_chan);
262 }
263
264 if (base_owner) {
265 ast_channel_unlock(base_owner);
266 ast_channel_unref(base_owner);
267 }
268
269 if (tech_pvt) {
270 struct local_pvt *p = tech_pvt;
271 ao2_unlock(&p->base);
272 ao2_ref(tech_pvt, -1);
273 }
274}
275
277{
278 struct local_pvt *p = ast_channel_tech_pvt(ast);
279 struct local_pvt *found;
280 struct ast_channel *peer;
281
282 if (!p) {
283 return NULL;
284 }
285
286 found = p ? ao2_find(locals, p, 0) : NULL;
287 if (!found) {
288 /* ast is either not a local channel or it has alredy been hungup */
289 return NULL;
290 }
291 ao2_lock(found);
292 if (ast == p->base.owner) {
293 peer = p->base.chan;
294 } else if (ast == p->base.chan) {
295 peer = p->base.owner;
296 } else {
297 peer = NULL;
298 }
299 if (peer) {
300 ast_channel_ref(peer);
301 }
302 ao2_unlock(found);
303 ao2_ref(found, -1);
304 return peer;
305}
306
307/*! \brief Adds devicestate to local channels */
308static int local_devicestate(const char *data)
309{
310 int is_inuse = 0;
311 int res = AST_DEVICE_INVALID;
312 char *exten = ast_strdupa(data);
313 char *context;
314 char *opts;
315 struct local_pvt *lp;
316 struct ao2_iterator it;
317
318 /* Strip options if they exist */
319 opts = strchr(exten, '/');
320 if (opts) {
321 *opts = '\0';
322 }
323
324 context = strchr(exten, '@');
325 if (!context) {
327 "Someone used Local/%s somewhere without a @context. This is bad.\n", data);
328 return AST_DEVICE_INVALID;
329 }
330 *context++ = '\0';
331
332 it = ao2_iterator_init(locals, 0);
333 for (; (lp = ao2_iterator_next(&it)); ao2_ref(lp, -1)) {
334 ao2_lock(lp);
335 if (!strcmp(exten, lp->exten)
336 && !strcmp(context, lp->context)) {
338 if (lp->base.owner
340 is_inuse = 1;
341 }
342 }
343 ao2_unlock(lp);
344 if (is_inuse) {
345 res = AST_DEVICE_INUSE;
346 ao2_ref(lp, -1);
347 break;
348 }
349 }
351
352 if (res == AST_DEVICE_INVALID) {
353 ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
354 if (ast_exists_extension(NULL, context, exten, 1, NULL)) {
356 }
357 }
358
359 return res;
360}
361
363 struct ast_json *json_object)
364{
365 struct ast_multi_channel_blob *payload;
366 RAII_VAR(struct ast_channel_snapshot *, local_one_snapshot, NULL, ao2_cleanup);
367 RAII_VAR(struct ast_channel_snapshot *, local_two_snapshot, NULL, ao2_cleanup);
368
370 if (!local_one_snapshot) {
371 return NULL;
372 }
373
375 if (!local_two_snapshot) {
376 return NULL;
377 }
378
379 payload = ast_multi_channel_blob_create(json_object);
380 if (!payload) {
381 return NULL;
382 }
383 ast_multi_channel_blob_add_channel(payload, "1", local_one_snapshot);
384 ast_multi_channel_blob_add_channel(payload, "2", local_two_snapshot);
385
386 return payload;
387}
388
389/*! \brief Callback for \ref ast_unreal_pvt_callbacks \p optimization_started */
390static void local_optimization_started_cb(struct ast_unreal_pvt *base, struct ast_channel *source,
391 enum ast_unreal_channel_indicator dest, unsigned int id)
392{
393 RAII_VAR(struct ast_json *, json_object, ast_json_null(), ast_json_unref);
394 RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
395 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
396 struct local_pvt *p = (struct local_pvt *)base;
397
399 return;
400 }
401
402 json_object = ast_json_pack("{s: i, s: I}",
403 "dest", dest, "id", (ast_json_int_t)id);
404
405 if (!json_object) {
406 return;
407 }
408
409 payload = local_channel_optimization_blob(p, json_object);
410 if (!payload) {
411 return;
412 }
413
414 if (source) {
415 RAII_VAR(struct ast_channel_snapshot *, source_snapshot, NULL, ao2_cleanup);
416 source_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(source));
417 if (!source_snapshot) {
418 return;
419 }
420
421 ast_multi_channel_blob_add_channel(payload, "source", source_snapshot);
422 }
423
425 if (!msg) {
426 return;
427 }
428
430}
431
432/*! \brief Callback for \ref ast_unreal_pvt_callbacks \p optimization_finished */
433static void local_optimization_finished_cb(struct ast_unreal_pvt *base, int success, unsigned int id)
434{
435 RAII_VAR(struct ast_json *, json_object, ast_json_null(), ast_json_unref);
436 RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
437 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
438 struct local_pvt *p = (struct local_pvt *)base;
439
441 return;
442 }
443
444 json_object = ast_json_pack("{s: i, s: I}", "success", success, "id", (ast_json_int_t)id);
445
446 if (!json_object) {
447 return;
448 }
449
450 payload = local_channel_optimization_blob(p, json_object);
451 if (!payload) {
452 return;
453 }
454
456 if (!msg) {
457 return;
458 }
459
461}
462
464{
466 struct ast_json *blob = ast_multi_channel_blob_get_json(obj);
467 struct ast_channel_snapshot *local_snapshot_one;
468 struct ast_channel_snapshot *local_snapshot_two;
469 RAII_VAR(struct ast_str *, local_channel_one, NULL, ast_free);
470 RAII_VAR(struct ast_str *, local_channel_two, NULL, ast_free);
471 RAII_VAR(struct ast_str *, event_buffer, NULL, ast_free);
472 const char *event;
473
474 local_snapshot_one = ast_multi_channel_blob_get_channel(obj, "1");
475 local_snapshot_two = ast_multi_channel_blob_get_channel(obj, "2");
476 if (!local_snapshot_one || !local_snapshot_two) {
477 return NULL;
478 }
479
480 event_buffer = ast_str_create(1024);
481 local_channel_one = ast_manager_build_channel_state_string_prefix(local_snapshot_one, "LocalOne");
482 local_channel_two = ast_manager_build_channel_state_string_prefix(local_snapshot_two, "LocalTwo");
483 if (!event_buffer || !local_channel_one || !local_channel_two) {
484 return NULL;
485 }
486
488 struct ast_channel_snapshot *source_snapshot;
489 RAII_VAR(struct ast_str *, source_str, NULL, ast_free);
490 const char *dest_uniqueid;
491
492 source_snapshot = ast_multi_channel_blob_get_channel(obj, "source");
493 if (source_snapshot) {
494 source_str = ast_manager_build_channel_state_string_prefix(source_snapshot, "Source");
495 if (!source_str) {
496 return NULL;
497 }
498 }
499
500 dest_uniqueid = ast_json_object_get(blob, "dest") == AST_UNREAL_OWNER ?
501 local_snapshot_one->base->uniqueid : local_snapshot_two->base->uniqueid;
502
503 event = "LocalOptimizationBegin";
504 if (source_str) {
505 ast_str_append(&event_buffer, 0, "%s", ast_str_buffer(source_str));
506 }
507 ast_str_append(&event_buffer, 0, "DestUniqueId: %s\r\n", dest_uniqueid);
508 ast_str_append(&event_buffer, 0, "Id: %u\r\n", (unsigned int) ast_json_integer_get(ast_json_object_get(blob, "id")));
510 event = "LocalOptimizationEnd";
511 ast_str_append(&event_buffer, 0, "Success: %s\r\n", ast_json_integer_get(ast_json_object_get(blob, "success")) ? "Yes" : "No");
512 ast_str_append(&event_buffer, 0, "Id: %u\r\n", (unsigned int) ast_json_integer_get(ast_json_object_get(blob, "id")));
514 event = "LocalBridge";
515 ast_str_append(&event_buffer, 0, "Context: %s\r\n", ast_json_string_get(ast_json_object_get(blob, "context")));
516 ast_str_append(&event_buffer, 0, "Exten: %s\r\n", ast_json_string_get(ast_json_object_get(blob, "exten")));
517 ast_str_append(&event_buffer, 0, "LocalOptimization: %s\r\n", ast_json_is_true(ast_json_object_get(blob, "can_optimize")) ? "Yes" : "No");
518 } else {
519 return NULL;
520 }
521
523 "%s"
524 "%s"
525 "%s",
526 ast_str_buffer(local_channel_one),
527 ast_str_buffer(local_channel_two),
528 ast_str_buffer(event_buffer));
529}
530
531/*!
532 * \internal
533 * \brief Post the \ref ast_local_bridge_type \ref stasis message
534 * \since 12.0.0
535 *
536 * \param p local_pvt to raise the local bridge message
537 */
539{
540 RAII_VAR(struct ast_multi_channel_blob *, multi_blob, NULL, ao2_cleanup);
541 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
542 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
543 RAII_VAR(struct ast_channel_snapshot *, one_snapshot, NULL, ao2_cleanup);
544 RAII_VAR(struct ast_channel_snapshot *, two_snapshot, NULL, ao2_cleanup);
545 struct ast_channel *owner;
546 struct ast_channel *chan;
547
548 if (!ast_local_bridge_type()) {
549 return;
550 }
551
552 ast_unreal_lock_all(&p->base, &chan, &owner);
553
554 blob = ast_json_pack("{s: s, s: s, s: b}",
555 "context", p->context,
556 "exten", p->exten,
557 "can_optimize", !ast_test_flag(&p->base, AST_UNREAL_NO_OPTIMIZATION));
558 if (!blob) {
559 goto end;
560 }
561
562 multi_blob = ast_multi_channel_blob_create(blob);
563 if (!multi_blob) {
564 goto end;
565 }
566
568 if (!one_snapshot) {
569 goto end;
570 }
571
573 if (!two_snapshot) {
574 goto end;
575 }
576
577 ast_multi_channel_blob_add_channel(multi_blob, "1", one_snapshot);
578 ast_multi_channel_blob_add_channel(multi_blob, "2", two_snapshot);
579
580 msg = stasis_message_create(ast_local_bridge_type(), multi_blob);
581 if (!msg) {
582 goto end;
583 }
584
586
587end:
588 ast_channel_unlock(owner);
589 ast_channel_unref(owner);
590
591 ast_channel_unlock(chan);
592 ast_channel_unref(chan);
593
594 ao2_unlock(&p->base);
595}
596
597int ast_local_setup_bridge(struct ast_channel *ast, struct ast_bridge *bridge, struct ast_channel *swap, struct ast_bridge_features *features)
598{
599 struct local_pvt *p;
600 struct local_pvt *found;
601 int res = -1;
602
603 /* Sanity checks. */
604 if (!ast || !bridge) {
606 return -1;
607 }
608
609 ast_channel_lock(ast);
610 p = ast_channel_tech_pvt(ast);
612
613 found = p ? ao2_find(locals, p, 0) : NULL;
614 if (found) {
615 ao2_lock(found);
616 if (found->type == LOCAL_CALL_ACTION_DIALPLAN
617 && found->base.owner
618 && found->base.chan
620 ao2_ref(bridge, +1);
621 if (swap) {
622 ast_channel_ref(swap);
623 }
625 found->action.bridge.join = bridge;
626 found->action.bridge.swap = swap;
627 found->action.bridge.features = features;
628 res = 0;
629 } else {
631 }
632 ao2_unlock(found);
633 ao2_ref(found, -1);
634 }
635
636 return res;
637}
638
640{
641 struct local_pvt *p;
642 struct local_pvt *found;
643 int res = -1;
644
645 /* Sanity checks. */
646 if (!ast || !masq) {
647 return -1;
648 }
649
650 ast_channel_lock(ast);
651 p = ast_channel_tech_pvt(ast);
653
654 found = p ? ao2_find(locals, p, 0) : NULL;
655 if (found) {
656 ao2_lock(found);
657 if (found->type == LOCAL_CALL_ACTION_DIALPLAN
658 && found->base.owner
659 && found->base.chan
663 found->action.masq = masq;
664 res = 0;
665 }
666 ao2_unlock(found);
667 ao2_ref(found, -1);
668 }
669
670 return res;
671}
672
673/*! \brief Initiate new call, part of PBX interface
674 * dest is the dial string */
675static int local_call(struct ast_channel *ast, const char *dest, int timeout)
676{
677 struct local_pvt *p = ast_channel_tech_pvt(ast);
678 int pvt_locked = 0;
679
680 struct ast_channel *owner = NULL;
681 struct ast_channel *chan = NULL;
682 int res;
683 char *reduced_dest = ast_strdupa(dest);
684 char *slash;
685 const char *chan_cid;
686
687 if (!p) {
688 return -1;
689 }
690
691 /* since we are letting go of channel locks that were locked coming into
692 * this function, then we need to give the tech pvt a ref */
693 ao2_ref(p, 1);
695
696 ast_unreal_lock_all(&p->base, &chan, &owner);
697 pvt_locked = 1;
698
699 if (owner != ast) {
700 res = -1;
701 goto return_cleanup;
702 }
703
704 if (!owner || !chan) {
705 res = -1;
706 goto return_cleanup;
707 }
708
709 ast_unreal_call_setup(owner, chan);
710
711 /*
712 * If the local channel has /n on the end of it, we need to lop
713 * that off for our argument to setting up the CC_INTERFACES
714 * variable.
715 */
716 if ((slash = strrchr(reduced_dest, '/'))) {
717 *slash = '\0';
718 }
719 ast_set_cc_interfaces_chanvar(chan, reduced_dest);
720
721 ao2_unlock(p);
722 pvt_locked = 0;
723
724 ast_channel_unlock(owner);
725
726 chan_cid = S_COR(ast_channel_caller(chan)->id.number.valid,
727 ast_channel_caller(chan)->id.number.str, NULL);
728 if (chan_cid) {
729 chan_cid = ast_strdupa(chan_cid);
730 }
731 ast_channel_unlock(chan);
732
733 res = -1;
734 switch (p->type) {
736 if (!ast_exists_extension(NULL, p->context, p->exten, 1, chan_cid)) {
737 ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n",
738 p->exten, p->context);
739 } else {
741
742 /* Start switch on sub channel */
743 res = ast_pbx_start(chan);
744 }
745 break;
748 ast_answer(chan);
751 ao2_ref(p->action.bridge.join, -1);
752 p->action.bridge.join = NULL;
754 p->action.bridge.swap = NULL;
756 break;
759 ast_answer(chan);
760 res = ast_channel_move(p->action.masq, chan);
761 if (!res) {
762 /* Chan is now an orphaned zombie. Destroy it. */
763 ast_hangup(chan);
764 }
766 break;
767 }
768 if (!res) {
769 ao2_lock(p);
771 ao2_unlock(p);
772 }
773
774 /* we already unlocked them, clear them here so the cleanup label won't touch them. */
775 owner = ast_channel_unref(owner);
776 chan = ast_channel_unref(chan);
777
778return_cleanup:
779 if (p) {
780 if (pvt_locked) {
781 ao2_unlock(p);
782 }
783 ao2_ref(p, -1);
784 }
785 if (chan) {
786 ast_channel_unlock(chan);
787 ast_channel_unref(chan);
788 }
789
790 /*
791 * owner is supposed to be == to ast, if it is, don't unlock it
792 * because ast must exit locked
793 */
794 if (owner) {
795 if (owner != ast) {
796 ast_channel_unlock(owner);
797 ast_channel_lock(ast);
798 }
799 ast_channel_unref(owner);
800 } else {
801 /* we have to exit with ast locked */
802 ast_channel_lock(ast);
803 }
804
805 return res;
806}
807
808/*! \brief Hangup a call through the local proxy channel */
809static int local_hangup(struct ast_channel *ast)
810{
811 struct local_pvt *p = ast_channel_tech_pvt(ast);
812 int res;
813
814 if (!p) {
815 return -1;
816 }
817
818 /* give the pvt a ref to fulfill calling requirements. */
819 ao2_ref(p, +1);
820 res = ast_unreal_hangup(&p->base, ast);
821 if (!res) {
822 int unlink;
823
824 ao2_lock(p);
825 unlink = !p->base.owner && !p->base.chan;
826 ao2_unlock(p);
827 if (unlink) {
828 ao2_unlink(locals, p);
829 }
830 }
831 ao2_ref(p, -1);
832
833 return res;
834}
835
836/*!
837 * \internal
838 * \brief struct local_pvt destructor.
839 *
840 * \param vdoomed Object to destroy.
841 */
842static void local_pvt_destructor(void *vdoomed)
843{
844 struct local_pvt *doomed = vdoomed;
845
846 switch (doomed->type) {
848 break;
850 ao2_cleanup(doomed->action.bridge.join);
851 ao2_cleanup(doomed->action.bridge.swap);
853 break;
855 ao2_cleanup(doomed->action.masq);
856 break;
857 }
858 ast_unreal_destructor(&doomed->base);
859}
860
861/*! \brief Create a call structure */
862static struct local_pvt *local_alloc(const char *data, struct ast_stream_topology *topology)
863{
864 struct local_pvt *pvt;
865 char *parse;
866 char *context;
867 char *opts;
868
869 pvt = (struct local_pvt *) ast_unreal_alloc_stream_topology(sizeof(*pvt), local_pvt_destructor, topology);
870 if (!pvt) {
871 return NULL;
872 }
874
875 parse = ast_strdupa(data);
876
877 /*
878 * Local channels intercept MOH by default.
879 *
880 * This is a silly default because it represents state held by
881 * the local channels. Unless local channel optimization is
882 * disabled, the state will dissapear when the local channels
883 * optimize out.
884 */
886
887 /* Look for options */
888 if ((opts = strchr(parse, '/'))) {
889 *opts++ = '\0';
890 if (strchr(opts, 'n')) {
892 }
893 if (strchr(opts, 'j')) {
896 } else {
897 ast_log(LOG_ERROR, "You must use the 'n' option with the 'j' option to enable the jitter buffer\n");
898 }
899 }
900 if (strchr(opts, 'm')) {
902 }
903 }
904
905 /* Look for a context */
906 if ((context = strchr(parse, '@'))) {
907 *context++ = '\0';
908 }
909
910 ast_copy_string(pvt->context, S_OR(context, "default"), sizeof(pvt->context));
911 ast_copy_string(pvt->exten, parse, sizeof(pvt->exten));
912 snprintf(pvt->base.name, sizeof(pvt->base.name), "%s@%s", pvt->exten, pvt->context);
913
914 return pvt; /* this is returned with a ref */
915}
916
917/*! \brief Part of PBX interface */
918static 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)
919{
920 struct ast_stream_topology *topology;
921 struct ast_channel *chan;
922
924 if (!topology) {
925 return NULL;
926 }
927
928 chan = local_request_with_stream_topology(type, topology, assignedids, requestor, data, cause);
929
930 ast_stream_topology_free(topology);
931
932 return chan;
933}
934
935/*! \brief Part of PBX interface */
936static 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)
937{
938 struct ast_stream_topology *audio_filtered_topology;
939 int i;
940 struct local_pvt *p;
941 struct ast_channel *chan;
943
944 /* Create a copy of the requested topology as we don't have ownership over
945 * the one that is passed in.
946 */
947 audio_filtered_topology = ast_stream_topology_clone(topology);
948 if (!audio_filtered_topology) {
949 return NULL;
950 }
951
952 /* Some users of Local channels request every known format in the
953 * universe. The core itself automatically pruned this list down to a single
954 * "best" format for audio in non-multistream. We replicate the logic here to
955 * do the same thing.
956 */
957 for (i = 0; i < ast_stream_topology_get_count(audio_filtered_topology); ++i) {
958 struct ast_stream *stream;
959 int res;
960 struct ast_format *tmp_fmt = NULL;
961 struct ast_format *best_audio_fmt = NULL;
962 struct ast_format_cap *caps;
963
964 stream = ast_stream_topology_get_stream(audio_filtered_topology, i);
965
968 continue;
969 }
970
971 /* Respect the immutable state of formats on the stream and create a new
972 * format capabilities to replace the existing one.
973 */
975 if (!caps) {
976 ao2_ref(audio_filtered_topology, -1);
977 return NULL;
978 }
979
980 /* The ast_translator_best_choice function treats both caps as const
981 * but does not declare it in the API.
982 */
984 &tmp_fmt, &best_audio_fmt);
985 if (res < 0) {
986 struct ast_str *tech_codecs = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
987 struct ast_str *request_codecs = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
988
989 ast_log(LOG_WARNING, "No translator path exists for channel type %s (native %s) to %s\n", type,
991 ast_format_cap_get_names(ast_stream_get_formats(stream), &request_codecs));
992
993 /* If there are no formats then we abort */
994 ao2_ref(caps, -1);
995 ao2_ref(audio_filtered_topology, -1);
996 return NULL;
997 }
998
999 ast_format_cap_append(caps, best_audio_fmt, 0);
1000 ast_stream_set_formats(stream, caps);
1001
1002 ao2_ref(caps, -1);
1003 ao2_ref(tmp_fmt, -1);
1004 ao2_ref(best_audio_fmt, -1);
1005 }
1006
1007 /* Allocate a new private structure and then Asterisk channels */
1008 p = local_alloc(data, audio_filtered_topology);
1009 ao2_ref(audio_filtered_topology, -1);
1010 if (!p) {
1011 return NULL;
1012 }
1015 p->exten, p->context, assignedids, requestor, callid);
1016 if (chan) {
1017 ao2_link(locals, p);
1018 }
1019 ao2_ref(p, -1); /* kill the ref from the alloc */
1020
1021 return chan;
1022}
1023
1024
1025/*! \brief CLI command "local show channels" */
1026static char *locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1027{
1028 struct local_pvt *p;
1029 struct ao2_iterator it;
1030
1031 switch (cmd) {
1032 case CLI_INIT:
1033 e->command = "local show channels";
1034 e->usage =
1035 "Usage: local show channels\n"
1036 " Provides summary information on active local proxy channels.\n";
1037 return NULL;
1038 case CLI_GENERATE:
1039 return NULL;
1040 }
1041
1042 if (a->argc != 3) {
1043 return CLI_SHOWUSAGE;
1044 }
1045
1046 if (ao2_container_count(locals) == 0) {
1047 ast_cli(a->fd, "No local channels in use\n");
1048 return RESULT_SUCCESS;
1049 }
1050
1051 it = ao2_iterator_init(locals, 0);
1052 while ((p = ao2_iterator_next(&it))) {
1053 ao2_lock(p);
1054 ast_cli(a->fd, "%s -- %s\n",
1055 p->base.owner ? ast_channel_name(p->base.owner) : "<unowned>",
1056 p->base.name);
1057 ao2_unlock(p);
1058 ao2_ref(p, -1);
1059 }
1061
1062 return CLI_SUCCESS;
1063}
1064
1065static struct ast_cli_entry cli_local[] = {
1066 AST_CLI_DEFINE(locals_show, "List status of local channels"),
1067};
1068
1069static int manager_optimize_away(struct mansession *s, const struct message *m)
1070{
1071 const char *channel;
1072 struct local_pvt *p;
1073 struct local_pvt *found;
1074 struct ast_channel *chan;
1075
1076 channel = astman_get_header(m, "Channel");
1077 if (ast_strlen_zero(channel)) {
1078 astman_send_error(s, m, "'Channel' not specified.");
1079 return 0;
1080 }
1081
1082 chan = ast_channel_get_by_name(channel);
1083 if (!chan) {
1084 astman_send_error(s, m, "Channel does not exist.");
1085 return 0;
1086 }
1087
1088 p = ast_channel_tech_pvt(chan);
1089 ast_channel_unref(chan);
1090
1091 found = p ? ao2_find(locals, p, 0) : NULL;
1092 if (found) {
1093 ao2_lock(found);
1095 ao2_unlock(found);
1096 ao2_ref(found, -1);
1097 astman_send_ack(s, m, "Queued channel to be optimized away");
1098 } else {
1099 astman_send_error(s, m, "Unable to find channel");
1100 }
1101
1102 return 0;
1103}
1104
1105
1106static int locals_cmp_cb(void *obj, void *arg, int flags)
1107{
1108 return (obj == arg) ? CMP_MATCH : 0;
1109}
1110
1111/*!
1112 * \internal
1113 * \brief Shutdown the local proxy channel.
1114 * \since 12.0.0
1115 */
1116static void local_shutdown(void)
1117{
1118 /* First, take us out of the channel loop */
1120 ast_manager_unregister("LocalOptimizeAway");
1122
1123 ao2_ref(locals, -1);
1124 locals = NULL;
1125
1128
1132}
1133
1135{
1137 return -1;
1138 }
1139
1141 return -1;
1142 }
1143
1145 return -1;
1146 }
1147
1149 return -1;
1150 }
1152
1154 if (!locals) {
1155 return -1;
1156 }
1157
1158 /* Make sure we can register our channel type */
1160 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
1161
1162 return -1;
1163 }
1166
1168 return 0;
1169}
1170
1171int local_setoption(struct ast_channel *ast, int option, void *data, int datalen)
1172{
1173 switch (option) {
1176 return 0; /* local calls (like forwardings) are secure always */
1177 default:
1178 return ast_unreal_setoption(ast, option, data, datalen);
1179 }
1180}
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:1878
@ AST_BRIDGE_IMPART_CHAN_INDEPENDENT
Definition: bridge.h:590
void ast_bridge_features_destroy(struct ast_bridge_features *features)
Destroy an allocated bridge features struct.
Definition: bridge.c:3674
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:3633
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:2535
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:2922
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:2947
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:10658
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:2958
#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:1448
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2799
#define ast_channel_unlock(chan)
Definition: channel.h:2923
#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:1069
struct ast_channel * ast_local_get_peer(struct ast_channel *ast)
Get the other local channel in the pair.
Definition: core_local.c:276
static int locals_cmp_cb(void *obj, void *arg, int flags)
Definition: core_local.c:1106
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:675
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:256
static int local_devicestate(const char *data)
Adds devicestate to local channels.
Definition: core_local.c:308
static void local_pvt_destructor(void *vdoomed)
Definition: core_local.c:842
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:597
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:918
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:390
static struct ast_channel_tech local_tech
Definition: core_local.c:173
static void publish_local_bridge_message(struct local_pvt *p)
Definition: core_local.c:538
static const char tdesc[]
Definition: core_local.c:136
int ast_local_init(void)
Initialize the local proxy channel.
Definition: core_local.c:1134
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:241
static int local_setoption(struct ast_channel *chan, int option, void *data, int datalen)
Definition: core_local.c:1171
static struct ast_manager_event_blob * local_message_to_ami(struct stasis_message *msg)
Definition: core_local.c:463
static struct local_pvt * local_alloc(const char *data, struct ast_stream_topology *topology)
Create a call structure.
Definition: core_local.c:862
static struct ast_cli_entry cli_local[]
Definition: core_local.c:1065
static void local_shutdown(void)
Definition: core_local.c:1116
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:639
static struct ast_multi_channel_blob * local_channel_optimization_blob(struct local_pvt *p, struct ast_json *json_object)
Definition: core_local.c:362
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:433
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:1026
static int local_hangup(struct ast_channel *ast)
Hangup a call through the local proxy channel.
Definition: core_local.c:809
local_call_action
Definition: core_local.c:197
@ LOCAL_CALL_ACTION_BRIDGE
Definition: core_local.c:201
@ LOCAL_CALL_ACTION_MASQUERADE
Definition: core_local.c:203
@ LOCAL_CALL_ACTION_DIALPLAN
Definition: core_local.c:199
static struct ao2_container * locals
Definition: core_local.c:138
struct ast_unreal_pvt_callbacks local_unreal_callbacks
Callbacks from the unreal core when channel optimization occurs.
Definition: core_local.c:167
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:936
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:3280
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3312
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:2941
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7887
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:2048
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:602
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:273
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:397
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
Definition: json.c:322
int ast_json_is_true(const struct ast_json *value)
Check if value is JSON true.
Definition: json.c:253
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:202
#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:10393
#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:4175
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Create a new thread and start the PBX.
Definition: pbx.c:4708
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:1511
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: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_topology_free(struct ast_stream_topology *topology)
Unreference and destroy a stream topology.
Definition: stream.c:743
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:848
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
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:1136
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:758
#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:845
#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:604
Structure that contains features information.
Structure that contains information about a bridge.
Definition: bridge.h:349
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:628
struct ast_format_cap * capabilities
Definition: channel.h:632
const char *const type
Definition: channel.h:629
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:502
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:211
struct ast_bridge * join
Definition: core_local.c:209
struct ast_bridge_features * features
Definition: core_local.c:213
the local pvt structure for all channels
Definition: core_local.c:223
struct ast_unreal_pvt base
Definition: core_local.c:225
struct local_bridge bridge
Definition: core_local.c:229
char exten[AST_MAX_EXTENSION]
Definition: core_local.c:238
union local_pvt::@338 action
char context[AST_MAX_CONTEXT]
Definition: core_local.c:236
enum local_call_action type
Definition: core_local.c:234
struct ast_channel * masq
Definition: core_local.c:231
In case you didn't read that giant block of text above the mansession_session struct,...
Definition: manager.c:1746
Number structure.
Definition: app_followme.c:154
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:1385
#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