From 7f70d818cdefbf726d1519a264cc552ef72049df Mon Sep 17 00:00:00 2001 From: Yalu Zhang <yalu.zhang@iopsys.eu> Date: Tue, 25 Jun 2024 08:17:56 +0000 Subject: [PATCH] Forward RTP telephone event packets to voicemngr The frame type of RTP telephone event packets is AST_FRAME_DTMF_BYPASS. --- src/channels/chan_voicemngr.c | 144 +++++++++++++++++++--------------- 1 file changed, 79 insertions(+), 65 deletions(-) diff --git a/src/channels/chan_voicemngr.c b/src/channels/chan_voicemngr.c index 00d89b0..188067f 100644 --- a/src/channels/chan_voicemngr.c +++ b/src/channels/chan_voicemngr.c @@ -1283,7 +1283,7 @@ static int chan_voicemngr_senddigit_begin(struct ast_channel *ast, char digit) struct chan_voicemngr_subchannel *sub; char signal[10]; - //ast_debug(5, "DTMF send begin: %c\n", digit); + ast_debug(5, "DTMF send begin: %c\n", digit); sub = ast_channel_tech_pvt(ast); pvt_lock(sub->parent, "DTMF senddigit_begin"); @@ -1301,7 +1301,7 @@ static int chan_voicemngr_senddigit_end(struct ast_channel *ast, char digit, uns struct chan_voicemngr_subchannel *sub; char signal[10]; - //ast_debug(5, "DTMF send end: %c, %d ms\n", digit, duration); + ast_debug(5, "DTMF send end: %c, %d ms\n", digit, duration); sub = ast_channel_tech_pvt(ast); pvt_lock(sub->parent, "DTMF senddigit_end"); @@ -1754,7 +1754,7 @@ static int chan_voicemngr_classify_rtp_packet(int payload_type) { if (voicemngr_codecs[i].rtp_payload_type == payload_type) return CHAN_VOICEMNGR_AUDIO; - ast_verbose("Unknown rtp packet payload_type %d\n", payload_type); + ast_log(LOG_WARNING, "Unknown RTP payload_type %d\n", payload_type); return CHAN_VOICEMNGR_UNKNOWN; } @@ -1764,147 +1764,161 @@ static int map_ast_codec_id_to_rtp(const struct ast_format *astcodec) if (ast_format_cmp(astcodec, *voicemngr_codecs[i].ast_format) == AST_FORMAT_CMP_EQUAL) return voicemngr_codecs[i].rtp_payload_type; - ast_verbose("Unknown asterisk format/codec\n"); + ast_log(LOG_WARNING, "Unknown asterisk format(%s), return PCMA\n", ast_format_get_name(astcodec)); return RTP_PT_PCMA; } - static struct ast_frame *chan_voicemngr_read(struct ast_channel *ast) { return &ast_null_frame; } -/* Handle stream events on audio_bus. Parses raw stream and calls - registered packet handlers. */ +/* Handle stream events on audio_bus. Parses raw stream and calls registered packet handlers. */ static void audio_rx_stream_handler(pe_stream_t *stream __attribute__((unused)), pe_event_t *event __attribute__((unused))) { if (pe_bus_receive(audio_rx_bus, event) < 0) { printf("audio_bus rx buffer full"); - return; // Drop packets if we can't cope the pace + return; // Drop packets if we can't cope the pace } pe_bus_dispatch(audio_rx_bus); } +/* Handle audio packets from Asterisk, i.e. from network */ static int chan_voicemngr_write(struct ast_channel *ast, struct ast_frame *frame) { struct chan_voicemngr_subchannel *sub = ast_channel_tech_pvt(ast); - int packet_size; - audio_packet_t *ap; - int sip_client_id = -1; + int packet_size, payload_type, sip_client_id = -1; + audio_packet_t *ap = NULL; - if (ast_channel_state(ast) != AST_STATE_UP && ast_channel_state(ast) != AST_STATE_RING) { - /* Silently ignore packets until channel is up */ - ast_debug(5, "error: channel not up\n"); + if (sub->channel_state == ONHOLD || (ast_channel_state(ast) != AST_STATE_UP && ast_channel_state(ast) != AST_STATE_RING)) { + ast_debug(5, "Silently ignore the frame since the channel is not in the right state\n"); return 0; } - /* Ignore if on hold */ - if (sub->channel_state == ONHOLD) { - return 0; - } - if (frame->frametype == AST_FRAME_CNG) { - /*packet_size = sizeof(audio_packet_t) - 1 + RTP_HEADER_SIZE + frame->datalen; - CNG paket has only 1 data for the noise lvl, datalen=1*/ - packet_size = sizeof(audio_packet_t) + RTP_HEADER_SIZE ; + if (frame->frametype == AST_FRAME_VOICE) { + packet_size = sizeof(audio_packet_t) - 1 + RTP_HEADER_SIZE + frame->datalen; ap = ast_calloc(1, packet_size); if (!ap) { ast_log(LOG_ERROR, "Out of memory\n"); return -1; } - ap->line = sub->parent->line_id; ap->connection_id = sub->parent->line_id; - ap->rtp_size = RTP_HEADER_SIZE + 1; + ap->rtp_size = RTP_HEADER_SIZE + frame->datalen; /* copy frame data to audio packet */ - /* level = 127 - (level & 0x7f); */ - ap->rtp[12]=127 - (frame->subclass.integer & 0x7f); + memcpy(ap->rtp + RTP_HEADER_SIZE, frame->data.ptr, frame->datalen); - //ast_mutex_lock(&sub->parent->lock); pvt_lock(sub->parent, "TELCHAN write frame"); /* generate the rtp header */ - chan_voicemngr_generate_rtp_packet(sub, ap->rtp, RTP_PT_CN, frame->seqno, frame->ts, frame->ssrc); + payload_type = map_ast_codec_id_to_rtp(frame->subclass.format); + chan_voicemngr_generate_rtp_packet(sub, ap->rtp, payload_type, frame->seqno, frame->ts, frame->ssrc); sip_client_id = chan_voicemngr_get_sip_client_id(sub); if (sip_client_id >= 0 && sip_client_id < MAX_SIP_CLIENTS) { - line_stats[sip_client_id].rxpkts++; - line_stats[sip_client_id].rxbytes += ap->rtp_size; + line_stats[sip_client_id].rxpkts++; + line_stats[sip_client_id].rxbytes += ap->rtp_size; } /* set rtp payload type sent to voicemngr */ - sub->codec = RTP_PT_CN; + sub->codec = payload_type; + /* in case of media played during calling on an outgoing call and there has no codec set + * and dsp do not have the cap to handle any payload type that received. */ + if (sub->owner && ast_strlen_zero(ast_channel_codec_get(sub->owner))) { + ast_channel_codec_set(sub->owner, ast_format_get_name(frame->subclass.format)); + ast_log(LOG_NOTICE, "set local codec to :%s \n", ast_channel_codec_get(sub->owner)); + } - //ast_mutex_unlock(&sub->parent->lock); pvt_unlock(sub->parent); - pe_bus_send(audio_tx_bus, (uint8_t *)ap, packet_size); - ast_free(ap); - } - - if(frame->frametype == AST_FRAME_VOICE) { - packet_size = sizeof(audio_packet_t) - 1 + RTP_HEADER_SIZE + frame->datalen; + chan_voicemngr_modify_codec(sub); // in case of early media on outgoing + } else if(frame->frametype == AST_FRAME_RTCP) { + packet_size = sizeof(audio_packet_t) - 1 + frame->datalen; ap = ast_calloc(1, packet_size); if (!ap) { ast_log(LOG_ERROR, "Out of memory\n"); return -1; } - ap->line = sub->parent->line_id; ap->connection_id = sub->parent->line_id; - ap->rtp_size = RTP_HEADER_SIZE + frame->datalen; + ap->rtp_size = frame->datalen; /* copy frame data to audio packet */ - memcpy(ap->rtp + RTP_HEADER_SIZE, frame->data.ptr, frame->datalen); + memcpy(ap->rtp, frame->data.ptr, frame->datalen); + + chan_voicemngr_process_incoming_rtcp_packet(sub, ap->rtp, ap->rtp_size); + } else if (frame->frametype == AST_FRAME_CNG) { + /* CNG packet has only one byte for the noise level, i.e. frame->datalen=1*/ + packet_size = sizeof(audio_packet_t) + RTP_HEADER_SIZE ; + ap = ast_calloc(1, packet_size); + if (!ap) { + ast_log(LOG_ERROR, "Out of memory\n"); + return -1; + } + ap->line = sub->parent->line_id; + ap->connection_id = sub->parent->line_id; + ap->rtp_size = RTP_HEADER_SIZE + 1; + + /* level = 127 - (level & 0x7f); */ + ap->rtp[12]=127 - (frame->subclass.integer & 0x7f); - //ast_mutex_lock(&sub->parent->lock); pvt_lock(sub->parent, "TELCHAN write frame"); /* generate the rtp header */ - chan_voicemngr_generate_rtp_packet(sub, ap->rtp, map_ast_codec_id_to_rtp(frame->subclass.format), frame->seqno, frame->ts, frame->ssrc); + chan_voicemngr_generate_rtp_packet(sub, ap->rtp, RTP_PT_CN, frame->seqno, frame->ts, frame->ssrc); sip_client_id = chan_voicemngr_get_sip_client_id(sub); if (sip_client_id >= 0 && sip_client_id < MAX_SIP_CLIENTS) { - line_stats[sip_client_id].rxpkts++; - line_stats[sip_client_id].rxbytes += ap->rtp_size; + line_stats[sip_client_id].rxpkts++; + line_stats[sip_client_id].rxbytes += ap->rtp_size; } /* set rtp payload type sent to voicemngr */ - sub->codec = map_ast_codec_id_to_rtp(frame->subclass.format); - //in case of media played during calling on an outgoing call and there has no codec set - //and dsp do not have the cap to handle any payload type that received. - if (sub->owner && ast_strlen_zero(ast_channel_codec_get(sub->owner))) { - ast_channel_codec_set(sub->owner, ast_format_get_name(frame->subclass.format)); - ast_log(LOG_NOTICE, "set local codec to :%s \n", ast_channel_codec_get(sub->owner)); - } + sub->codec = RTP_PT_CN; //ast_mutex_unlock(&sub->parent->lock); pvt_unlock(sub->parent); - chan_voicemngr_modify_codec(sub); //in case of early media on outgoing - - pe_bus_send(audio_tx_bus, (uint8_t *)ap, packet_size); - ast_free(ap); - } - - if(frame->frametype == AST_FRAME_RTCP) { - packet_size = sizeof(audio_packet_t) - 1 + frame->datalen; + } else if (frame->frametype == AST_FRAME_DTMF_BYPASS) { + ast_debug(0, "RTP for Telephone Event: payload type = %d, len = %d, event = %hhu, timestamp = %ld, seqno = %d\n", + frame->subclass.integer, frame->datalen, *(unsigned char *)frame->data.ptr, frame->ts, frame->seqno); + packet_size = sizeof(audio_packet_t) - 1 + RTP_HEADER_SIZE + frame->datalen; ap = ast_calloc(1, packet_size); if (!ap) { ast_log(LOG_ERROR, "Out of memory\n"); return -1; } - ap->line = sub->parent->line_id; ap->connection_id = sub->parent->line_id; - ap->rtp_size = frame->datalen; + ap->rtp_size = RTP_HEADER_SIZE + frame->datalen; /* copy frame data to audio packet */ - memcpy(ap->rtp, frame->data.ptr, frame->datalen); + memcpy(ap->rtp + RTP_HEADER_SIZE, frame->data.ptr, frame->datalen); - chan_voicemngr_process_incoming_rtcp_packet(sub, ap->rtp, ap->rtp_size); + pvt_lock(sub->parent, "TELCHAN write frame"); + /* generate the rtp header */ + payload_type = frame->subclass.integer; + chan_voicemngr_generate_rtp_packet(sub, ap->rtp, payload_type, frame->seqno, frame->ts, frame->ssrc); + + sip_client_id = chan_voicemngr_get_sip_client_id(sub); + if (sip_client_id >= 0 && sip_client_id < MAX_SIP_CLIENTS) { + line_stats[sip_client_id].rxpkts++; + line_stats[sip_client_id].rxbytes += ap->rtp_size; + } + + pvt_unlock(sub->parent); + } else { + char ftype[40] = "Unknown frame type"; + + ast_frame_type2str(frame->frametype, ftype, sizeof(ftype)); + ast_log(LOG_WARNING, "Unsupported frame type, %s(%d)\n", ftype, frame->frametype); + } + + if (ap) { pe_bus_send(audio_tx_bus, (uint8_t *)ap, packet_size); ast_free(ap); } + return 0; } @@ -3294,7 +3308,7 @@ static void audio_packet_handler(pe_packet_t *p) { } else if(payload_type == sub->dtmf_pt) { frame.frametype = AST_FRAME_DTMF_BYPASS; frame.subclass.integer = ap->rtp[1]; //payload_type - ast_debug(3, "DTMF rtp_event for digit: %d, with payload_type: %d \n", ap->rtp[12], ap->rtp[1]); + ast_debug(3, "DTMF rtp_event for digit: %d, with payload_type: %d \n", ap->rtp[12], payload_type); if (sub->conference_initiator == 1) { drop_frame=1; } -- GitLab