diff --git a/src/include/switch_rtp.h b/src/include/switch_rtp.h index fa54a5ac12..1fd94ce688 100644 --- a/src/include/switch_rtp.h +++ b/src/include/switch_rtp.h @@ -433,6 +433,8 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_activate_stun_ping(switch_rtp_t *rtp_ SWITCH_DECLARE(void) switch_rtp_intentional_bugs(switch_rtp_t *rtp_session, switch_rtp_bug_flag_t bugs); +SWITCH_DECLARE(switch_rtp_stats_t *) switch_rtp_get_stats(switch_rtp_t *rtp_session, switch_memory_pool_t *pool); + /*! \} */ diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 7a7166c21c..6ebf7997af 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -426,6 +426,24 @@ typedef enum { } switch_vad_flag_enum_t; typedef uint32_t switch_vad_flag_t; +typedef struct { + switch_size_t raw_bytes; + switch_size_t media_bytes; + switch_size_t packet_count; + switch_size_t media_packet_count; + switch_size_t skip_packet_count; + switch_size_t jb_packet_count; + switch_size_t dtmf_packet_count; + switch_size_t cng_packet_count; + switch_size_t flush_packet_count; +} switch_rtp_numbers_t; + +typedef struct { + switch_rtp_numbers_t in; + switch_rtp_numbers_t out; +} switch_rtp_stats_t; + + #define SWITCH_RTP_CNG_PAYLOAD 13 /*! diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 67fac6ac0b..1b77e00212 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -1689,6 +1689,40 @@ void sofia_glue_tech_absorb_sdp(private_object_t *tech_pvt) } } + +#define add_stat(_i, _s) \ + switch_snprintf(var_name, sizeof(var_name), "rtp_%s_%s", switch_str_nil(prefix), _s) ; \ + switch_snprintf(var_val, sizeof(var_val), "%" SWITCH_SIZE_T_FMT, _i); \ + switch_channel_set_variable(tech_pvt->channel, var_name, var_val) + +static void set_stats(switch_rtp_t *rtp_session, private_object_t *tech_pvt, const char *prefix) +{ + switch_rtp_stats_t *stats = switch_rtp_get_stats(rtp_session, NULL); + char var_name[256] = "", var_val[35] = ""; + + if (stats) { + + add_stat(stats->in.raw_bytes, "in_raw_bytes"); + add_stat(stats->in.media_bytes, "in_media_bytes"); + add_stat(stats->in.packet_count, "in_packet_count"); + add_stat(stats->in.media_packet_count, "in_media_packet_count"); + add_stat(stats->in.skip_packet_count, "in_skip_packet_count"); + add_stat(stats->in.jb_packet_count, "in_jb_packet_count"); + add_stat(stats->in.dtmf_packet_count, "in_dtmf_packet_count"); + add_stat(stats->in.cng_packet_count, "in_cng_packet_count"); + add_stat(stats->in.cng_packet_count, "in_flush_packet_count"); + + add_stat(stats->out.raw_bytes, "out_raw_bytes"); + add_stat(stats->out.media_bytes, "out_media_bytes"); + add_stat(stats->out.packet_count, "out_packet_count"); + add_stat(stats->out.media_packet_count, "out_media_packet_count"); + add_stat(stats->out.skip_packet_count, "out_skip_packet_count"); + add_stat(stats->out.dtmf_packet_count, "out_dtmf_packet_count"); + add_stat(stats->out.cng_packet_count, "out_cng_packet_count"); + + } +} + void sofia_glue_deactivate_rtp(private_object_t *tech_pvt) { int loops = 0; @@ -1700,12 +1734,14 @@ void sofia_glue_deactivate_rtp(private_object_t *tech_pvt) } if (tech_pvt->rtp_session) { + set_stats(tech_pvt->rtp_session, tech_pvt, "audio"); switch_rtp_destroy(&tech_pvt->rtp_session); } else if (tech_pvt->local_sdp_audio_port) { switch_rtp_release_port(tech_pvt->profile->rtpip, tech_pvt->local_sdp_audio_port); } if (tech_pvt->video_rtp_session) { + set_stats(tech_pvt->video_rtp_session, tech_pvt, "video"); switch_rtp_destroy(&tech_pvt->video_rtp_session); } else if (tech_pvt->local_sdp_video_port) { switch_rtp_release_port(tech_pvt->profile->rtpip, tech_pvt->local_sdp_video_port); diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 846fe20f2c..5c0a895048 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -202,6 +202,7 @@ struct switch_rtp { int from_auto; uint32_t cng_count; switch_rtp_bug_flag_t rtp_bugs; + switch_rtp_stats_t stats; }; static int global_init = 0; @@ -1246,8 +1247,14 @@ static void do_2833(switch_rtp_t *rtp_session) rtp_session->dtmf_data.out_digit_packet[3] = (unsigned char) rtp_session->dtmf_data.out_digit_sub_sofar; for (x = 0; x < loops; x++) { - switch_rtp_write_manual(rtp_session, - rtp_session->dtmf_data.out_digit_packet, 4, 0, rtp_session->te, rtp_session->dtmf_data.timestamp_dtmf, &flags); + switch_size_t wrote = switch_rtp_write_manual(rtp_session, + rtp_session->dtmf_data.out_digit_packet, 4, 0, + rtp_session->te, rtp_session->dtmf_data.timestamp_dtmf, &flags); + + rtp_session->stats.out.raw_bytes += wrote; + rtp_session->stats.out.dtmf_packet_count++; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Send %s packet for [%c] ts=%u dur=%d/%d/%d seq=%d\n", loops == 1 ? "middle" : "end", rtp_session->dtmf_data.out_digit, rtp_session->dtmf_data.timestamp_dtmf, @@ -1281,7 +1288,7 @@ static void do_2833(switch_rtp_t *rtp_session) if (switch_queue_trypop(rtp_session->dtmf_data.dtmf_queue, &pop) == SWITCH_STATUS_SUCCESS) { switch_dtmf_t *rdigit = pop; int64_t offset; - + switch_size_t wrote; rtp_session->sending_dtmf = 1; memset(rtp_session->dtmf_data.out_digit_packet, 0, 4); @@ -1302,12 +1309,15 @@ static void do_2833(switch_rtp_t *rtp_session) rtp_session->dtmf_data.timestamp_dtmf = (uint32_t) (rtp_session->dtmf_data.timestamp_dtmf + offset); } } - - switch_rtp_write_manual(rtp_session, - rtp_session->dtmf_data.out_digit_packet, - 4, - rtp_session->rtp_bugs & RTP_BUG_CISCO_SKIP_MARK_BIT_2833 ? 0 : 1, - rtp_session->te, rtp_session->dtmf_data.timestamp_dtmf, &flags); + + wrote =switch_rtp_write_manual(rtp_session, + rtp_session->dtmf_data.out_digit_packet, + 4, + rtp_session->rtp_bugs & RTP_BUG_CISCO_SKIP_MARK_BIT_2833 ? 0 : 1, + rtp_session->te, rtp_session->dtmf_data.timestamp_dtmf, &flags); + + rtp_session->stats.out.raw_bytes += wrote; + rtp_session->stats.out.dtmf_packet_count++; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Send start packet for [%c] ts=%u dur=%d/%d/%d seq=%d\n", rtp_session->dtmf_data.out_digit, @@ -1350,6 +1360,11 @@ static void do_flush(switch_rtp_t *rtp_session) if (switch_rtp_ready(rtp_session)) { bytes = sizeof(rtp_msg_t); status = switch_socket_recvfrom(rtp_session->from_addr, rtp_session->sock_input, 0, (void *) &rtp_session->recv_msg, &bytes); + if (bytes) { + rtp_session->stats.in.raw_bytes += bytes; + rtp_session->stats.in.flush_packet_count++; + rtp_session->stats.in.packet_count++; + } } else { break; } @@ -1376,6 +1391,20 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t *bytes = sizeof(rtp_msg_t); status = switch_socket_recvfrom(rtp_session->from_addr, rtp_session->sock_input, 0, (void *) &rtp_session->recv_msg, bytes); + if (*bytes) { + rtp_session->stats.in.raw_bytes += *bytes; + if (rtp_session->te && rtp_session->recv_msg.header.pt == rtp_session->te) { + rtp_session->stats.in.dtmf_packet_count++; + } else if (rtp_session->cng_pt && (rtp_session->recv_msg.header.pt == rtp_session->cng_pt || rtp_session->recv_msg.header.pt == 13)) { + rtp_session->stats.in.cng_packet_count++; + } else { + rtp_session->stats.in.media_packet_count++; + rtp_session->stats.in.media_bytes += *bytes; + } + + rtp_session->stats.in.packet_count++; + } + if (rtp_session->jb && rtp_session->recv_msg.header.version == 2 && *bytes) { if (rtp_session->recv_msg.header.m && rtp_session->recv_msg.header.pt != rtp_session->te) { stfu_n_reset(rtp_session->jb); @@ -1391,6 +1420,8 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t memcpy(rtp_session->recv_msg.body, jb_frame->data, jb_frame->dlen); if (jb_frame->plc) { *flags |= SFF_PLC; + } else { + rtp_session->stats.in.jb_packet_count++; } *bytes = jb_frame->dlen + rtp_header_len; rtp_session->recv_msg.header.ts = htonl(jb_frame->ts); @@ -1741,6 +1772,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ *flags |= SFF_CNG; *payload_type = (switch_payload_t) rtp_session->recv_msg.header.pt; ret = 2 + rtp_header_len; + rtp_session->stats.in.skip_packet_count++; goto end; } @@ -2193,6 +2225,16 @@ static int rtp_common_write(switch_rtp_t *rtp_session, goto end; } + rtp_session->stats.out.raw_bytes += bytes; + rtp_session->stats.out.packet_count++; + + if (send_msg->header.pt == rtp_session->cng_pt) { + rtp_session->stats.out.cng_packet_count++; + } else { + rtp_session->stats.out.media_packet_count++; + rtp_session->stats.out.media_bytes += bytes; + } + if (rtp_session->timer.interval) { rtp_session->last_write_samplecount = rtp_session->timer.samplecount; } else { @@ -2303,6 +2345,12 @@ SWITCH_DECLARE(int) switch_rtp_write_frame(switch_rtp_t *rtp_session, switch_fra if (switch_socket_sendto(rtp_session->sock_output, rtp_session->remote_addr, 0, frame->packet, &bytes) != SWITCH_STATUS_SUCCESS) { return -1; } + + rtp_session->stats.out.raw_bytes += bytes; + rtp_session->stats.out.media_bytes += bytes; + rtp_session->stats.out.media_packet_count++; + rtp_session->stats.out.packet_count++; + return (int) bytes; } @@ -2318,7 +2366,13 @@ SWITCH_DECLARE(int) switch_rtp_write_frame(switch_rtp_t *rtp_session, switch_fra } if (switch_test_flag(frame, SFF_RTP_HEADER)) { - return switch_rtp_write_manual(rtp_session, frame->data, frame->datalen, frame->m, frame->payload, (uint32_t) (frame->timestamp), &frame->flags); + switch_size_t wrote = switch_rtp_write_manual(rtp_session, frame->data, frame->datalen, + frame->m, frame->payload, (uint32_t) (frame->timestamp), &frame->flags); + + rtp_session->stats.out.raw_bytes += wrote; + rtp_session->stats.out.media_bytes += wrote; + rtp_session->stats.out.media_packet_count++; + rtp_session->stats.out.packet_count++; } if (fwd) { @@ -2337,6 +2391,20 @@ SWITCH_DECLARE(int) switch_rtp_write_frame(switch_rtp_t *rtp_session, switch_fra return rtp_common_write(rtp_session, send_msg, data, len, payload, ts, &frame->flags); } +SWITCH_DECLARE(switch_rtp_stats_t *) switch_rtp_get_stats(switch_rtp_t *rtp_session, switch_memory_pool_t *pool) +{ + switch_rtp_stats_t *s; + + if (pool) { + s = switch_core_alloc(pool, sizeof(*s)); + *s = rtp_session->stats; + } else { + s = &rtp_session->stats; + } + + return s; +} + SWITCH_DECLARE(int) switch_rtp_write_manual(switch_rtp_t *rtp_session, void *data, uint32_t datalen, uint8_t m, switch_payload_t payload, uint32_t ts, switch_frame_flag_t *flags) {