diff --git a/channels/chan_sip.c b/channels/chan_sip.c index d623df5ee1aa2e4df95ceb1465912b5598bbcaab..189e4f0646c4b835960ad1c49a6acc739a806fb3 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -2195,6 +2195,7 @@ static int create_addr_from_peer(struct sip_pvt *r, struct sip_peer *peer) ast_rtp_destroy(r->vrtp); r->vrtp = NULL; } + ast_rtp_setdtmf(r->rtp, ast_test_flag(&r->flags[0], SIP_DTMF) != SIP_DTMF_INFO); r->prefs = peer->prefs; natflags = ast_test_flag(&r->flags[0], SIP_NAT) & SIP_NAT_ROUTE; if (r->rtp) { @@ -3524,9 +3525,12 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si free(p); return NULL; } + ast_rtp_setdtmf(p->rtp, ast_test_flag(&p->flags[0], SIP_DTMF) != SIP_DTMF_INFO); ast_rtp_settos(p->rtp, global_tos_audio); - if (p->vrtp) + if (p->vrtp) { ast_rtp_settos(p->vrtp, global_tos_video); + ast_rtp_setdtmf(p->vrtp, 0); + } p->rtptimeout = global_rtptimeout; p->rtpholdtimeout = global_rtpholdtimeout; p->rtpkeepalive = global_rtpkeepalive; @@ -11170,6 +11174,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int get_rdnis(p, NULL); /* Get redirect information */ extract_uri(p, req); /* Get the Contact URI */ build_contact(p); /* Build our contact header */ + ast_rtp_setdtmf(p->rtp, ast_test_flag(&p->flags[0], SIP_DTMF) != SIP_DTMF_INFO); if (gotdest) { if (gotdest == 1 && ast_test_flag(&p->flags[1], SIP_PAGE2_ALLOWOVERLAP)) { diff --git a/include/asterisk/rtp.h b/include/asterisk/rtp.h index 7235639f16d4303fe10b9eb2603eec96d7906d77..5b03d1d861dfe613d1ae70385391b95d69b90ea4 100644 --- a/include/asterisk/rtp.h +++ b/include/asterisk/rtp.h @@ -151,6 +151,9 @@ char *ast_rtp_lookup_mime_multiple(char *buf, int size, const int capability, co void ast_rtp_setnat(struct ast_rtp *rtp, int nat); +/*! \brief Indicate whether this RTP session is carrying DTMF or not */ +void ast_rtp_setdtmf(struct ast_rtp *rtp, int dtmf); + int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms); int ast_rtp_proto_register(struct ast_rtp_protocol *proto); diff --git a/rtp.c b/rtp.c index 841bbbd950dbadc8ed72834bfaf3a9758a03d03f..bfb2262038c09df6d221a27b8f1b72ab7163e05c 100644 --- a/rtp.c +++ b/rtp.c @@ -86,6 +86,7 @@ struct rtpPayloadType { #define FLAG_NAT_ACTIVE (3 << 1) #define FLAG_NAT_INACTIVE (0 << 1) #define FLAG_NAT_INACTIVE_NOWARN (1 << 1) +#define FLAG_HAS_DTMF (1 << 3) /*! \brief RTP session description */ struct ast_rtp { @@ -434,6 +435,11 @@ void ast_rtp_setnat(struct ast_rtp *rtp, int nat) rtp->nat = nat; } +void ast_rtp_setdtmf(struct ast_rtp *rtp, int dtmf) +{ + ast_set2_flag(rtp, dtmf ? 1 : 0, FLAG_HAS_DTMF); +} + static struct ast_frame *send_dtmf(struct ast_rtp *rtp) { char iabuf[INET_ADDRSTRLEN]; @@ -1344,6 +1350,7 @@ struct ast_rtp *ast_rtp_new_with_bindaddr(struct sched_context *sched, struct io rtp->s = rtp_socket(); rtp->ssrc = ast_random(); rtp->seqno = ast_random() & 0xffff; + ast_set_flag(rtp, FLAG_HAS_DTMF); if (rtp->s < 0) { free(rtp); ast_log(LOG_ERROR, "Unable to allocate socket: %s\n", strerror(errno)); @@ -1921,10 +1928,6 @@ enum ast_bridge_result ast_rtp_bridge(struct ast_channel *c0, struct ast_channel memset(&vac0, 0, sizeof(vac0)); memset(&vac1, 0, sizeof(vac1)); - /* if need DTMF, cant native bridge */ - if (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1)) - return AST_BRIDGE_FAILED_NOWARN; - /* Lock channels */ ast_channel_lock(c0); while(ast_channel_trylock(c1)) { @@ -1966,6 +1969,25 @@ enum ast_bridge_result ast_rtp_bridge(struct ast_channel *c0, struct ast_channel ast_channel_unlock(c1); return AST_BRIDGE_FAILED_NOWARN; } + + if (ast_test_flag(p0, FLAG_HAS_DTMF) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) { + /* can't bridge, we are carrying DTMF for this channel and the bridge + needs it + */ + ast_channel_unlock(c0); + ast_channel_unlock(c1); + return AST_BRIDGE_FAILED_NOWARN; + } + + if (ast_test_flag(p1, FLAG_HAS_DTMF) && (flags & AST_BRIDGE_DTMF_CHANNEL_1)) { + /* can't bridge, we are carrying DTMF for this channel and the bridge + needs it + */ + ast_channel_unlock(c0); + ast_channel_unlock(c1); + return AST_BRIDGE_FAILED_NOWARN; + } + /* Get codecs from both sides */ codec0 = pr0->get_codec ? pr0->get_codec(c0) : 0; codec1 = pr1->get_codec ? pr1->get_codec(c1) : 0;