Asterisk - The Open Source Telephony Project GIT-master-27fb039
Loading...
Searching...
No Matches
core_unreal.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 Unreal channel derivatives framework for channel drivers like local channels.
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#include "asterisk.h"
34
35#include "asterisk/causes.h"
36#include "asterisk/channel.h"
38#include "asterisk/pbx.h"
40#include "asterisk/astobj2.h"
41#include "asterisk/bridge.h"
43#include "asterisk/stream.h"
44
45static unsigned int name_sequence = 0;
46
47void ast_unreal_lock_all(struct ast_unreal_pvt *p, struct ast_channel **outchan, struct ast_channel **outowner)
48{
49 struct ast_channel *chan = NULL;
50 struct ast_channel *owner = NULL;
51
52 ao2_lock(p);
53 for (;;) {
54 if (p->chan) {
55 chan = p->chan;
56 ast_channel_ref(chan);
57 }
58 if (p->owner) {
59 owner = p->owner;
60 ast_channel_ref(owner);
61 }
62 ao2_unlock(p);
63
64 /* if we don't have both channels, then this is very easy */
65 if (!owner || !chan) {
66 if (owner) {
67 ast_channel_lock(owner);
68 } else if(chan) {
69 ast_channel_lock(chan);
70 }
71 } else {
72 /* lock both channels first, then get the pvt lock */
73 ast_channel_lock_both(chan, owner);
74 }
75 ao2_lock(p);
76
77 /* Now that we have all the locks, validate that nothing changed */
78 if (p->owner != owner || p->chan != chan) {
79 if (owner) {
80 ast_channel_unlock(owner);
81 owner = ast_channel_unref(owner);
82 }
83 if (chan) {
85 chan = ast_channel_unref(chan);
86 }
87 continue;
88 }
89
90 break;
91 }
92 *outowner = p->owner;
93 *outchan = p->chan;
94}
95
96/* Called with ast locked */
97int ast_unreal_setoption(struct ast_channel *ast, int option, void *data, int datalen)
98{
99 int res = 0;
100 struct ast_unreal_pvt *p;
101 struct ast_channel *otherchan = NULL;
102 ast_chan_write_info_t *write_info;
103 char *info_data;
104
105 if (option != AST_OPTION_CHANNEL_WRITE) {
106 return -1;
107 }
108
109 write_info = data;
110
111 if (write_info->version != AST_CHAN_WRITE_INFO_T_VERSION) {
112 ast_log(LOG_ERROR, "The chan_write_info_t type has changed, and this channel hasn't been updated!\n");
113 return -1;
114 }
115
116 info_data = write_info->data;
117 if (!strcmp(write_info->function, "CHANNEL")) {
118 if (!strncasecmp(info_data, "hangup_handler_", 15)) {
119 /* Block CHANNEL(hangup_handler_xxx) writes to the other unreal channel. */
120 return 0;
121 }
122
123 /* Crossover the accountcode and peeraccount to cross the unreal bridge. */
124 if (!strcasecmp(info_data, "accountcode")) {
125 info_data = "peeraccount";
126 } else if (!strcasecmp(info_data, "peeraccount")) {
127 info_data = "accountcode";
128 }
129 }
130
131 /* get the tech pvt */
132 if (!(p = ast_channel_tech_pvt(ast))) {
133 return -1;
134 }
135 ao2_ref(p, 1);
136 ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */
137
138 /* get the channel we are supposed to write to */
139 ao2_lock(p);
140 otherchan = (write_info->chan == p->owner) ? p->chan : p->owner;
141 if (!otherchan || otherchan == write_info->chan) {
142 res = -1;
143 otherchan = NULL;
144 ao2_unlock(p);
145 goto setoption_cleanup;
146 }
147 ast_channel_ref(otherchan);
148
149 /* clear the pvt lock before grabbing the channel */
150 ao2_unlock(p);
151
152 ast_channel_lock(otherchan);
153 res = write_info->write_fn(otherchan, write_info->function, info_data, write_info->value);
154 ast_channel_unlock(otherchan);
155
156setoption_cleanup:
157 ao2_ref(p, -1);
158 if (otherchan) {
159 ast_channel_unref(otherchan);
160 }
161 ast_channel_lock(ast); /* Lock back before we leave */
162 return res;
163}
164
165/* Called with ast locked */
166int ast_unreal_queryoption(struct ast_channel *ast, int option, void *data, int *datalen)
167{
168 struct ast_unreal_pvt *p;
169 struct ast_channel *peer;
170 struct ast_channel *other;
171 int res = 0;
172
173 if (option != AST_OPTION_T38_STATE) {
174 /* AST_OPTION_T38_STATE is the only supported option at this time */
175 return -1;
176 }
177
178 /* for some reason the channel is not locked in channel.c when this function is called */
179 if (!(p = ast_channel_tech_pvt(ast))) {
180 return -1;
181 }
182
183 ao2_lock(p);
184 other = AST_UNREAL_IS_OUTBOUND(ast, p) ? p->owner : p->chan;
185 if (!other) {
186 ao2_unlock(p);
187 return -1;
188 }
189 ast_channel_ref(other);
190 ao2_unlock(p);
191 ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */
192
193 peer = ast_channel_bridge_peer(other);
194 if (peer) {
195 res = ast_channel_queryoption(peer, option, data, datalen, 0);
196 ast_channel_unref(peer);
197 }
198 ast_channel_unref(other);
199 ast_channel_lock(ast); /* Lock back before we leave */
200
201 return res;
202}
203
204/*!
205 * \brief queue a frame onto either the p->owner or p->chan
206 *
207 * \note the ast_unreal_pvt MUST have it's ref count bumped before entering this function and
208 * decremented after this function is called. This is a side effect of the deadlock
209 * avoidance that is necessary to lock 2 channels and a tech_pvt. Without a ref counted
210 * ast_unreal_pvt, it is impossible to guarantee it will not be destroyed by another thread
211 * during deadlock avoidance.
212 */
213static int unreal_queue_frame(struct ast_unreal_pvt *p, int isoutbound, struct ast_frame *f,
214 struct ast_channel *us, int us_locked)
215{
216 struct ast_channel *other;
217
218 /* Recalculate outbound channel */
219 other = isoutbound ? p->owner : p->chan;
220 if (!other) {
221 return 0;
222 }
223
224 /* do not queue media frames if a generator is on both unreal channels */
225 if (us
228 && ast_channel_generator(other)) {
229 return 0;
230 }
231
232 /* grab a ref on the channel before unlocking the pvt,
233 * other can not go away from us now regardless of locking */
234 ast_channel_ref(other);
235 if (us && us_locked) {
237 }
238 ao2_unlock(p);
239
242 }
243 ast_queue_frame(other, f);
244
245 other = ast_channel_unref(other);
246 if (us && us_locked) {
248 }
249 ao2_lock(p);
250
251 return 0;
252}
253
255{
256 struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
257 int isoutbound;
258 int res = -1;
259
260 if (!p) {
261 return -1;
262 }
263
264 ao2_ref(p, 1);
265 ao2_lock(p);
266 isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
267 if (isoutbound) {
268 /* Pass along answer since somebody answered us */
270
271 res = unreal_queue_frame(p, isoutbound, &answer, ast, 1);
272 } else {
273 ast_log(LOG_WARNING, "Huh? %s is being asked to answer?\n",
274 ast_channel_name(ast));
275 }
276 ao2_unlock(p);
277 ao2_ref(p, -1);
278 return res;
279}
280
281/*!
282 * \internal
283 * \brief Check and optimize out the unreal channels between bridges.
284 * \since 12.0.0
285 *
286 * \param ast Channel writing a frame into the unreal channels.
287 * \param p Unreal channel private.
288 *
289 * \note It is assumed that ast is locked.
290 * \note It is assumed that p is locked.
291 *
292 * \retval 0 if unreal channels were not optimized out.
293 * \retval non-zero if unreal channels were optimized out.
294 */
295static int got_optimized_out(struct ast_channel *ast, struct ast_unreal_pvt *p)
296{
297 int res = 0;
298
299 /* Do a few conditional checks early on just to see if this optimization is possible */
300 if (ast_test_flag(p, AST_UNREAL_NO_OPTIMIZATION) || !p->chan || !p->owner) {
301 return res;
302 }
303
304 if (ast == p->owner) {
306 } else if (ast == p->chan) {
308 }
309
310 return res;
311}
312
314{
315 return &ast_null_frame;
316}
317
318int ast_unreal_write(struct ast_channel *ast, struct ast_frame *f)
319{
320 return ast_unreal_write_stream(ast, -1, f);
321}
322
324{
325 struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
326 int res = -1;
327
328 if (!p) {
329 return -1;
330 }
331
332 /* If we are told to write a frame with a type that has no corresponding
333 * stream on the channel then drop it.
334 */
335 if (f->frametype == AST_FRAME_VOICE) {
337 return 0;
338 }
339 } else if (f->frametype == AST_FRAME_VIDEO ||
342 return 0;
343 }
344 }
345
346 /* Update the frame to reflect the stream */
347 f->stream_num = stream_num;
348
349 /* Just queue for delivery to the other side */
350 ao2_ref(p, 1);
351 ao2_lock(p);
352 switch (f->frametype) {
353 case AST_FRAME_VOICE:
354 case AST_FRAME_VIDEO:
355 if (got_optimized_out(ast, p)) {
356 break;
357 }
358 /* fall through */
359 default:
360 res = unreal_queue_frame(p, AST_UNREAL_IS_OUTBOUND(ast, p), f, ast, 1);
361 break;
362 }
363 ao2_unlock(p);
364 ao2_ref(p, -1);
365
366 return res;
367}
368
369int ast_unreal_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
370{
371 struct ast_unreal_pvt *p = ast_channel_tech_pvt(newchan);
372 struct ast_bridge *bridge_owner;
373 struct ast_bridge *bridge_chan;
374
375 if (!p) {
376 return -1;
377 }
378
379 ao2_lock(p);
380
381 if ((p->owner != oldchan) && (p->chan != oldchan)) {
382 ast_log(LOG_WARNING, "Old channel %p wasn't %p or %p\n", oldchan, p->owner, p->chan);
383 ao2_unlock(p);
384 return -1;
385 }
386 if (p->owner == oldchan) {
387 p->owner = newchan;
388 } else {
389 p->chan = newchan;
390 }
391
392 if (ast_check_hangup(newchan) || !p->owner || !p->chan) {
393 ao2_unlock(p);
394 return 0;
395 }
396
397 /* Do not let a masquerade cause an unreal channel to be bridged to itself! */
398 bridge_owner = ast_channel_internal_bridge(p->owner);
399 bridge_chan = ast_channel_internal_bridge(p->chan);
400 if (bridge_owner && bridge_owner == bridge_chan) {
401 ast_log(LOG_WARNING, "You can not bridge an unreal channel (%s) to itself!\n",
402 ast_channel_name(newchan));
403 ao2_unlock(p);
404 ast_queue_hangup(newchan);
405 return -1;
406 }
407
408 ao2_unlock(p);
409 return 0;
410}
411
412/*!
413 * \internal
414 * \brief Queue up a frame representing the indication as a control frame.
415 * \since 12.0.0
416 *
417 * \param p Unreal private structure.
418 * \param ast Channel indicating the condition.
419 * \param condition What is being indicated.
420 * \param data Extra data.
421 * \param datalen Length of extra data.
422 *
423 * \retval 0 on success.
424 * \retval AST_T38_REQUEST_PARMS if successful and condition is AST_CONTROL_T38_PARAMETERS.
425 * \retval -1 on error.
426 */
427static int unreal_queue_indicate(struct ast_unreal_pvt *p, struct ast_channel *ast, int condition, const void *data, size_t datalen)
428{
429 int res = 0;
430 int isoutbound;
431
432 ao2_lock(p);
433 /*
434 * Block -1 stop tones events if we are to be optimized out. We
435 * don't need a flurry of these events on an unreal channel chain
436 * when initially connected to slow the optimization process.
437 */
438 if (0 <= condition || ast_test_flag(p, AST_UNREAL_NO_OPTIMIZATION)) {
439 struct ast_frame f = {
441 .subclass.integer = condition,
442 .data.ptr = (void *) data,
443 .datalen = datalen,
444 };
445
446 isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
447 res = unreal_queue_frame(p, isoutbound, &f, ast, 1);
448 if (!res
449 && condition == AST_CONTROL_T38_PARAMETERS
450 && datalen == sizeof(struct ast_control_t38_parameters)) {
451 const struct ast_control_t38_parameters *parameters = data;
452
453 if (parameters->request_response == AST_T38_REQUEST_PARMS) {
455 }
456 }
457 } else {
458 ast_debug(4, "Blocked indication %d\n", condition);
459 }
460 ao2_unlock(p);
461
462 return res;
463}
464
465/*!
466 * \internal
467 * \brief Handle COLP and redirecting conditions.
468 * \since 12.0.0
469 *
470 * \param p Unreal private structure.
471 * \param ast Channel indicating the condition.
472 * \param condition What is being indicated.
473 *
474 * \retval 0 on success.
475 * \retval -1 on error.
476 */
477static int unreal_colp_redirect_indicate(struct ast_unreal_pvt *p, struct ast_channel *ast, int condition)
478{
479 struct ast_channel *my_chan;
480 struct ast_channel *my_owner;
481 struct ast_channel *this_channel;
482 struct ast_channel *the_other_channel;
483 int isoutbound;
484 int res = 0;
485 unsigned char frame_data[1024];
486 struct ast_frame f = {
488 .subclass.integer = condition,
489 .data.ptr = frame_data,
490 };
491
492 /*
493 * A connected line update frame may only contain a partial
494 * amount of data, such as just a source, or just a ton, and not
495 * the full amount of information. However, the collected
496 * information is all stored in the outgoing channel's
497 * connectedline structure, so when receiving a connected line
498 * update on an outgoing unreal channel, we need to transmit the
499 * collected connected line information instead of whatever
500 * happens to be in this control frame. The same applies for
501 * redirecting information, which is why it is handled here as
502 * well.
503 */
505 ast_unreal_lock_all(p, &my_chan, &my_owner);
506 isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
507 if (isoutbound) {
508 this_channel = p->chan;
509 the_other_channel = p->owner;
510 } else {
511 this_channel = p->owner;
512 the_other_channel = p->chan;
513 }
514 if (the_other_channel) {
515 if (condition == AST_CONTROL_CONNECTED_LINE) {
517 ast_channel_connected(this_channel));
518 f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data),
519 ast_channel_connected(this_channel), NULL);
520 } else {
521 f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data),
522 ast_channel_redirecting(this_channel), NULL);
523 }
524 }
525 if (my_chan) {
526 ast_channel_unlock(my_chan);
527 ast_channel_unref(my_chan);
528 }
529 if (my_owner) {
530 ast_channel_unlock(my_owner);
531 ast_channel_unref(my_owner);
532 }
533 if (the_other_channel) {
534 res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
535 }
536 ao2_unlock(p);
537 ast_channel_lock(ast);
538
539 return res;
540}
541
542/*!
543 * \internal
544 * \brief Handle stream topology change request.
545 * \since 16.12.0
546 * \since 17.6.0
547 *
548 * \param p Unreal private structure.
549 * \param ast Channel indicating the condition.
550 * \param topology The requested topology.
551 *
552 * \retval 0 on success.
553 * \retval -1 on error.
554 */
555static int unreal_colp_stream_topology_request_change(struct ast_unreal_pvt *p, struct ast_channel *ast, const struct ast_stream_topology *topology)
556{
557 struct ast_stream_topology *this_channel_topology;
558 struct ast_stream_topology *the_other_channel_topology;
559 int i;
560 struct ast_stream *stream;
561 struct ast_channel *my_chan;
562 struct ast_channel *my_owner;
563 struct ast_channel *this_channel;
564 struct ast_channel *the_other_channel;
565 int res = 0;
566
567 this_channel_topology = ast_stream_topology_clone(topology);
568 if (!this_channel_topology) {
569 return -1;
570 }
571
572 the_other_channel_topology = ast_stream_topology_clone(topology);
573 if (!the_other_channel_topology) {
574 ast_stream_topology_free(this_channel_topology);
575 return -1;
576 }
577
578 /* We swap the stream state on the other channel because it is as if the channel is
579 * connected to an external endpoint, so the perspective changes.
580 */
581 for (i = 0; i < ast_stream_topology_get_count(the_other_channel_topology); ++i) {
582 stream = ast_stream_topology_get_stream(the_other_channel_topology, i);
583
588 }
589 }
590
592 ast_unreal_lock_all(p, &my_chan, &my_owner);
593 if (AST_UNREAL_IS_OUTBOUND(ast, p)) {
594 this_channel = p->chan;
595 the_other_channel = p->owner;
596 } else {
597 this_channel = p->owner;
598 the_other_channel = p->chan;
599 }
600 if (this_channel) {
601 ast_channel_set_stream_topology(this_channel, this_channel_topology);
603 }
604 if (the_other_channel) {
605 ast_channel_set_stream_topology(the_other_channel, the_other_channel_topology);
607 }
608 if (my_chan) {
609 ast_channel_unlock(my_chan);
610 ast_channel_unref(my_chan);
611 }
612 if (my_owner) {
613 ast_channel_unlock(my_owner);
614 ast_channel_unref(my_owner);
615 }
616 ao2_unlock(p);
617 ast_channel_lock(ast);
618
619 return res;
620}
621
622int ast_unreal_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
623{
624 struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
625 int res = 0;
626 struct ast_channel *chan = NULL;
627 struct ast_channel *owner = NULL;
628 const struct ast_control_t38_parameters *parameters;
629
630 if (!p) {
631 return -1;
632 }
633
634 ao2_ref(p, 1); /* ref for unreal_queue_frame */
635
636 switch (condition) {
638 /*
639 * Always block this because this is the channel being
640 * masqueraded; not anything down the chain.
641 */
642 break;
645 res = unreal_colp_redirect_indicate(p, ast, condition);
646 break;
647 case AST_CONTROL_HOLD:
649 ast_moh_start(ast, data, NULL);
650 break;
651 }
652 res = unreal_queue_indicate(p, ast, condition, data, datalen);
653 break;
656 ast_moh_stop(ast);
657 break;
658 }
659 res = unreal_queue_indicate(p, ast, condition, data, datalen);
660 break;
662 /* Don't queue ringing frames if the channel is not in a "ring" state. Otherwise,
663 * the real channel on the other end will likely start a playtones generator. It is
664 * possible that this playtones generator will never be stopped under certain
665 * circumstances.
666 */
667 if (ast_channel_state(ast) == AST_STATE_RING) {
668 res = unreal_queue_indicate(p, ast, condition, data, datalen);
669 } else {
670 res = -1;
671 }
672 break;
674 /* Return -1 so that asterisk core will correctly set up hangupcauses. */
675 unreal_queue_indicate(p, ast, condition, data, datalen);
676 res = -1;
677 break;
681 }
682 break;
684 parameters = data;
685 if (parameters->request_response == AST_T38_NEGOTIATED) {
686 struct ast_stream *stream;
687 struct ast_stream_topology *new_topology;
688
689 stream = ast_stream_alloc("local_fax", AST_MEDIA_TYPE_IMAGE);
690 if (!stream) {
691 ast_log(LOG_ERROR, "Failed to allocate memory for stream.\n");
692 res = -1;
693 break;
694 }
695 new_topology = ast_stream_topology_alloc();
696 if (!new_topology) {
697 ast_log(LOG_ERROR, "Failed to allocate memory for stream topology.\n");
698 ast_free(stream);
699 res = -1;
700 break;
701 }
702 ast_stream_topology_append_stream(new_topology, stream);
703
704 /*
705 * Lock both parts of the local channel so we can store their topologies and replace them with
706 * one that has a stream with type IMAGE. We can just hold the reference on the unreal_pvt
707 * structure and bump it, then steal the ref later when we are restoring the topology.
708 *
709 * We use ast_unreal_lock_all here because we don't know if the ;1 or ;2 side will get the
710 * signaling and we need to be sure that the locking order is the same to prevent possible
711 * deadlocks.
712 */
714 ast_unreal_lock_all(p, &chan, &owner);
715
716 if (owner) {
718 ast_channel_set_stream_topology(owner, new_topology);
719 }
720
721 if (chan) {
723
724 /* Bump the ref for new_topology, since it will be used by both sides of the local channel */
725 ao2_ref(new_topology, +1);
726 ast_channel_set_stream_topology(chan, new_topology);
727 }
728
729 ao2_unlock(p);
730 ast_channel_lock(ast);
731 } else if (parameters->request_response == AST_T38_TERMINATED) {
732 /*
733 * Lock both parts of the local channel so we can restore their topologies to the original.
734 * The topology should be on the unreal_pvt structure, with a ref that we can steal. Same
735 * conditions as above.
736 */
738 ast_unreal_lock_all(p, &chan, &owner);
739
740 if (owner) {
743 }
744
745 if (chan) {
748 }
749
750 ao2_unlock(p);
751 ast_channel_lock(ast);
752 }
753
754 /*
755 * We unlock ast_unreal_pvt in the above conditionals since there's no way to
756 * tell if it's been unlocked already or not when we get to this point, but
757 * if either of these are not NULL, we know that they are locked and need to
758 * unlock them.
759 */
760 if (owner) {
761 ast_channel_unlock(owner);
762 ast_channel_unref(owner);
763 }
764
765 if (chan) {
766 ast_channel_unlock(chan);
767 ast_channel_unref(chan);
768 }
769 /* Fall through for all T38 conditions */
770 default:
771 res = unreal_queue_indicate(p, ast, condition, data, datalen);
772 break;
773 }
774
775 ao2_ref(p, -1);
776 return res;
777}
778
780{
781 struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
782 int res = -1;
783 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
784 int isoutbound;
785
786 if (!p) {
787 return -1;
788 }
789
790 ao2_ref(p, 1); /* ref for unreal_queue_frame */
791 ao2_lock(p);
792 isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
794 res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
795 ao2_unlock(p);
796 ao2_ref(p, -1);
797
798 return res;
799}
800
801int ast_unreal_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
802{
803 struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
804 int res = -1;
805 struct ast_frame f = { AST_FRAME_DTMF_END, };
806 int isoutbound;
807
808 if (!p) {
809 return -1;
810 }
811
812 ao2_ref(p, 1); /* ref for unreal_queue_frame */
813 ao2_lock(p);
814 isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
816 f.len = duration;
817 res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
818 ao2_unlock(p);
819 ao2_ref(p, -1);
820
821 return res;
822}
823
824int ast_unreal_sendtext(struct ast_channel *ast, const char *text)
825{
826 struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
827 int res = -1;
828 struct ast_frame f = { AST_FRAME_TEXT, };
829 int isoutbound;
830
831 if (!p) {
832 return -1;
833 }
834
835 ao2_ref(p, 1); /* ref for unreal_queue_frame */
836 ao2_lock(p);
837 isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
838 f.data.ptr = (char *) text;
839 f.datalen = strlen(text) + 1;
840 res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
841 ao2_unlock(p);
842 ao2_ref(p, -1);
843 return res;
844}
845
846int ast_unreal_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
847{
848 struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
849 int res = -1;
850 struct ast_frame f = { AST_FRAME_HTML, };
851 int isoutbound;
852
853 if (!p) {
854 return -1;
855 }
856
857 ao2_ref(p, 1); /* ref for unreal_queue_frame */
858 ao2_lock(p);
859 isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
861 f.data.ptr = (char *)data;
862 f.datalen = datalen;
863 res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
864 ao2_unlock(p);
865 ao2_ref(p, -1);
866
867 return res;
868}
869
870void ast_unreal_call_setup(struct ast_channel *semi1, struct ast_channel *semi2)
871{
872 struct ast_var_t *varptr;
873 struct ast_var_t *clone_var;
874
876
877 /*
878 * Note that cid_num and cid_name aren't passed in the
879 * ast_channel_alloc calls in ast_unreal_new_channels(). It's
880 * done here instead.
881 */
883
885
886 /* Crossover the CallerID and conected-line to cross the unreal bridge. */
889
891 ast_channel_language_set(semi2, ast_channel_language(semi1));
892 ast_channel_musicclass_set(semi2, ast_channel_musicclass(semi1));
893 ast_channel_parkinglot_set(semi2, ast_channel_parkinglot(semi1));
894
895 /* Crossover the accountcode and peeraccount to cross the unreal bridge. */
896 ast_channel_accountcode_set(semi2, ast_channel_peeraccount(semi1));
897 ast_channel_peeraccount_set(semi2, ast_channel_accountcode(semi1));
898
900
901 /*
902 * Make sure we inherit the AST_CAUSE_ANSWERED_ELSEWHERE if it's
903 * set on the queue/dial call request in the dialplan.
904 */
907 }
908
909 /*
910 * Copy the channel variables from the semi1 channel to the
911 * outgoing channel.
912 *
913 * Note that due to certain assumptions, they MUST be in the
914 * same order.
915 */
917 clone_var = ast_var_assign(varptr->name, varptr->value);
918 if (clone_var) {
921 ast_var_value(clone_var));
922 }
923 }
924 ast_channel_datastore_inherit(semi1, semi2);
925
927}
928
929int ast_unreal_channel_push_to_bridge(struct ast_channel *ast, struct ast_bridge *bridge, unsigned int flags)
930{
931 struct ast_bridge_features *features;
932 struct ast_channel *chan;
933 struct ast_channel *owner;
934 ast_callid bridge_callid;
936
938 bridge_callid = bridge->callid;
940
941 {
943 p = ast_channel_tech_pvt(ast);
944 if (!p) {
945 return -1;
946 }
947 ao2_ref(p, +1);
948 }
949
950 {
952 chan = p->chan;
953 if (!chan) {
954 return -1;
955 }
956
957 owner = p->owner;
958 if (!owner) {
959 return -1;
960 }
961
962 ast_channel_ref(chan);
963 ast_channel_ref(owner);
964 }
965
966 if (bridge_callid) {
967 ast_callid chan_callid;
968 ast_callid owner_callid;
969
970 /* chan side call ID setting */
971 ast_channel_lock(chan);
972
973 chan_callid = ast_channel_callid(chan);
974 if (!chan_callid) {
975 ast_channel_callid_set(chan, bridge_callid);
976 }
977 ast_channel_unlock(chan);
978
979 /* owner side call ID setting */
980 ast_channel_lock(owner);
981
982 owner_callid = ast_channel_callid(owner);
983 if (!owner_callid) {
984 ast_channel_callid_set(owner, bridge_callid);
985 }
986
987 ast_channel_unlock(owner);
988 }
989
990 /* We are done with the owner now that its call ID matches the bridge */
991 ast_channel_unref(owner);
992 owner = NULL;
993
994 features = ast_bridge_features_new();
995 if (!features) {
996 ast_channel_unref(chan);
997 return -1;
998 }
999
1000 ast_set_flag(&features->feature_flags, flags);
1001
1002 /* Impart the semi2 channel into the bridge */
1003 if (ast_bridge_impart(bridge, chan, NULL, features,
1005 ast_channel_unref(chan);
1006 return -1;
1007 }
1008
1009 /* The bridge thread now controls the chan ref from the ast_unreal_pvt */
1010 ao2_lock(p);
1012 ao2_unlock(p);
1013
1014 ast_channel_unref(chan);
1015
1016 return 0;
1017}
1018
1020{
1021 int hangup_chan = 0;
1022 int res = 0;
1023 int cause;
1024 struct ast_channel *owner = NULL;
1025 struct ast_channel *chan = NULL;
1026
1027 /* the pvt isn't going anywhere, it has a ref */
1028 ast_channel_unlock(ast);
1029
1030 /* lock everything */
1031 ast_unreal_lock_all(p, &chan, &owner);
1032
1033 if (ast != chan && ast != owner) {
1034 res = -1;
1035 goto unreal_hangup_cleanup;
1036 }
1037
1038 cause = ast_channel_hangupcause(ast);
1039
1040 if (ast == p->chan) {
1041 /* Outgoing side is hanging up. */
1043 p->chan = NULL;
1044 if (p->owner) {
1045 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
1046
1047 if (status) {
1049 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
1050 }
1052 }
1053 } else {
1054 /* Owner side is hanging up. */
1055 p->owner = NULL;
1056 if (p->chan) {
1057 if (cause == AST_CAUSE_ANSWERED_ELSEWHERE) {
1059 ast_debug(2, "%s has AST_CAUSE_ANSWERED_ELSEWHERE set.\n",
1061 }
1063 /*
1064 * Need to actually hangup p->chan since nothing else is taking
1065 * care of it.
1066 */
1067 hangup_chan = 1;
1068 } else {
1070 }
1071 }
1072 }
1073
1074 /* this is one of our locked channels, doesn't matter which */
1076 ao2_ref(p, -1);
1077
1078unreal_hangup_cleanup:
1079 ao2_unlock(p);
1080 if (owner) {
1081 ast_channel_unlock(owner);
1082 ast_channel_unref(owner);
1083 }
1084 if (chan) {
1085 ast_channel_unlock(chan);
1086 if (hangup_chan) {
1087 ast_hangup(chan);
1088 }
1089 ast_channel_unref(chan);
1090 }
1091
1092 /* leave with the channel locked that came in */
1093 ast_channel_lock(ast);
1094
1095 return res;
1096}
1097
1098void ast_unreal_destructor(void *vdoomed)
1099{
1100 struct ast_unreal_pvt *doomed = vdoomed;
1101
1102 ao2_cleanup(doomed->reqcap);
1103 doomed->reqcap = NULL;
1105 doomed->reqtopology = NULL;
1108}
1109
1110struct ast_unreal_pvt *ast_unreal_alloc(size_t size, ao2_destructor_fn destructor, struct ast_format_cap *cap)
1111{
1112 struct ast_stream_topology *topology;
1113 struct ast_unreal_pvt *unreal;
1114
1116 if (!topology) {
1117 return NULL;
1118 }
1119
1120 unreal = ast_unreal_alloc_stream_topology(size, destructor, topology);
1121
1122 ast_stream_topology_free(topology);
1123
1124 return unreal;
1125}
1126
1128{
1129 struct ast_unreal_pvt *unreal;
1130
1131 static const struct ast_jb_conf jb_conf = {
1132 .flags = 0,
1133 .max_size = -1,
1134 .resync_threshold = -1,
1135 .impl = "",
1136 .target_extra = -1,
1137 };
1138
1139 unreal = ao2_alloc(size, destructor);
1140 if (!unreal) {
1141 return NULL;
1142 }
1143
1144 unreal->reqtopology = ast_stream_topology_clone(topology);
1145 if (!unreal->reqtopology) {
1146 ao2_ref(unreal, -1);
1147 return NULL;
1148 }
1149
1150 unreal->reqcap = ast_stream_topology_get_formats(topology);
1151 if (!unreal->reqcap) {
1152 ao2_ref(unreal, -1);
1153 return NULL;
1154 }
1155
1156 memcpy(&unreal->jb_conf, &jb_conf, sizeof(unreal->jb_conf));
1157
1158 return unreal;
1159}
1160
1162 const struct ast_channel_tech *tech, int semi1_state, int semi2_state,
1163 const char *exten, const char *context, const struct ast_assigned_ids *assignedids,
1164 const struct ast_channel *requestor, ast_callid callid)
1165{
1166 struct ast_channel *owner;
1167 struct ast_channel *chan;
1168 RAII_VAR(struct ast_format *, fmt, NULL, ao2_cleanup);
1169 struct ast_assigned_ids id1 = {NULL, NULL};
1170 struct ast_assigned_ids id2 = {NULL, NULL};
1171 int generated_seqno = ast_atomic_fetchadd_int((int *) &name_sequence, +1);
1172 int i;
1173 RAII_VAR(struct ast_stream_topology *, chan_topology, NULL, ast_stream_topology_free);
1174 struct ast_stream *stream;
1175
1176 /* set unique ids for the two channels */
1177 if (assignedids && !ast_strlen_zero(assignedids->uniqueid)) {
1178 id1.uniqueid = assignedids->uniqueid;
1179 id2.uniqueid = assignedids->uniqueid2;
1180 }
1181
1182 /* if id1 given but not id2, use default of id1;2 */
1183 if (id1.uniqueid && ast_strlen_zero(id2.uniqueid)) {
1184 char *uniqueid2;
1185
1186 uniqueid2 = ast_alloca(strlen(id1.uniqueid) + 3);
1187 strcpy(uniqueid2, id1.uniqueid);/* Safe */
1188 strcat(uniqueid2, ";2");/* Safe */
1189 id2.uniqueid = uniqueid2;
1190 }
1191
1192 /* We need to create a topology to place on the second channel, as we can't
1193 * share a single one between both.
1194 */
1195 chan_topology = ast_stream_topology_clone(p->reqtopology);
1196 if (!chan_topology) {
1197 return NULL;
1198 }
1199
1200 for (i = 0; i < ast_stream_topology_get_count(chan_topology); ++i) {
1201 stream = ast_stream_topology_get_stream(chan_topology, i);
1202 /* We need to make sure that the ;2 channel has the opposite stream topology
1203 * of the first channel if the stream is one-way. I.e. if the first channel
1204 * is recvonly, the second channel has to be sendonly and vice versa.
1205 */
1208 } else if (ast_stream_get_state(stream) == AST_STREAM_STATE_SENDONLY) {
1210 }
1211 }
1212
1213 /*
1214 * Allocate two new Asterisk channels
1215 *
1216 * Make sure that the ;2 channel gets the same linkedid as ;1.
1217 * You can't pass linkedid to both allocations since if linkedid
1218 * isn't set, then each channel will generate its own linkedid.
1219 */
1220 owner = ast_channel_alloc(1, semi1_state, NULL, NULL, NULL,
1221 exten, context, &id1, requestor, 0,
1222 "%s/%s-%08x;1", tech->type, p->name, (unsigned)generated_seqno);
1223 if (!owner) {
1224 ast_log(LOG_WARNING, "Unable to allocate owner channel structure\n");
1225 return NULL;
1226 }
1227
1228 if (callid) {
1229 ast_channel_callid_set(owner, callid);
1230 }
1231
1232 ast_channel_tech_set(owner, tech);
1233 ao2_ref(p, +1);
1234 ast_channel_tech_pvt_set(owner, p);
1235
1237
1238 if (ast_channel_is_multistream(owner)) {
1240 p->reqtopology = NULL;
1241 }
1242
1243 /* Determine our read/write format and set it on each channel */
1244 fmt = ast_format_cap_get_format(p->reqcap, 0);
1245 if (!fmt) {
1247 ao2_ref(p, -1);
1248 ast_channel_unlock(owner);
1249 ast_channel_release(owner);
1250 return NULL;
1251 }
1252
1253 ast_channel_set_writeformat(owner, fmt);
1255 ast_channel_set_readformat(owner, fmt);
1257
1259
1260 ast_jb_configure(owner, &p->jb_conf);
1261
1262 if (ast_channel_cc_params_init(owner, requestor
1263 ? ast_channel_get_cc_config_params((struct ast_channel *) requestor) : NULL)) {
1265 ao2_ref(p, -1);
1267 ast_channel_unlock(owner);
1268 ast_channel_release(owner);
1269 return NULL;
1270 }
1271
1272 p->owner = owner;
1273 ast_channel_unlock(owner);
1274
1275 chan = ast_channel_alloc(1, semi2_state, NULL, NULL, NULL,
1276 exten, context, &id2, owner, 0,
1277 "%s/%s-%08x;2", tech->type, p->name, (unsigned)generated_seqno);
1278 if (!chan) {
1279 ast_log(LOG_WARNING, "Unable to allocate chan channel structure\n");
1281 ao2_ref(p, -1);
1283 ast_channel_release(owner);
1284 return NULL;
1285 }
1286
1287 if (callid) {
1288 ast_channel_callid_set(chan, callid);
1289 }
1290
1291 ast_channel_tech_set(chan, tech);
1292 ao2_ref(p, +1);
1293 ast_channel_tech_pvt_set(chan, p);
1294
1296
1297 if (ast_channel_is_multistream(chan)) {
1298 ast_channel_set_stream_topology(chan, ao2_bump(chan_topology));
1299 }
1300
1301 /* Format was already determined when setting up owner */
1302 ast_channel_set_writeformat(chan, fmt);
1304 ast_channel_set_readformat(chan, fmt);
1306
1308
1309 p->chan = chan;
1310 ast_channel_unlock(chan);
1311
1312 return owner;
1313}
void ast_jb_configure(struct ast_channel *chan, const struct ast_jb_conf *conf)
Configures a jitterbuffer on a channel.
char digit
jack_status_t status
Definition app_jack.c:149
char * text
Definition app_queue.c:1772
ast_mutex_t lock
Definition app_sla.c:337
Asterisk main include file. File version handling, generic pbx functions.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition astmm.h:288
#define ast_free(a)
Definition astmm.h:180
#define ast_log
Definition astobj2.c:42
#define ao2_cleanup(obj)
Definition astobj2.h:1934
void(* ao2_destructor_fn)(void *vdoomed)
Typedef for an object destructor.
Definition astobj2.h:358
#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
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
Bridging API.
#define ast_bridge_unlock(bridge)
Unlock the bridge.
Definition bridge.h:485
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
#define ast_bridge_lock(bridge)
Lock the bridge.
Definition bridge.h:474
@ AST_BRIDGE_IMPART_CHAN_INDEPENDENT
Definition bridge.h:594
int ast_bridge_unreal_optimize_out(struct ast_channel *chan, struct ast_channel *peer, struct ast_unreal_pvt *pvt)
Check and optimize out the unreal channels between bridges.
Definition bridge.c:2999
struct ast_bridge_features * ast_bridge_features_new(void)
Allocate a new bridge features struct.
Definition bridge.c:3762
Internal Asterisk hangup causes.
#define AST_CAUSE_ANSWERED_ELSEWHERE
Definition causes.h:114
static int answer(void *data)
Definition chan_pjsip.c:687
General Asterisk PBX channel definitions.
const char * ast_channel_name(const struct ast_channel *chan)
struct ast_bridge * ast_channel_internal_bridge(const struct ast_channel *chan)
struct ast_stream_topology * ast_channel_set_stream_topology(struct ast_channel *chan, struct ast_stream_topology *topology)
Set the topology of streams on a channel.
void * ast_channel_tech_pvt(const struct ast_channel *chan)
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition channel.c:2538
struct varshead * ast_channel_varshead(struct ast_channel *chan)
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
Definition channel.h:1299
int ast_queue_hangup(struct ast_channel *chan)
Queue a hangup frame.
Definition channel.c:1181
struct ast_channel * ast_channel_bridge_peer(struct ast_channel *chan)
Get the channel's bridge peer only if the bridge is two-party.
Definition channel.c:10608
void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
const char * ast_channel_musicclass(const struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition channel.h:2982
struct ast_party_redirecting * ast_channel_redirecting(struct ast_channel *chan)
int ast_channel_queryoption(struct ast_channel *channel, int option, void *data, int *datalen, int block)
Checks the value of an option.
Definition channel.c:7454
int ast_queue_control(struct ast_channel *chan, enum ast_control_frame_type control)
Queue a control frame without payload.
Definition channel.c:1288
int ast_channel_cc_params_init(struct ast_channel *chan, const struct ast_cc_config_params *base_params)
Set up datastore with CCSS parameters for a channel.
Definition channel.c:10495
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
#define ast_channel_ref(c)
Increase channel reference count.
Definition channel.h:3007
#define ast_channel_lock_both(chan1, chan2)
Lock two channels.
Definition channel.h:2989
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
ast_callid ast_channel_callid(const struct ast_channel *chan)
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel's frame queue.
Definition channel.c:1170
int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *to)
Inherit datastores from a parent to a child.
Definition channel.c:2358
const char * ast_channel_accountcode(const struct ast_channel *chan)
const char * ast_channel_parkinglot(const struct ast_channel *chan)
ast_channel_adsicpe
Definition channel.h:888
const char * ast_channel_peeraccount(const struct ast_channel *chan)
int ast_queue_hangup_with_cause(struct ast_channel *chan, int cause)
Queue a hangup frame with hangupcause set.
Definition channel.c:1212
void ast_channel_set_rawreadformat(struct ast_channel *chan, struct ast_format *format)
void ast_channel_tech_pvt_set(struct ast_channel *chan, void *value)
void ast_party_dialed_copy(struct ast_party_dialed *dest, const struct ast_party_dialed *src)
Copy the source dialed party information to the destination dialed party.
Definition channel.c:1922
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition channel.c:445
struct ast_stream_topology * ast_channel_get_stream_topology(const struct ast_channel *chan)
Retrieve the topology of streams on a channel.
int ast_channel_hangupcause(const struct ast_channel *chan)
void ast_channel_set_rawwriteformat(struct ast_channel *chan, struct ast_format *format)
struct ast_party_dialed * ast_channel_dialed(struct ast_channel *chan)
struct ast_channel * ast_channel_release(struct ast_channel *chan)
Unlink and release reference to a channel.
Definition channel.c:1570
int ast_redirecting_build_data(unsigned char *data, size_t datalen, const struct ast_party_redirecting *redirecting, const struct ast_set_party_redirecting *update)
Build the redirecting id data frame.
Definition channel.c:9312
void ast_channel_set_readformat(struct ast_channel *chan, struct ast_format *format)
int ast_connected_line_build_data(unsigned char *data, size_t datalen, const struct ast_party_connected_line *connected, const struct ast_set_party_connected_line *update)
Build the connected line information data frame.
Definition channel.c:8741
#define ast_channel_unref(c)
Decrease channel reference count.
Definition channel.h:3018
struct ast_stream * ast_channel_get_default_stream(struct ast_channel *chan, enum ast_media_type type)
Retrieve the default stream of a specific media type on a channel.
int ast_channel_stream_topology_changed_externally(struct ast_channel *chan)
Provide notice from a channel that the topology has changed on it as a result of the remote party ren...
Definition channel.c:11052
struct ast_generator * ast_channel_generator(const struct ast_channel *chan)
const char * ast_channel_language(const struct ast_channel *chan)
void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest, const struct ast_party_caller *src)
Copy the caller information to the connected line information.
Definition channel.c:8337
#define AST_CHAN_WRITE_INFO_T_VERSION
ast_chan_write_info_t version. Must be incremented if structure is changed
Definition channel.h:593
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
@ AST_FLAG_DISABLE_DEVSTATE_CACHE
Definition channel.h:1049
void ast_channel_callid_set(struct ast_channel *chan, ast_callid value)
void ast_connected_line_copy_to_caller(struct ast_party_caller *dest, const struct ast_party_connected_line *src)
Copy the connected line information to the caller information.
Definition channel.c:8344
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
void ast_channel_adsicpe_set(struct ast_channel *chan, enum ast_channel_adsicpe value)
int ast_channel_is_multistream(struct ast_channel *chan)
Determine if a channel is multi-stream capable.
void ast_channel_tech_set(struct ast_channel *chan, const struct ast_channel_tech *value)
struct ast_cc_config_params * ast_channel_get_cc_config_params(struct ast_channel *chan)
Get the CCSS parameters from a channel.
Definition channel.c:10518
#define ast_channel_unlock(chan)
Definition channel.h:2983
void ast_party_redirecting_copy(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src)
Copy the source redirecting information to the destination redirecting.
Definition channel.c:2121
void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format)
ast_channel_state
ast_channel states
@ AST_STATE_RING
@ AST_STATE_RINGING
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition channel.c:7398
#define ast_var_assign(name, value)
Definition chanvars.h:40
const char * ast_var_full_name(const struct ast_var_t *var)
Definition chanvars.c:75
const char * ast_var_value(const struct ast_var_t *var)
Definition chanvars.c:80
@ AST_MEDIA_TYPE_AUDIO
Definition codec.h:32
@ AST_MEDIA_TYPE_VIDEO
Definition codec.h:33
@ AST_MEDIA_TYPE_IMAGE
Definition codec.h:34
int ast_unreal_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
int ast_unreal_setoption(struct ast_channel *ast, int option, void *data, int datalen)
Definition core_unreal.c:97
static int unreal_colp_redirect_indicate(struct ast_unreal_pvt *p, struct ast_channel *ast, int condition)
int ast_unreal_queryoption(struct ast_channel *ast, int option, void *data, int *datalen)
int ast_unreal_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
int ast_unreal_digit_begin(struct ast_channel *ast, char digit)
int ast_unreal_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
void ast_unreal_call_setup(struct ast_channel *semi1, struct ast_channel *semi2)
Setup unreal owner and chan channels before initiating call.
void ast_unreal_destructor(void *vdoomed)
struct ast_unreal_pvt destructor.
int ast_unreal_hangup(struct ast_unreal_pvt *p, struct ast_channel *ast)
Hangup one end (maybe both ends) of an unreal channel derivative.
static int unreal_queue_indicate(struct ast_unreal_pvt *p, struct ast_channel *ast, int condition, const void *data, size_t datalen)
static unsigned int name_sequence
Definition core_unreal.c:45
int ast_unreal_write(struct ast_channel *ast, struct ast_frame *f)
struct ast_unreal_pvt * ast_unreal_alloc(size_t size, ao2_destructor_fn destructor, struct ast_format_cap *cap)
Allocate the base unreal struct for a derivative.
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.
int ast_unreal_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
int ast_unreal_channel_push_to_bridge(struct ast_channel *ast, struct ast_bridge *bridge, unsigned int flags)
Push the semi2 unreal channel into a bridge from either member of the unreal pair.
int ast_unreal_sendtext(struct ast_channel *ast, const char *text)
static int got_optimized_out(struct ast_channel *ast, struct ast_unreal_pvt *p)
static int unreal_queue_frame(struct ast_unreal_pvt *p, int isoutbound, struct ast_frame *f, struct ast_channel *us, int us_locked)
queue a frame onto either the p->owner or p->chan
int ast_unreal_answer(struct ast_channel *ast)
int ast_unreal_write_stream(struct ast_channel *ast, int stream_num, struct ast_frame *f)
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.
static int unreal_colp_stream_topology_request_change(struct ast_unreal_pvt *p, struct ast_channel *ast, const struct ast_stream_topology *topology)
struct ast_frame * ast_unreal_read(struct ast_channel *ast)
Unreal channel derivative framework.
#define AST_UNREAL_IS_OUTBOUND(a, b)
#define AST_UNREAL_MOH_INTERCEPT
#define AST_UNREAL_NO_OPTIMIZATION
#define AST_UNREAL_CARETAKER_THREAD
struct ast_format * ast_format_cap_get_format(const struct ast_format_cap *cap, int position)
Get the format at a specific index.
Definition format_cap.c:400
void ast_channel_publish_varset(struct ast_channel *chan, const char *variable, const char *value)
Publish a ast_channel_publish_varset for a channel.
void ast_channel_stage_snapshot_done(struct ast_channel *chan)
Clear flag to indicate channel snapshot is being staged, and publish snapshot.
void ast_channel_stage_snapshot(struct ast_channel *chan)
Set flag to indicate channel snapshot is being staged.
@ AST_T38_REQUEST_PARMS
@ AST_T38_TERMINATED
@ AST_T38_NEGOTIATED
#define AST_OPTION_CHANNEL_WRITE
Handle channel write data If a channel needs to process the data from a func_channel write operation ...
#define AST_OPTION_T38_STATE
@ AST_FRAME_DTMF_END
@ AST_FRAME_DTMF_BEGIN
@ AST_FRAME_CONTROL
@ AST_CONTROL_UNHOLD
@ AST_CONTROL_VIDUPDATE
@ AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE
@ AST_CONTROL_REDIRECTING
@ AST_CONTROL_T38_PARAMETERS
@ AST_CONTROL_ANSWER
@ AST_CONTROL_RINGING
@ AST_CONTROL_STREAM_TOPOLOGY_CHANGED
@ AST_CONTROL_CONNECTED_LINE
@ AST_CONTROL_MASQUERADE_NOTIFY
@ AST_CONTROL_PVT_CAUSE_CODE
struct ast_frame ast_null_frame
Definition main/frame.c:79
#define ast_debug(level,...)
Log a DEBUG message.
unsigned int ast_callid
#define LOG_ERROR
#define LOG_WARNING
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition lock.h:611
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition lock.h:764
#define SCOPED_CHANNELLOCK(varname, chan)
scoped lock specialization for channels.
Definition lock.h:626
Music on hold handling.
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition channel.c:7778
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition channel.c:7788
Core PBX routines and definitions.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
#define NULL
Definition resample.c:96
Media Stream API.
struct ast_stream_topology * ast_stream_topology_alloc(void)
Create a stream topology.
Definition stream.c:652
struct ast_stream * ast_stream_alloc(const char *name, enum ast_media_type type)
Create a new media stream representation.
Definition stream.c:233
@ AST_STREAM_STATE_RECVONLY
Set when the stream is receiving media only.
Definition stream.h:90
@ AST_STREAM_STATE_SENDONLY
Set when the stream is sending media only.
Definition stream.h:86
void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state)
Set the state of a stream.
Definition stream.c:380
int ast_stream_topology_append_stream(struct ast_stream_topology *topology, struct ast_stream *stream)
Append a stream to the topology.
Definition stream.c:751
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
void ast_stream_topology_free(struct ast_stream_topology *topology)
Unreference and destroy a stream topology.
Definition stream.c:746
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
struct ast_format_cap * ast_stream_topology_get_formats(struct ast_stream_topology *topology)
Create a format capabilities structure representing the topology.
Definition stream.c:933
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
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
Structure to pass both assignedid values to channel drivers.
Definition channel.h:606
const char * uniqueid2
Definition channel.h:608
const char * uniqueid
Definition channel.h:607
Structure that contains features information.
struct ast_flags feature_flags
Structure that contains information about a bridge.
Definition bridge.h:353
ast_callid callid
Definition bridge.h:365
Structure to handle passing func_channel_write info to channels via setoption.
Definition channel.h:591
ast_acf_write_fn_t write_fn
Definition channel.h:595
struct ast_channel * chan
Definition channel.h:596
const char * value
Definition channel.h:599
const char * function
Definition channel.h:597
Structure to describe a channel "technology", ie a channel driver See for examples:
Definition channel.h:648
const char *const type
Definition channel.h:649
Main Channel structure associated with a channel.
struct ast_filestream * stream
struct ast_bridge * bridge
ast_callid callid
char exten[AST_MAX_EXTENSION]
const char * data
const struct ast_channel_tech * tech
char context[AST_MAX_CONTEXT]
struct ast_flags flags
enum ast_control_t38 request_response
Format capabilities structure, holds formats + preference order + etc.
Definition format_cap.c:54
Definition of a media format.
Definition format.c:43
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
enum ast_frame_type frametype
union ast_frame::@239 data
General jitterbuffer configuration.
Definition abstract_jb.h:70
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_stream_topology * chan_old_topology
struct ast_format_cap * reqcap
Definition core_unreal.h:95
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_channel * owner
Definition core_unreal.h:93
struct ast_stream_topology * owner_old_topology
struct ast_stream_topology * reqtopology
char name[0]
Definition chanvars.h:31
struct ast_var_t::@224 entries
char * value
Definition chanvars.h:30
long resync_threshold
Definition jitterbuf.h:70
#define ast_test_flag(p, flag)
Definition utils.h:64
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:981
#define ast_clear_flag(p, flag)
Definition utils.h:78
#define ast_set_flag(p, flag)
Definition utils.h:71