diff --git a/apps/app_dial.c b/apps/app_dial.c index ec8eb6410a4e5409beb5e0fe2f8810773d8f6260..8f9a050712af7eb89a71e12e566c395ae547ed60 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -575,8 +575,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct dial_l OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | OPT_CALLEE_PARK | OPT_CALLER_PARK | DIAL_NOFORWARDHTML); - /* Setup RTP early bridge if appropriate */ - ast_rtp_early_bridge(in, peer); + /* Setup early bridge if appropriate */ + ast_channel_early_bridge(in, peer); } /* If call has been answered, then the eventual hangup is likely to be normal hangup */ in->hangupcause = AST_CAUSE_NORMAL_CLEARING; @@ -605,7 +605,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct dial_l ast_verbose(VERBOSE_PREFIX_3 "%s is ringing\n", c->name); /* Setup early media if appropriate */ if (single) - ast_rtp_early_bridge(in, c); + ast_channel_early_bridge(in, c); if (!(*sentringing) && !ast_test_flag(outgoing, OPT_MUSICBACK)) { ast_indicate(in, AST_CONTROL_RINGING); (*sentringing)++; @@ -616,7 +616,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct dial_l ast_verbose (VERBOSE_PREFIX_3 "%s is making progress passing it to %s\n", c->name, in->name); /* Setup early media if appropriate */ if (single) - ast_rtp_early_bridge(in, c); + ast_channel_early_bridge(in, c); if (!ast_test_flag(outgoing, OPT_RINGBACK)) ast_indicate(in, AST_CONTROL_PROGRESS); break; @@ -629,7 +629,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct dial_l if (option_verbose > 2) ast_verbose (VERBOSE_PREFIX_3 "%s is proceeding passing it to %s\n", c->name, in->name); if (single) - ast_rtp_early_bridge(in, c); + ast_channel_early_bridge(in, c); if (!ast_test_flag(outgoing, OPT_RINGBACK)) ast_indicate(in, AST_CONTROL_PROCEEDING); break; @@ -1624,7 +1624,7 @@ out: sentringing = 0; ast_indicate(chan, -1); } - ast_rtp_early_bridge(chan, NULL); + ast_channel_early_bridge(chan, NULL); hanguptree(outgoing, NULL); pbx_builtin_setvar_helper(chan, "DIALSTATUS", status); if (option_debug) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index a21760d20178820c52dc9c5b1528b4a8594a3f88..ed9650fd558adc229ba03e716e99a9aa1365d555 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1527,6 +1527,7 @@ static const struct ast_channel_tech sip_tech = { .send_digit_begin = sip_senddigit_begin, .send_digit_end = sip_senddigit_end, .bridge = ast_rtp_bridge, + .early_bridge = ast_rtp_early_bridge, .send_text = sip_sendtext, }; diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index d54a1bdd797d3a7dfeceb3ad69aa290eee1caafa..4f636d1853e7e9d2bca58f58a4f62195651d16bc 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -238,6 +238,9 @@ struct ast_channel_tech { enum ast_bridge_result (* const bridge)(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms); + /*! \brief Bridge two channels of the same type together (early) */ + enum ast_bridge_result (* const early_bridge)(struct ast_channel *c0, struct ast_channel *c1); + /*! \brief Indicate a particular condition (e.g. AST_CONTROL_BUSY or AST_CONTROL_RINGING or AST_CONTROL_CONGESTION */ int (* const indicate)(struct ast_channel *c, int condition, const void *data, size_t datalen); @@ -965,6 +968,13 @@ int ast_readstring_full(struct ast_channel *c, char *s, int len, int timeout, in * \return Returns 0 on success and -1 if it could not be done */ int ast_channel_make_compatible(struct ast_channel *c0, struct ast_channel *c1); +/*! Bridge two channels together (early) + * \param c0 first channel to bridge + * \param c1 second channel to bridge + * Bridge two channels (c0 and c1) together early. This implies either side may not be answered yet. + * \return Returns 0 on success and -1 if it could not be done */ +int ast_channel_early_bridge(struct ast_channel *c0, struct ast_channel *c1); + /*! Bridge two channels together * \param c0 first channel to bridge * \param c1 second channel to bridge diff --git a/include/asterisk/rtp.h b/include/asterisk/rtp.h index c332159ecca6ef12651bd3148f6ee81077f789c8..03f2044532228aeb763b5317f7d70cfb5bc6eba3 100644 --- a/include/asterisk/rtp.h +++ b/include/asterisk/rtp.h @@ -196,7 +196,7 @@ int ast_rtp_make_compatible(struct ast_channel *dest, struct ast_channel *src, i /*! \brief If possible, create an early bridge directly between the devices without having to send a re-invite later */ -int ast_rtp_early_bridge(struct ast_channel *dest, struct ast_channel *src); +int ast_rtp_early_bridge(struct ast_channel *c0, struct ast_channel *c1); void ast_rtp_stop(struct ast_rtp *rtp); diff --git a/main/channel.c b/main/channel.c index 9c9f1daa314e043ef3c27784ab7d16c8dd4b536d..3df9191f8f77176951834ed2b7d98332040937a8 100644 --- a/main/channel.c +++ b/main/channel.c @@ -3675,6 +3675,16 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct return res; } +/*! \brief Bridge two channels together (early) */ +int ast_channel_early_bridge(struct ast_channel *c0, struct ast_channel *c1) +{ + /* Make sure we can early bridge, if not error out */ + if (!c0->tech->early_bridge || (c1 && (!c1->tech->early_bridge || c0->tech->early_bridge != c1->tech->early_bridge))) + return -1; + + return c0->tech->early_bridge(c0, c1); +} + /*! \brief Bridge two channels together */ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, struct ast_bridge_config *config, struct ast_frame **fo, struct ast_channel **rc) diff --git a/main/rtp.c b/main/rtp.c index 748837eee484c75c1515c37ff723f97ae92c4273..151bb7376575c3d530dc353e626550c6349c8983 100644 --- a/main/rtp.c +++ b/main/rtp.c @@ -1374,8 +1374,9 @@ static struct ast_rtp_protocol *get_proto(struct ast_channel *chan) return cur; } -int ast_rtp_early_bridge(struct ast_channel *dest, struct ast_channel *src) +int ast_rtp_early_bridge(struct ast_channel *c0, struct ast_channel *c1) { + // dest = c0, src = c1 struct ast_rtp *destp = NULL, *srcp = NULL; /* Audio RTP Channels */ struct ast_rtp *vdestp = NULL, *vsrcp = NULL; /* Video RTP channels */ struct ast_rtp_protocol *destpr = NULL, *srcpr = NULL; @@ -1384,68 +1385,68 @@ int ast_rtp_early_bridge(struct ast_channel *dest, struct ast_channel *src) int srccodec; /* Lock channels */ - ast_channel_lock(dest); - if (src) { - while(ast_channel_trylock(src)) { - ast_channel_unlock(dest); + ast_channel_lock(c0); + if (c1) { + while(ast_channel_trylock(c1)) { + ast_channel_unlock(c0); usleep(1); - ast_channel_lock(dest); + ast_channel_lock(c0); } } /* Find channel driver interfaces */ - destpr = get_proto(dest); - if (src) - srcpr = get_proto(src); + destpr = get_proto(c0); + if (c1) + srcpr = get_proto(c1); if (!destpr) { if (option_debug) - ast_log(LOG_DEBUG, "Channel '%s' has no RTP, not doing anything\n", dest->name); - ast_channel_unlock(dest); - if (src) - ast_channel_unlock(src); - return 0; + ast_log(LOG_DEBUG, "Channel '%s' has no RTP, not doing anything\n", c0->name); + ast_channel_unlock(c0); + if (c1) + ast_channel_unlock(c1); + return -1; } if (!srcpr) { if (option_debug) - ast_log(LOG_DEBUG, "Channel '%s' has no RTP, not doing anything\n", src ? src->name : "<unspecified>"); - ast_channel_unlock(dest); - if (src) - ast_channel_unlock(src); - return 0; + ast_log(LOG_DEBUG, "Channel '%s' has no RTP, not doing anything\n", c1 ? c1->name : "<unspecified>"); + ast_channel_unlock(c0); + if (c1) + ast_channel_unlock(c1); + return -1; } /* Get audio and video interface (if native bridge is possible) */ - audio_dest_res = destpr->get_rtp_info(dest, &destp); - video_dest_res = destpr->get_vrtp_info ? destpr->get_vrtp_info(dest, &vdestp) : AST_RTP_GET_FAILED; + audio_dest_res = destpr->get_rtp_info(c0, &destp); + video_dest_res = destpr->get_vrtp_info ? destpr->get_vrtp_info(c0, &vdestp) : AST_RTP_GET_FAILED; if (srcpr) { - audio_src_res = srcpr->get_rtp_info(src, &srcp); - video_src_res = srcpr->get_vrtp_info ? srcpr->get_vrtp_info(src, &vsrcp) : AST_RTP_GET_FAILED; + audio_src_res = srcpr->get_rtp_info(c1, &srcp); + video_src_res = srcpr->get_vrtp_info ? srcpr->get_vrtp_info(c1, &vsrcp) : AST_RTP_GET_FAILED; } /* Check if bridge is still possible (In SIP canreinvite=no stops this, like NAT) */ if (audio_dest_res != AST_RTP_TRY_NATIVE) { /* Somebody doesn't want to play... */ - ast_channel_unlock(dest); - if (src) - ast_channel_unlock(src); - return 0; + ast_channel_unlock(c0); + if (c1) + ast_channel_unlock(c1); + return -1; } if (audio_src_res == AST_RTP_TRY_NATIVE && srcpr->get_codec) - srccodec = srcpr->get_codec(src); + srccodec = srcpr->get_codec(c1); else srccodec = 0; /* Consider empty media as non-existant */ if (audio_src_res == AST_RTP_TRY_NATIVE && !srcp->them.sin_addr.s_addr) srcp = NULL; /* Bridge media early */ - if (destpr->set_rtp_peer(dest, srcp, vsrcp, srccodec, srcp ? ast_test_flag(srcp, FLAG_NAT_ACTIVE) : 0)) - ast_log(LOG_WARNING, "Channel '%s' failed to setup early bridge to '%s'\n", dest->name, src ? src->name : "<unspecified>"); - ast_channel_unlock(dest); - if (src) - ast_channel_unlock(src); + if (destpr->set_rtp_peer(c0, srcp, vsrcp, srccodec, srcp ? ast_test_flag(srcp, FLAG_NAT_ACTIVE) : 0)) + ast_log(LOG_WARNING, "Channel '%s' failed to setup early bridge to '%s'\n", c0->name, c1 ? c1->name : "<unspecified>"); + ast_channel_unlock(c0); + if (c1) + ast_channel_unlock(c1); if (option_debug) - ast_log(LOG_DEBUG, "Setting early bridge SDP of '%s' with that of '%s'\n", dest->name, src ? src->name : "<unspecified>"); - return 1; + ast_log(LOG_DEBUG, "Setting early bridge SDP of '%s' with that of '%s'\n", c0->name, c1 ? c1->name : "<unspecified>"); + return 0; } int ast_rtp_make_compatible(struct ast_channel *dest, struct ast_channel *src, int media)