2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2013 Digium, Inc.
6 * Richard Mudgett <rmudgett@digium.com>
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.
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.
21 * \brief Unreal channel derivatives framework for channel drivers like local channels.
23 * \author Richard Mudgett <rmudgett@digium.com>
26 * \arg \ref AstCREDITS
30 <support_level>core</support_level>
35 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
37 #include "asterisk/causes.h"
38 #include "asterisk/channel.h"
39 #include "asterisk/pbx.h"
40 #include "asterisk/musiconhold.h"
41 #include "asterisk/astobj2.h"
42 #include "asterisk/bridge.h"
43 #include "asterisk/core_unreal.h"
45 static unsigned int name_sequence = 0;
47 void ast_unreal_lock_all(struct ast_unreal_pvt *p, struct ast_channel **outchan, struct ast_channel **outowner)
49 struct ast_channel *chan = NULL;
50 struct ast_channel *owner = NULL;
56 ast_channel_ref(chan);
60 ast_channel_ref(owner);
64 /* if we don't have both channels, then this is very easy */
65 if (!owner || !chan) {
67 ast_channel_lock(owner);
69 ast_channel_lock(chan);
72 /* lock both channels first, then get the pvt lock */
73 ast_channel_lock_both(chan, owner);
77 /* Now that we have all the locks, validate that nothing changed */
78 if (p->owner != owner || p->chan != chan) {
80 ast_channel_unlock(owner);
81 owner = ast_channel_unref(owner);
84 ast_channel_unlock(chan);
85 chan = ast_channel_unref(chan);
96 /* Called with ast locked */
97 int ast_unreal_setoption(struct ast_channel *ast, int option, void *data, int datalen)
100 struct ast_unreal_pvt *p;
101 struct ast_channel *otherchan = NULL;
102 ast_chan_write_info_t *write_info;
104 if (option != AST_OPTION_CHANNEL_WRITE) {
110 if (write_info->version != AST_CHAN_WRITE_INFO_T_VERSION) {
111 ast_log(LOG_ERROR, "The chan_write_info_t type has changed, and this channel hasn't been updated!\n");
115 if (!strcmp(write_info->function, "CHANNEL")
116 && !strncasecmp(write_info->data, "hangup_handler_", 15)) {
117 /* Block CHANNEL(hangup_handler_xxx) writes to the other unreal channel. */
121 /* get the tech pvt */
122 if (!(p = ast_channel_tech_pvt(ast))) {
126 ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */
128 /* get the channel we are supposed to write to */
130 otherchan = (write_info->chan == p->owner) ? p->chan : p->owner;
131 if (!otherchan || otherchan == write_info->chan) {
135 goto setoption_cleanup;
137 ast_channel_ref(otherchan);
139 /* clear the pvt lock before grabbing the channel */
142 ast_channel_lock(otherchan);
143 res = write_info->write_fn(otherchan, write_info->function, write_info->data, write_info->value);
144 ast_channel_unlock(otherchan);
149 ast_channel_unref(otherchan);
151 ast_channel_lock(ast); /* Lock back before we leave */
155 /* Called with ast locked */
156 int ast_unreal_queryoption(struct ast_channel *ast, int option, void *data, int *datalen)
158 struct ast_unreal_pvt *p;
159 struct ast_channel *peer;
160 struct ast_channel *other;
163 if (option != AST_OPTION_T38_STATE) {
164 /* AST_OPTION_T38_STATE is the only supported option at this time */
168 /* for some reason the channel is not locked in channel.c when this function is called */
169 if (!(p = ast_channel_tech_pvt(ast))) {
174 other = AST_UNREAL_IS_OUTBOUND(ast, p) ? p->owner : p->chan;
179 ast_channel_ref(other);
181 ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */
183 peer = ast_channel_bridge_peer(other);
185 res = ast_channel_queryoption(peer, option, data, datalen, 0);
186 ast_channel_unref(peer);
188 ast_channel_unref(other);
189 ast_channel_lock(ast); /* Lock back before we leave */
195 * \brief queue a frame onto either the p->owner or p->chan
197 * \note the ast_unreal_pvt MUST have it's ref count bumped before entering this function and
198 * decremented after this function is called. This is a side effect of the deadlock
199 * avoidance that is necessary to lock 2 channels and a tech_pvt. Without a ref counted
200 * ast_unreal_pvt, it is impossible to guarantee it will not be destroyed by another thread
201 * during deadlock avoidance.
203 static int unreal_queue_frame(struct ast_unreal_pvt *p, int isoutbound, struct ast_frame *f,
204 struct ast_channel *us, int us_locked)
206 struct ast_channel *other;
208 /* Recalculate outbound channel */
209 other = isoutbound ? p->owner : p->chan;
214 /* do not queue frame if generator is on both unreal channels */
215 if (us && ast_channel_generator(us) && ast_channel_generator(other)) {
219 /* grab a ref on the channel before unlocking the pvt,
220 * other can not go away from us now regardless of locking */
221 ast_channel_ref(other);
222 if (us && us_locked) {
223 ast_channel_unlock(us);
227 if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_RINGING) {
228 ast_setstate(other, AST_STATE_RINGING);
230 ast_queue_frame(other, f);
232 other = ast_channel_unref(other);
233 if (us && us_locked) {
234 ast_channel_lock(us);
241 int ast_unreal_answer(struct ast_channel *ast)
243 struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
253 isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
255 /* Pass along answer since somebody answered us */
256 struct ast_frame answer = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } };
258 res = unreal_queue_frame(p, isoutbound, &answer, ast, 1);
260 ast_log(LOG_WARNING, "Huh? %s is being asked to answer?\n",
261 ast_channel_name(ast));
270 * \brief Check and optimize out the unreal channels between bridges.
273 * \param ast Channel writing a frame into the unreal channels.
274 * \param p Unreal channel private.
276 * \note It is assumed that ast is locked.
277 * \note It is assumed that p is locked.
279 * \retval 0 if unreal channels were not optimized out.
280 * \retval non-zero if unreal channels were optimized out.
282 static int got_optimized_out(struct ast_channel *ast, struct ast_unreal_pvt *p)
286 /* Do a few conditional checks early on just to see if this optimization is possible */
287 if (ast_test_flag(p, AST_UNREAL_NO_OPTIMIZATION) || !p->chan || !p->owner) {
291 if (ast == p->owner) {
292 res = ast_bridge_unreal_optimize_out(p->owner, p->chan, p);
293 } else if (ast == p->chan) {
294 res = ast_bridge_unreal_optimize_out(p->chan, p->owner, p);
300 struct ast_frame *ast_unreal_read(struct ast_channel *ast)
302 return &ast_null_frame;
305 int ast_unreal_write(struct ast_channel *ast, struct ast_frame *f)
307 struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
314 /* Just queue for delivery to the other side */
317 switch (f->frametype) {
318 case AST_FRAME_VOICE:
319 case AST_FRAME_VIDEO:
320 if (got_optimized_out(ast, p)) {
325 res = unreal_queue_frame(p, AST_UNREAL_IS_OUTBOUND(ast, p), f, ast, 1);
334 int ast_unreal_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
336 struct ast_unreal_pvt *p = ast_channel_tech_pvt(newchan);
337 struct ast_bridge *bridge_owner;
338 struct ast_bridge *bridge_chan;
346 if ((p->owner != oldchan) && (p->chan != oldchan)) {
347 ast_log(LOG_WARNING, "Old channel %p wasn't %p or %p\n", oldchan, p->owner, p->chan);
351 if (p->owner == oldchan) {
357 if (ast_check_hangup(newchan) || !p->owner || !p->chan) {
362 /* Do not let a masquerade cause an unreal channel to be bridged to itself! */
363 bridge_owner = ast_channel_internal_bridge(p->owner);
364 bridge_chan = ast_channel_internal_bridge(p->chan);
365 if (bridge_owner && bridge_owner == bridge_chan) {
366 ast_log(LOG_WARNING, "You can not bridge an unreal channel (%s) to itself!\n",
367 ast_channel_name(newchan));
369 ast_queue_hangup(newchan);
379 * \brief Queue up a frame representing the indication as a control frame.
382 * \param p Unreal private structure.
383 * \param ast Channel indicating the condition.
384 * \param condition What is being indicated.
385 * \param data Extra data.
386 * \param datalen Length of extra data.
388 * \retval 0 on success.
389 * \retval AST_T38_REQUEST_PARMS if successful and condition is AST_CONTROL_T38_PARAMETERS.
390 * \retval -1 on error.
392 static int unreal_queue_indicate(struct ast_unreal_pvt *p, struct ast_channel *ast, int condition, const void *data, size_t datalen)
399 * Block -1 stop tones events if we are to be optimized out. We
400 * don't need a flurry of these events on an unreal channel chain
401 * when initially connected to slow the optimization process.
403 if (0 <= condition || ast_test_flag(p, AST_UNREAL_NO_OPTIMIZATION)) {
404 struct ast_frame f = {
405 .frametype = AST_FRAME_CONTROL,
406 .subclass.integer = condition,
407 .data.ptr = (void *) data,
411 isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
412 res = unreal_queue_frame(p, isoutbound, &f, ast, 1);
414 && condition == AST_CONTROL_T38_PARAMETERS
415 && datalen == sizeof(struct ast_control_t38_parameters)) {
416 const struct ast_control_t38_parameters *parameters = data;
418 if (parameters->request_response == AST_T38_REQUEST_PARMS) {
419 res = AST_T38_REQUEST_PARMS;
423 ast_debug(4, "Blocked indication %d\n", condition);
432 * \brief Handle COLP and redirecting conditions.
435 * \param p Unreal private structure.
436 * \param ast Channel indicating the condition.
437 * \param condition What is being indicated.
439 * \retval 0 on success.
440 * \retval -1 on error.
442 static int unreal_colp_redirect_indicate(struct ast_unreal_pvt *p, struct ast_channel *ast, int condition)
444 struct ast_channel *this_channel;
445 struct ast_channel *the_other_channel;
450 * A connected line update frame may only contain a partial
451 * amount of data, such as just a source, or just a ton, and not
452 * the full amount of information. However, the collected
453 * information is all stored in the outgoing channel's
454 * connectedline structure, so when receiving a connected line
455 * update on an outgoing unreal channel, we need to transmit the
456 * collected connected line information instead of whatever
457 * happens to be in this control frame. The same applies for
458 * redirecting information, which is why it is handled here as
462 isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
464 this_channel = p->chan;
465 the_other_channel = p->owner;
467 this_channel = p->owner;
468 the_other_channel = p->chan;
470 if (the_other_channel) {
471 unsigned char frame_data[1024];
472 struct ast_frame f = {
473 .frametype = AST_FRAME_CONTROL,
474 .subclass.integer = condition,
475 .data.ptr = frame_data,
478 if (condition == AST_CONTROL_CONNECTED_LINE) {
479 ast_connected_line_copy_to_caller(ast_channel_caller(the_other_channel),
480 ast_channel_connected(this_channel));
481 f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data),
482 ast_channel_connected(this_channel), NULL);
484 f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data),
485 ast_channel_redirecting(this_channel), NULL);
487 res = unreal_queue_frame(p, isoutbound, &f, ast, 1);
494 int ast_unreal_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
496 struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
503 ao2_ref(p, 1); /* ref for unreal_queue_frame */
506 case AST_CONTROL_CONNECTED_LINE:
507 case AST_CONTROL_REDIRECTING:
508 res = unreal_colp_redirect_indicate(p, ast, condition);
510 case AST_CONTROL_HOLD:
511 if (ast_test_flag(p, AST_UNREAL_MOH_INTERCEPT)) {
512 ast_moh_start(ast, data, NULL);
515 res = unreal_queue_indicate(p, ast, condition, data, datalen);
517 case AST_CONTROL_UNHOLD:
518 if (ast_test_flag(p, AST_UNREAL_MOH_INTERCEPT)) {
522 res = unreal_queue_indicate(p, ast, condition, data, datalen);
525 res = unreal_queue_indicate(p, ast, condition, data, datalen);
533 int ast_unreal_digit_begin(struct ast_channel *ast, char digit)
535 struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
537 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
544 ao2_ref(p, 1); /* ref for unreal_queue_frame */
546 isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
547 f.subclass.integer = digit;
548 res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
555 int ast_unreal_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
557 struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
559 struct ast_frame f = { AST_FRAME_DTMF_END, };
566 ao2_ref(p, 1); /* ref for unreal_queue_frame */
568 isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
569 f.subclass.integer = digit;
571 res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
578 int ast_unreal_sendtext(struct ast_channel *ast, const char *text)
580 struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
582 struct ast_frame f = { AST_FRAME_TEXT, };
589 ao2_ref(p, 1); /* ref for unreal_queue_frame */
591 isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
592 f.data.ptr = (char *) text;
593 f.datalen = strlen(text) + 1;
594 res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
600 int ast_unreal_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
602 struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
604 struct ast_frame f = { AST_FRAME_HTML, };
611 ao2_ref(p, 1); /* ref for unreal_queue_frame */
613 isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
614 f.subclass.integer = subclass;
615 f.data.ptr = (char *)data;
617 res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
624 void ast_unreal_call_setup(struct ast_channel *semi1, struct ast_channel *semi2)
626 struct ast_var_t *varptr;
627 struct ast_var_t *clone_var;
630 * Note that cid_num and cid_name aren't passed in the
631 * ast_channel_alloc calls in ast_unreal_new_channels(). It's
634 ast_party_redirecting_copy(ast_channel_redirecting(semi2), ast_channel_redirecting(semi1));
636 ast_party_dialed_copy(ast_channel_dialed(semi2), ast_channel_dialed(semi1));
638 ast_connected_line_copy_to_caller(ast_channel_caller(semi2), ast_channel_connected(semi1));
639 ast_connected_line_copy_from_caller(ast_channel_connected(semi2), ast_channel_caller(semi1));
641 ast_channel_language_set(semi2, ast_channel_language(semi1));
642 ast_channel_accountcode_set(semi2, ast_channel_accountcode(semi1));
643 ast_channel_musicclass_set(semi2, ast_channel_musicclass(semi1));
645 ast_channel_cc_params_init(semi2, ast_channel_get_cc_config_params(semi1));
648 * Make sure we inherit the AST_CAUSE_ANSWERED_ELSEWHERE if it's
649 * set on the queue/dial call request in the dialplan.
651 if (ast_channel_hangupcause(semi1) == AST_CAUSE_ANSWERED_ELSEWHERE) {
652 ast_channel_hangupcause_set(semi2, AST_CAUSE_ANSWERED_ELSEWHERE);
656 * Copy the channel variables from the semi1 channel to the
659 * Note that due to certain assumptions, they MUST be in the
662 AST_LIST_TRAVERSE(ast_channel_varshead(semi1), varptr, entries) {
663 clone_var = ast_var_assign(varptr->name, varptr->value);
665 AST_LIST_INSERT_TAIL(ast_channel_varshead(semi2), clone_var, entries);
668 ast_channel_datastore_inherit(semi1, semi2);
671 int ast_unreal_channel_push_to_bridge(struct ast_channel *ast, struct ast_bridge *bridge)
673 struct ast_bridge_features *features;
674 struct ast_channel *chan;
675 struct ast_channel *owner;
676 RAII_VAR(struct ast_unreal_pvt *, p, NULL, ao2_cleanup);
678 RAII_VAR(struct ast_callid *, bridge_callid, NULL, ast_callid_cleanup);
680 ast_bridge_lock(bridge);
681 bridge_callid = bridge->callid ? ast_callid_ref(bridge->callid) : NULL;
682 ast_bridge_unlock(bridge);
685 SCOPED_CHANNELLOCK(lock, ast);
686 p = ast_channel_tech_pvt(ast);
694 SCOPED_AO2LOCK(lock, p);
705 ast_channel_ref(chan);
706 ast_channel_ref(owner);
710 struct ast_callid *chan_callid;
711 struct ast_callid *owner_callid;
713 /* chan side call ID setting */
714 ast_channel_lock(chan);
716 chan_callid = ast_channel_callid(chan);
718 ast_channel_callid_set(chan, bridge_callid);
720 ast_channel_unlock(chan);
721 ast_callid_cleanup(chan_callid);
723 /* owner side call ID setting */
724 ast_channel_lock(owner);
726 owner_callid = ast_channel_callid(owner);
728 ast_channel_callid_set(owner, bridge_callid);
731 ast_channel_unlock(owner);
732 ast_callid_cleanup(owner_callid);
735 /* We are done with the owner now that its call ID matches the bridge */
736 ast_channel_unref(owner);
739 features = ast_bridge_features_new();
741 ast_channel_unref(chan);
744 ast_set_flag(&features->feature_flags, AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE);
746 /* Impart the semi2 channel into the bridge */
747 if (ast_bridge_impart(bridge, chan, NULL, features, 1)) {
748 ast_bridge_features_destroy(features);
749 ast_channel_unref(chan);
754 ast_set_flag(p, AST_UNREAL_CARETAKER_THREAD);
756 ast_channel_unref(chan);
761 int ast_unreal_hangup(struct ast_unreal_pvt *p, struct ast_channel *ast)
766 struct ast_channel *owner = NULL;
767 struct ast_channel *chan = NULL;
769 /* the pvt isn't going anywhere, it has a ref */
770 ast_channel_unlock(ast);
772 /* lock everything */
773 ast_unreal_lock_all(p, &chan, &owner);
775 if (ast != chan && ast != owner) {
777 goto unreal_hangup_cleanup;
780 cause = ast_channel_hangupcause(ast);
782 if (ast == p->chan) {
783 /* Outgoing side is hanging up. */
784 ast_clear_flag(p, AST_UNREAL_CARETAKER_THREAD);
787 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
790 ast_channel_hangupcause_set(p->owner, cause);
791 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
793 ast_queue_hangup_with_cause(p->owner, cause);
796 /* Owner side is hanging up. */
799 if (cause == AST_CAUSE_ANSWERED_ELSEWHERE) {
800 ast_channel_hangupcause_set(p->chan, AST_CAUSE_ANSWERED_ELSEWHERE);
801 ast_debug(2, "%s has AST_CAUSE_ANSWERED_ELSEWHERE set.\n",
802 ast_channel_name(p->chan));
804 if (!ast_test_flag(p, AST_UNREAL_CARETAKER_THREAD)) {
806 * Need to actually hangup p->chan since nothing else is taking
811 ast_queue_hangup_with_cause(p->chan, cause);
816 /* this is one of our locked channels, doesn't matter which */
817 ast_channel_tech_pvt_set(ast, NULL);
820 unreal_hangup_cleanup:
823 ast_channel_unlock(owner);
824 ast_channel_unref(owner);
827 ast_channel_unlock(chan);
831 ast_channel_unref(chan);
834 /* leave with the channel locked that came in */
835 ast_channel_lock(ast);
840 void ast_unreal_destructor(void *vdoomed)
842 struct ast_unreal_pvt *doomed = vdoomed;
844 doomed->reqcap = ast_format_cap_destroy(doomed->reqcap);
847 struct ast_unreal_pvt *ast_unreal_alloc(size_t size, ao2_destructor_fn destructor, struct ast_format_cap *cap)
849 struct ast_unreal_pvt *unreal;
851 static const struct ast_jb_conf jb_conf = {
854 .resync_threshold = -1,
859 unreal = ao2_alloc(size, destructor);
863 unreal->reqcap = ast_format_cap_dup(cap);
864 if (!unreal->reqcap) {
869 memcpy(&unreal->jb_conf, &jb_conf, sizeof(unreal->jb_conf));
874 struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p,
875 const struct ast_channel_tech *tech, int semi1_state, int semi2_state,
876 const char *exten, const char *context, const struct ast_channel *requestor,
877 struct ast_callid *callid)
879 struct ast_channel *owner;
880 struct ast_channel *chan;
881 const char *linkedid = requestor ? ast_channel_linkedid(requestor) : NULL;
882 struct ast_format fmt;
883 int generated_seqno = ast_atomic_fetchadd_int((int *) &name_sequence, +1);
886 * Allocate two new Asterisk channels
888 * Make sure that the ;2 channel gets the same linkedid as ;1.
889 * You can't pass linkedid to both allocations since if linkedid
890 * isn't set, then each channel will generate its own linkedid.
892 if (!(owner = ast_channel_alloc(1, semi1_state, NULL, NULL, NULL,
893 exten, context, linkedid, 0,
894 "%s/%s-%08x;1", tech->type, p->name, generated_seqno))
895 || !(chan = ast_channel_alloc(1, semi2_state, NULL, NULL, NULL,
896 exten, context, ast_channel_linkedid(owner), 0,
897 "%s/%s-%08x;2", tech->type, p->name, generated_seqno))) {
899 owner = ast_channel_release(owner);
901 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
906 ast_channel_callid_set(owner, callid);
907 ast_channel_callid_set(chan, callid);
910 ast_channel_tech_set(owner, tech);
911 ast_channel_tech_set(chan, tech);
912 ast_channel_tech_pvt_set(owner, p);
913 ast_channel_tech_pvt_set(chan, p);
915 ast_format_cap_copy(ast_channel_nativeformats(owner), p->reqcap);
916 ast_format_cap_copy(ast_channel_nativeformats(chan), p->reqcap);
918 /* Determine our read/write format and set it on each channel */
919 ast_best_codec(p->reqcap, &fmt);
920 ast_format_copy(ast_channel_writeformat(owner), &fmt);
921 ast_format_copy(ast_channel_writeformat(chan), &fmt);
922 ast_format_copy(ast_channel_rawwriteformat(owner), &fmt);
923 ast_format_copy(ast_channel_rawwriteformat(chan), &fmt);
924 ast_format_copy(ast_channel_readformat(owner), &fmt);
925 ast_format_copy(ast_channel_readformat(chan), &fmt);
926 ast_format_copy(ast_channel_rawreadformat(owner), &fmt);
927 ast_format_copy(ast_channel_rawreadformat(chan), &fmt);
929 ast_set_flag(ast_channel_flags(owner), AST_FLAG_DISABLE_DEVSTATE_CACHE);
930 ast_set_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE);
932 ast_jb_configure(owner, &p->jb_conf);
934 if (ast_channel_cc_params_init(owner, requestor
935 ? ast_channel_get_cc_config_params((struct ast_channel *) requestor) : NULL)) {
936 ast_channel_release(owner);
937 ast_channel_release(chan);
941 /* Give the private a ref for each channel. */