diff --git a/src/channels/chan_voicemngr.c b/src/channels/chan_voicemngr.c index 890cad713975086637f79f94b1f861684f225a0b..eaa896dd0176ec4e4840e0885cb13903146e1ecf 100644 --- a/src/channels/chan_voicemngr.c +++ b/src/channels/chan_voicemngr.c @@ -79,7 +79,8 @@ static int cwtimeout_cb(const void *data); static int cwbeep_cb(const void *data); static int r4hanguptimeout_cb(const void *data); static void chan_voicemngr_generate_rtp_packet(struct chan_voicemngr_subchannel *p, uint8_t *packet_buf, int type, int seqno, unsigned int rtp_timestamp); -static void chan_voicemngr_process_rtcp_packet(struct chan_voicemngr_subchannel *p, uint8_t *rtcp_frame, uint32_t rtcp_size); +static void chan_voicemngr_process_incoming_rtcp_packet(struct chan_voicemngr_subchannel *p, uint8_t *rtcp_frame, uint32_t rtcp_size); +static void chan_voicemngr_process_outgoing_rtcp_packet(struct chan_voicemngr_subchannel *p, uint8_t *rtcp_frame, uint32_t rtcp_size); static int chan_voicemngr_mute_connection(struct chan_voicemngr_subchannel *p); static int chan_voicemngr_unmute_connection(struct chan_voicemngr_subchannel *p); static int chan_voicemngr_close_connection(struct chan_voicemngr_subchannel *p); @@ -1796,7 +1797,7 @@ static int chan_voicemngr_write(struct ast_channel *ast, struct ast_frame *frame /* copy frame data to audio packet */ memcpy(ap->rtp, frame->data.ptr, frame->datalen); - chan_voicemngr_process_rtcp_packet(sub, ap->rtp, ap->rtp_size); + chan_voicemngr_process_incoming_rtcp_packet(sub, ap->rtp, ap->rtp_size); pe_bus_send(audio_tx_bus, (uint8_t *)ap, packet_size); free(ap); @@ -3108,6 +3109,7 @@ static void audio_packet_handler(pe_packet_t *p) { frame.data.ptr = ap->rtp; frame.datalen = ap->rtp_size; frame.subclass.integer = (packet_type == CHAN_VOICEMNGR_RTCP_SR ? RTCP_SR : RTCP_RR); + chan_voicemngr_process_outgoing_rtcp_packet(sub, ap->rtp, ap->rtp_size); } else { //ast_debug(5, "Dropping RTP frame of type %d.\n", packet_type); drop_frame=1; @@ -3648,8 +3650,12 @@ static struct chan_voicemngr_pvt *chan_voicemngr_allocate_pvt(void) sub->period = default_ptime; // 20 ms sub->conference_initiator = 0; tmp->sub[i] = sub; - sub->jitter_count = 0; - sub->farEndInterrivalJitter = 0; + sub->remote_jitter_count = 0; + sub->local_jitter_count = 0; + sub->farEndInterarrivalJitter = 0; + sub->receiveInterarrivalJitter = 0; + sub->totalFarEndInterarrivalJitter = 0; + sub->totalReceiveInterarrivalJitter = 0; sub->blind_xfer_target[0] = '\0'; ast_debug(2, "subchannel created\n"); } else { @@ -4522,7 +4528,8 @@ enum { RTP_STATS_TX_PKTS, RTP_STATS_JB_AVG, RTP_STATS_JITTER, - RTP_STATS_LOSS_RATE, + RTP_STATS_LOCAL_LOSS_RATE, + RTP_STATS_REMOTE_LOSS_RATE, RTP_STATS_MAX_JITTER, RTP_STATS_AVERAGE_ROUND_TRIP_DELAY, RTP_STATS_OVERRUNS, @@ -4554,7 +4561,8 @@ static const struct blobmsg_policy endpt_rtp_stats_policy[__MAX_RTP_STATS] = { [RTP_STATS_TX_PKTS] = { .name = "txpkts", .type = BLOBMSG_TYPE_INT32 }, [RTP_STATS_JB_AVG] = { .name = "jbAvg", .type = BLOBMSG_TYPE_INT16 }, [RTP_STATS_JITTER] = { .name = "jitter", .type = BLOBMSG_TYPE_INT32 }, - [RTP_STATS_LOSS_RATE] = { .name = "uLossRate", .type = BLOBMSG_TYPE_INT16 }, + [RTP_STATS_LOCAL_LOSS_RATE] = { .name = "localLossRate", .type = BLOBMSG_TYPE_INT16 }, + [RTP_STATS_REMOTE_LOSS_RATE] = { .name = "remoteLossRate", .type = BLOBMSG_TYPE_INT16 }, [RTP_STATS_MAX_JITTER] = { .name = "maxJitter", .type = BLOBMSG_TYPE_INT32 }, [RTP_STATS_AVERAGE_ROUND_TRIP_DELAY] = { .name = "averageRoundTripDelay", .type = BLOBMSG_TYPE_INT32 }, [RTP_STATS_OVERRUNS] = { .name = "overruns", .type = BLOBMSG_TYPE_INT16 }, @@ -4701,8 +4709,10 @@ static void ubus_call_answer_rtp_stats(struct ubus_request *req, int type, struc sub->rtp_stats.jbAvg = blobmsg_get_u16(tb[RTP_STATS_JB_AVG]); if (tb[RTP_STATS_JITTER]) sub->rtp_stats.jitter = blobmsg_get_u32(tb[RTP_STATS_JITTER]); - if (tb[RTP_STATS_LOSS_RATE]) - sub->rtp_stats.uLossRate = blobmsg_get_u16(tb[RTP_STATS_LOSS_RATE]); + if (tb[RTP_STATS_LOCAL_LOSS_RATE]) + sub->rtp_stats.localLossRate = blobmsg_get_u16(tb[RTP_STATS_LOCAL_LOSS_RATE]); + if (tb[RTP_STATS_REMOTE_LOSS_RATE]) + sub->rtp_stats.remoteLossRate = blobmsg_get_u16(tb[RTP_STATS_REMOTE_LOSS_RATE]); if (tb[RTP_STATS_MAX_JITTER]) sub->rtp_stats.maxJitter = blobmsg_get_u32(tb[RTP_STATS_MAX_JITTER]); if (tb[RTP_STATS_AVERAGE_ROUND_TRIP_DELAY]) @@ -4721,7 +4731,10 @@ static void ubus_call_answer_rtp_stats(struct ubus_request *req, int type, struc line_stats[sip_client_id].total_underruns += underruns; } } - sub->rtp_stats.averageFarEndInterarrivalJitter = sub->jitter_count ? (sub->farEndInterrivalJitter / sub->jitter_count) : 0; + sub->rtp_stats.farEndInterarrivalJitter = sub->farEndInterarrivalJitter; + sub->rtp_stats.receiveInterarrivalJitter = sub->receiveInterarrivalJitter; + sub->rtp_stats.averageFarEndInterarrivalJitter = sub->remote_jitter_count ? (sub->totalFarEndInterarrivalJitter / sub->remote_jitter_count) : 0; + sub->rtp_stats.averageReceiveInterarrivalJitter = sub->local_jitter_count ? (sub->totalReceiveInterarrivalJitter / sub->local_jitter_count) : 0; ast_log(LOG_DEBUG, "RTP stats received:\nlocalBurstDensity: %d, remoteBurstDensity: %d, " "localBurstDuration: %d, remoteBurstDuration: %d, localGapDensity: %d, " @@ -4729,16 +4742,18 @@ static void ubus_call_answer_rtp_stats(struct ubus_request *req, int type, struc "localJbRate: %d, remoteJbRate: %d, localJbMax: %d, remoteJbMax: %d, " "localJbNominal: %d remoteJbNominal: %d, localJbAbsMax: %d, " "remoteJbAbsMax: %d, discarded: %d, lost: %d, rxpkts: %d, txpkts: %d, " - "jbAvg: %d, jitter: %d, uLossRate: %d, maxJitter: %d, averageRoundTripDelay: %d, " - "averageFarEndInterarrivalJitter: %d, overruns: %d, underruns: %d\n", + "jbAvg: %d, jitter: %d, localLossRate: %d, remoteLossRate: %d, maxJitter: %d, averageRoundTripDelay: %d, " + "farEndInterarrivalJitter: %d, averageFarEndInterarrivalJitter: %d, receiveInterarrivalJitter: %d, averageReceiveInterarrivalJitter: %d, " + "overruns: %d, underruns: %d\n", sub->rtp_stats.localBurstDensity, sub->rtp_stats.remoteBurstDensity, sub->rtp_stats.localBurstDuration, sub->rtp_stats.remoteBurstDuration, sub->rtp_stats.localGapDensity, sub->rtp_stats.remoteGapDensity, sub->rtp_stats.localGapDuration, sub->rtp_stats.remoteGapDuration, sub->rtp_stats.localJbRate, sub->rtp_stats.remoteJbRate, sub->rtp_stats.localJbMax, sub->rtp_stats.remoteJbMax, sub->rtp_stats.localJbNominal, sub->rtp_stats.remoteJbNominal, sub->rtp_stats.localJbAbsMax, sub->rtp_stats.remoteJbAbsMax, sub->rtp_stats.discarded, sub->rtp_stats.lost, sub->rtp_stats.rxpkts, sub->rtp_stats.txpkts, sub->rtp_stats.jbAvg, sub->rtp_stats.jitter, - sub->rtp_stats.uLossRate, sub->rtp_stats.maxJitter, sub->rtp_stats.averageRoundTripDelay, - sub->rtp_stats.averageFarEndInterarrivalJitter, overruns, underruns); + sub->rtp_stats.localLossRate, sub->rtp_stats.remoteLossRate, sub->rtp_stats.maxJitter, sub->rtp_stats.averageRoundTripDelay, + sub->rtp_stats.farEndInterarrivalJitter, sub->rtp_stats.averageFarEndInterarrivalJitter, sub->rtp_stats.receiveInterarrivalJitter, sub->rtp_stats.averageReceiveInterarrivalJitter, + overruns, underruns); } static int endpt_get_rtp_stats(int line) { @@ -5245,8 +5260,12 @@ static int chan_voicemngr_create_connection(struct chan_voicemngr_subchannel *su ast_debug(1, "Creating virtual Asterisk connection for pvt line_id=%i connection_id=%d\n", sub->parent->line_id, sub->connection_id); sub->connection_init = 1; - sub->jitter_count = 0; - sub->farEndInterrivalJitter = 0; + sub->remote_jitter_count = 0; + sub->local_jitter_count = 0; + sub->farEndInterarrivalJitter = 0; + sub->receiveInterarrivalJitter = 0; + sub->totalFarEndInterarrivalJitter = 0; + sub->totalReceiveInterarrivalJitter = 0; if (sub->owner) { sub->call_id = ast_channel_callid(sub->owner); @@ -5516,10 +5535,10 @@ static void chan_voicemngr_generate_rtp_packet(struct chan_voicemngr_subchannel * This function does the followings. * - Replace SSRC with the value from the sub-channel, which is also used by the corresponding RTP packets within * the same session. Both RTP and RTCP packets in the same session must have the same SSRC value. - * - Accumulate "Interarrival jitter" for farEndInterrivalJitter and jitter_count which are used to calculate + * - Accumulate "Interarrival jitter" for farEndInterarrivalJitter and remote_jitter_count which are used to calculate * averageFarEndInterarrivalJitter. */ -static void chan_voicemngr_process_rtcp_packet(struct chan_voicemngr_subchannel *p, uint8_t *rtcp_frame, uint32_t rtcp_size) +static void chan_voicemngr_process_incoming_rtcp_packet(struct chan_voicemngr_subchannel *p, uint8_t *rtcp_frame, uint32_t rtcp_size) { struct rtcp_header_t *rtcp_hdr = (struct rtcp_header_t *)rtcp_frame; uint8_t *packet_end = rtcp_frame + rtcp_size; @@ -5530,19 +5549,50 @@ static void chan_voicemngr_process_rtcp_packet(struct chan_voicemngr_subchannel RTCP_PKT_END(rtcp_hdr) <= packet_end) { // Packet length validation switch (rtcp_hdr->pt) { case RTCP_SR: - p->jitter_count++; - p->farEndInterrivalJitter += RTCP_SR_GET_INTERARRIVAL_JITTER(rtcp_hdr); + p->remote_jitter_count++; + p->farEndInterarrivalJitter = RTCP_SR_GET_INTERARRIVAL_JITTER(rtcp_hdr); + p->totalFarEndInterarrivalJitter += p->farEndInterarrivalJitter; packet_buf32[7] = p->dsp_ssrc; // replace Source Identifier with dsp's SSRC /* Intentional fall through */ case RTCP_RR: case RTCP_SDES: case RTCP_XR: + case RTCP_BYE: // Replace SSRC with far end SSRC for all types of RTCP packets above rtcp_hdr->ssrc = p->far_end_ssrc; break; default: - ast_log(LOG_ERROR, "Unknown RTCP packet type:%hhu\n", rtcp_hdr->pt); + ast_log(LOG_ERROR, "Unknown incoming RTCP packet type:%hhu\n", rtcp_hdr->pt); + break; + } + // Move to the next RTCP header for a compound RTCP packet which contains more than one packet types + rtcp_hdr = (struct rtcp_header_t *)RTCP_PKT_END(rtcp_hdr); + } +} + +static void chan_voicemngr_process_outgoing_rtcp_packet(struct chan_voicemngr_subchannel *p, uint8_t *rtcp_frame, uint32_t rtcp_size) +{ + struct rtcp_header_t *rtcp_hdr = (struct rtcp_header_t *)rtcp_frame; + uint8_t *packet_end = rtcp_frame + rtcp_size; + + while ((uint8_t *)rtcp_hdr + sizeof(struct rtcp_header_t) <= packet_end && // Minimum RTCP packet size validation + RTCP_GET_VERSION(rtcp_hdr) == RTP_VERSION && // RTP version validation + RTCP_PKT_END(rtcp_hdr) <= packet_end) { // Packet length validation + switch (rtcp_hdr->pt) { + case RTCP_SR: + p->local_jitter_count++; + p->receiveInterarrivalJitter = RTCP_SR_GET_INTERARRIVAL_JITTER(rtcp_hdr); + p->totalReceiveInterarrivalJitter += p->receiveInterarrivalJitter; + break; + case RTCP_RR: + case RTCP_SDES: + case RTCP_XR: + case RTCP_BYE: + break; + + default: + ast_log(LOG_ERROR, "Unknown outgoing RTCP packet type:%hhu\n", rtcp_hdr->pt); break; } // Move to the next RTCP header for a compound RTCP packet which contains more than one packet types diff --git a/src/channels/chan_voicemngr.h b/src/channels/chan_voicemngr.h index f876e38d39ff763f23a6ecd14e13ee062e45964d..dd5d985f2113934cd4e6ecb0d3db47ffc64bedea 100644 --- a/src/channels/chan_voicemngr.h +++ b/src/channels/chan_voicemngr.h @@ -131,6 +131,7 @@ struct line_stats_t { #define RTCP_SR 200 #define RTCP_RR 201 #define RTCP_SDES 202 +#define RTCP_BYE 203 #define RTCP_XR 207 struct __attribute__((packed)) rtcp_header_t { uint8_t v_p_rc; // Version, padding and reception report count @@ -169,8 +170,12 @@ struct chan_voicemngr_subchannel { char *conference_id; /* uuid of the conference initiated by this subchannel */ int conf_timer_id; /* Current conference call timer id, -1 if no active timer */ rtp_statistics rtp_stats; /* RTP statistics for currently hanging up channel */ - unsigned int jitter_count; - unsigned long int farEndInterrivalJitter; + unsigned int remote_jitter_count; + unsigned int local_jitter_count; + unsigned int farEndInterarrivalJitter; + unsigned int receiveInterarrivalJitter; + unsigned long int totalFarEndInterarrivalJitter; + unsigned long int totalReceiveInterarrivalJitter; char blind_xfer_target[32]; /* Transfer target for unattended call transfer */ int updated_codec; int sip_client_id; /* The SIP client used for the current call */