diff --git a/channels/chan_brcm.c b/channels/chan_brcm.c index 9d25422c2992686cff15e25ac33c108cc2dad029..e60f56a4773082fc3e87e3c274899b166fee6b61 100644 --- a/channels/chan_brcm.c +++ b/channels/chan_brcm.c @@ -1109,6 +1109,7 @@ static char* brcm_get_codec_string(int id) { case G726: return "g726"; break; case G729: return "g729"; break; case G722: return "g722"; break; + case CN: return "cn"; break; case -1: return "none set"; break; default: return "unknown id"; break; } @@ -1125,6 +1126,7 @@ static int brcm_classify_rtp_packet(int id) { case PCMA: return BRCM_AUDIO; case G729: return BRCM_AUDIO; case G722: return BRCM_AUDIO; + case CN: return BRCM_AUDIO; case RTCP: return BRCM_UNKNOWN; // Ignored packet. default: ast_verbose("Unknown rtp packet id %d\n", id); @@ -1185,12 +1187,44 @@ static int brcm_write(struct ast_channel *ast, struct ast_frame *frame) 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 ; + ap = calloc(1, packet_size); + if (!ap) { + ast_log(LOG_ERROR, "Out of memory\n"); + return -1; + } + + ap->line = sub->parent->line_id; + ap->cnx_id = sub->parent->line_id; + ap->rtp_size = RTP_HEADER_SIZE + 1; + + /* copy frame data to audio packet */ + /* 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 */ + brcm_generate_rtp_packet(sub, ap->rtp, CN, 0, 0); + + /* set rtp id sent to endpoint */ + sub->codec = CN; + + //ast_mutex_unlock(&sub->parent->lock); + pvt_unlock(sub->parent); + pe_bus_send(audio_tx_bus, (uint8_t *)ap, packet_size); + free(ap); + } if(frame->frametype == AST_FRAME_VOICE) { packet_size = sizeof(audio_packet_t) - 1 + RTP_HEADER_SIZE + frame->datalen; ap = calloc(1, packet_size); if (!ap) { - printf("Out of memory\n"); + ast_log(LOG_ERROR, "Out of memory\n"); return -1; } @@ -2230,8 +2264,12 @@ static void audio_packet_handler(pe_packet_t *p) { fr.subclass.format = ast_format_g722; fr.samples = 160; break; + case CN: + fr.frametype = AST_FRAME_CNG; + fr.subclass.integer = ap->rtp[12]; + break; default: - ast_log(LOG_WARNING, "Unknown rtp codec id [%d]\n", p->data[1]); + ast_log(LOG_WARNING, "Unknown rtp codec id [%d], %d\n", ap->rtp[1], p->data[1]); return; } } else { diff --git a/channels/chan_brcm.h b/channels/chan_brcm.h index bfb7867ce864f96a858dcdd65b3e1822a6824a53..4316f43e2aaef82a4510a3be655ed47065190925 100644 --- a/channels/chan_brcm.h +++ b/channels/chan_brcm.h @@ -23,6 +23,7 @@ #define DTMF_PAYLOAD 101 #define DTMF 128 #define RTCP 200 +#define CN 13 #define NOT_INITIALIZED -1 //#define EPSTATUS_DRIVER_ERROR -1 diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index ba8d74e1f9a90dd75edcccc4e1409dd01b3227cd..60db00a5a42521efe64e27543795e8dbb42f6479 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -1017,6 +1017,14 @@ static int chan_pjsip_write_stream(struct ast_channel *ast, int stream_num, stru } break; case AST_FRAME_CNG: + if (!media) { + return 0; + } else if (media->write_callback) { + res = media->write_callback(session, media, frame); + } else { + ast_rtp_instance_sendcng(media->rtp, frame->subclass.integer); + return 0; + } break; case AST_FRAME_RTCP: /* We only support writing out feedback */ diff --git a/main/channel.c b/main/channel.c index 42083c3f47d2b409c7c4915e9b83ff05ace87bd2..436a1d736a9855b3e62a419468445870d9f20b7d 100644 --- a/main/channel.c +++ b/main/channel.c @@ -1068,7 +1068,7 @@ static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, in AST_LIST_INSERT_TAIL(&frames, f, frame_list); new_frames++; - if (f->frametype == AST_FRAME_VOICE) { + if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_CNG) { new_voice_frames++; } } @@ -1076,7 +1076,7 @@ static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, in /* Count how many frames exist on the queue */ AST_LIST_TRAVERSE(ast_channel_readq(chan), cur, frame_list) { queued_frames++; - if (cur->frametype == AST_FRAME_VOICE) { + if (cur->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_CNG) { queued_voice_frames++; } } @@ -1088,7 +1088,7 @@ static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, in /* Save the most recent frame */ if (!AST_LIST_NEXT(cur, frame_list)) { break; - } else if (cur->frametype == AST_FRAME_VOICE || cur->frametype == AST_FRAME_VIDEO || cur->frametype == AST_FRAME_NULL) { + } else if (cur->frametype == AST_FRAME_VOICE || cur->frametype == AST_FRAME_VIDEO || cur->frametype == AST_FRAME_NULL || cur->frametype == AST_FRAME_CNG) { if (++count > 64) { break; } @@ -2764,6 +2764,7 @@ int __ast_answer(struct ast_channel *chan, unsigned int delay) case AST_FRAME_HTML: case AST_FRAME_MODEM: case AST_FRAME_RTCP: + case AST_FRAME_CNG: done = 1; break; case AST_FRAME_CONTROL: @@ -2771,7 +2772,6 @@ int __ast_answer(struct ast_channel *chan, unsigned int delay) case AST_FRAME_BRIDGE_ACTION: case AST_FRAME_BRIDGE_ACTION_SYNC: case AST_FRAME_NULL: - case AST_FRAME_CNG: break; } @@ -3409,7 +3409,7 @@ static void ast_read_generator_actions(struct ast_channel *chan, struct ast_fram generator = ast_channel_generator(chan); if (!generator || !generator->generate - || f->frametype != AST_FRAME_VOICE + || (f->frametype != AST_FRAME_VOICE || f->frametype != AST_FRAME_CNG) || !ast_channel_generatordata(chan) || ast_channel_timingfunc(chan)) { return; @@ -3704,15 +3704,21 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int default: break; } - } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { + } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO || f->frametype == AST_FRAME_CNG) { + enum ast_media_type type = AST_MEDIA_TYPE_UNKNOWN; + if (f->frametype == AST_FRAME_CNG) { + type = AST_MEDIA_TYPE_AUDIO; + } else { + type = ast_format_get_type(f->subclass.format); + } if (ast_channel_tech(chan) && ast_channel_tech(chan)->read_stream) { stream = ast_stream_topology_get_stream(ast_channel_get_stream_topology(chan), f->stream_num); - default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(f->subclass.format)); + default_stream = ast_channel_get_default_stream(chan, type); } else { /* Since this channel driver does not support multistream determine the default stream this frame * originated from and update the frame to include it. */ - stream = default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(f->subclass.format)); + stream = default_stream = ast_channel_get_default_stream(chan, type); /* In order to allow media to be passed up the underlying media type has to have a format negotiated on * the channel itself. In cases where this hasn't happened the channel driver is incorrectly passing up * a frame for a format that has not been negotiated. If this occurs just drop the frame as we have no @@ -3743,9 +3749,13 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int * thing different is that we need to find the default stream so we know whether to invoke the * default stream logic or not (such as transcoding). */ - if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) { + if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO || f->frametype == AST_FRAME_CNG)) { stream = ast_stream_topology_get_stream(ast_channel_get_stream_topology(chan), f->stream_num); - default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(f->subclass.format)); + if (f->frametype == AST_FRAME_CNG) { + default_stream = ast_channel_get_default_stream(chan, AST_MEDIA_TYPE_AUDIO); + } else { + default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(f->subclass.format)); + } } } else if (ast_channel_tech(chan) && ast_channel_tech(chan)->read) { f = ast_channel_tech(chan)->read(chan); @@ -3753,8 +3763,12 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int /* Since this channel driver does not support multistream determine the default stream this frame * originated from and update the frame to include it. */ - if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) { - stream = default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(f->subclass.format)); + if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO || f->frametype == AST_FRAME_CNG)) { + if (f->frametype == AST_FRAME_CNG) { + stream = default_stream = ast_channel_get_default_stream(chan, AST_MEDIA_TYPE_AUDIO); + } else { + stream = default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(f->subclass.format)); + } if (!stream) { ast_frfree(f); f = &ast_null_frame; @@ -5130,7 +5144,7 @@ int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame } stream = ast_stream_topology_get_stream(ast_channel_get_stream_topology(chan), stream_num); default_stream = ast_channel_get_default_stream(chan, ast_stream_get_type(stream)); - } else if (fr->frametype == AST_FRAME_VOICE || fr->frametype == AST_FRAME_VIDEO || fr->frametype == AST_FRAME_MODEM) { + } else if (fr->frametype == AST_FRAME_VOICE || fr->frametype == AST_FRAME_VIDEO || fr->frametype == AST_FRAME_MODEM || fr->frametype == AST_FRAME_CNG) { /* If we haven't been told of a stream then we need to figure out which once we need */ enum ast_media_type type = AST_MEDIA_TYPE_UNKNOWN; @@ -5139,6 +5153,8 @@ int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame type = ast_format_get_type(fr->subclass.format); } else if (fr->frametype == AST_FRAME_MODEM) { type = AST_MEDIA_TYPE_IMAGE; + } else if (fr->frametype == AST_FRAME_CNG) { + type = AST_MEDIA_TYPE_AUDIO; } /* No stream was specified, so use the default one */ @@ -5450,6 +5466,16 @@ int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame } ast_clear_flag(ast_channel_flags(chan), AST_FLAG_BLOCKING); break; + case AST_FRAME_CNG: + CHECK_BLOCKING(chan); + if (ast_channel_tech(chan)->write_stream && stream) { + res = ast_channel_tech(chan)->write_stream(chan, ast_stream_get_position(stream), fr); + } else { + res = ast_channel_tech(chan)->write(chan, fr); + res = 0; + } + ast_clear_flag(ast_channel_flags(chan), AST_FLAG_BLOCKING); + break; default: /* At this point, fr is the incoming frame and f is NULL. Channels do * not expect to get NULL as a frame pointer and will segfault. Hence, diff --git a/main/frame.c b/main/frame.c index 711f9e15f104d6a71d071f948087335d46546bd9..f5e7ad038ea45bc4ed737c81479f752c3d31dab2 100644 --- a/main/frame.c +++ b/main/frame.c @@ -418,6 +418,12 @@ char *ast_frame_subclass2str(struct ast_frame *f, char *subclass, size_t slen, c subclass[1] = '\0'; } break; + case AST_FRAME_CNG: + if (slen > 1) { + subclass[0] = f->subclass.integer; + subclass[1] = '\0'; + } + break; case AST_FRAME_CONTROL: switch (f->subclass.integer) { case AST_CONTROL_HANGUP: @@ -677,6 +683,9 @@ char *ast_frame_type2str(enum ast_frame_type frame_type, char *ftype, size_t len case AST_FRAME_DTMF_END: ast_copy_string(ftype, "DTMF End", len); break; + case AST_FRAME_CNG: + ast_copy_string(ftype, "Comfort Noise", len); + break; case AST_FRAME_CONTROL: ast_copy_string(ftype, "Control", len); break; @@ -761,6 +770,9 @@ void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix) if (f->frametype == AST_FRAME_RTCP) { return; } + if (f->frametype == AST_FRAME_CNG) { + return; + } ast_frame_type2str(f->frametype, ftype, sizeof(ftype)); ast_frame_subclass2str(f, subclass, sizeof(subclass), moreinfo, sizeof(moreinfo)); diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index fe565f66def7b41cfac562f1371eb47ca936ca55..6b25ec43e43c4a7aacb0a72bfcef99c66f465807 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -94,6 +94,7 @@ static int send_keepalive(const void *data) rtp, (int) interval, send_keepalive ? "S" : "Not s"); if (send_keepalive) { + ast_verbose("Send ast_rtp_instance_sendcng\n"); ast_rtp_instance_sendcng(rtp, 0); return keepalive * 1000; } diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index e5bef24258ba2a6a56681104729c1200f0ed78da..14c2f15e5c148d42712c81e707dad73a15ceba9a 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -5311,6 +5311,11 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr } return 0; } + if (frame->frametype == AST_FRAME_CNG) { + /* send CN packet */ + ast_rtp_sendcng(instance, frame->subclass.integer); + return 0; + } /* If there is no data length we can't very well send the packet */ if (!frame->datalen) {