res_rtp_asterisk: Asterisk Media Experience Score (MES)

-----------------

This commit reinstates MES with some casting fixes to the
functions in time.h that convert between doubles and timeval
structures.  The casting issues were causing incorrect
timestamps to be calculated which caused transcoding from/to
G722 to produce bad or no audio.

ASTERISK-30391

-----------------

This module has been updated to provide additional
quality statistics in the form of an Asterisk
Media Experience Score.  The score is avilable using
the same mechanisms you'd use to retrieve jitter, loss,
and rtt statistics.  For more information about the
score and how to retrieve it, see
https://wiki.asterisk.org/wiki/display/AST/Media+Experience+Score

* Updated chan_pjsip to set quality channel variables when a
  call ends.
* Updated channels/pjsip/dialplan_functions.c to add the ability
  to retrieve the MES along with the existing rtcp stats when
  using the CHANNEL dialplan function.
* Added the ast_debug_rtp_is_allowed and ast_debug_rtcp_is_allowed
  checks for debugging purposes.
* Added several function to time.h for manipulating time-in-samples
  and times represented as double seconds.
* Updated rtp_engine.c to pass through the MES when stats are
  requested.  Also debug output that dumps the stats when an
  rtp instance is destroyed.
* Updated res_rtp_asterisk.c to implement the calculation of the
  MES.  In the process, also had to update the calculation of
  jitter.  Many debugging statements were also changed to be
  more informative.
* Added a unit test for internal testing.  The test should not be
  run during normal operation and is disabled by default.

Change-Id: I4fce265965e68c3fdfeca55e614371ee69c65038
This commit is contained in:
George Joseph
2022-10-28 04:57:56 -06:00
parent 62ca063fca
commit 4710f37ef6
8 changed files with 934 additions and 102 deletions

View File

@@ -2513,6 +2513,15 @@ static int hangup(void *data)
if (session) {
int cause = h_data->cause;
if (channel->session->active_media_state &&
channel->session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO]) {
struct ast_sip_session_media *media =
channel->session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];
if (media->rtp) {
ast_rtp_instance_set_stats_vars(ast, media->rtp);
}
}
/*
* It's possible that session_terminate might cause the session to be destroyed
* immediately so we need to keep a reference to it so we can NULL session->channel
@@ -2993,6 +3002,16 @@ static void chan_pjsip_session_end(struct ast_sip_session *session)
SCOPE_EXIT_RTN("No channel\n");
}
if (session->active_media_state &&
session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO]) {
struct ast_sip_session_media *media =
session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];
if (media->rtp) {
ast_rtp_instance_set_stats_vars(session->channel, media->rtp);
}
}
chan_pjsip_remove_hold(ast_channel_uniqueid(session->channel));
ast_set_hangupsource(session->channel, ast_channel_name(session->channel), 0);

View File

@@ -304,6 +304,12 @@
<enum name="rtt">
<para>Round trip time</para>
</enum>
<enum name="txmes">
<para>Transmitted Media Experience Score</para>
</enum>
<enum name="rxmes">
<para>Received Media Experience Score</para>
</enum>
</enumlist>
</enum>
<enum name="all_jitter">
@@ -387,6 +393,37 @@
</enum>
</enumlist>
</enum>
<enum name="all_mes">
<para>Retrieve a summary of all RTCP Media Experience Score information.</para>
<para>The following data items are returned in a semi-colon
delineated list:</para>
<enumlist>
<enum name="minmes">
<para>Minimum MES based on us analysing received packets.</para>
</enum>
<enum name="maxmes">
<para>Maximum MES based on us analysing received packets.</para>
</enum>
<enum name="avgmes">
<para>Average MES based on us analysing received packets.</para>
</enum>
<enum name="stdevmes">
<para>Standard deviation MES based on us analysing received packets.</para>
</enum>
<enum name="reported_minmes">
<para>Minimum MES based on data we get in Sender and Receiver Reports sent by the remote end</para>
</enum>
<enum name="reported_maxmes">
<para>Maximum MES based on data we get in Sender and Receiver Reports sent by the remote end</para>
</enum>
<enum name="reported_avgmes">
<para>Average MES based on data we get in Sender and Receiver Reports sent by the remote end</para>
</enum>
<enum name="reported_stdevmes">
<para>Standard deviation MES based on data we get in Sender and Receiver Reports sent by the remote end</para>
</enum>
</enumlist>
</enum>
<enum name="txcount"><para>Transmitted packet count</para></enum>
<enum name="rxcount"><para>Received packet count</para></enum>
<enum name="txjitter"><para>Transmitted packet jitter</para></enum>
@@ -416,6 +453,24 @@
<enum name="stdevrtt"><para>Standard deviation round trip time</para></enum>
<enum name="local_ssrc"><para>Our Synchronization Source identifier</para></enum>
<enum name="remote_ssrc"><para>Their Synchronization Source identifier</para></enum>
<enum name="txmes"><para>
Current MES based on us analyzing rtt, jitter and loss
in the actual received RTP stream received from the remote end.
I.E. This is the MES for the incoming audio stream.
</para></enum>
<enum name="rxmes"><para>
Current MES based on rtt and the jitter and loss values in
RTCP sender and receiver reports we receive from the
remote end. I.E. This is the MES for the outgoing audio stream.
</para></enum>
<enum name="remote_maxmes"><para>Max MES based on data we get in Sender and Receiver Reports sent by the remote end</para></enum>
<enum name="remote_minmes"><para>Min MES based on data we get in Sender and Receiver Reports sent by the remote end</para></enum>
<enum name="remote_normdevmes"><para>Average MES based on data we get in Sender and Receiver Reports sent by the remote end</para></enum>
<enum name="remote_stdevmes"><para>Standard deviation MES based on data we get in Sender and Receiver Reports sent by the remote end</para></enum>
<enum name="local_maxmes"><para>Max MES based on us analyzing the received RTP stream</para></enum>
<enum name="local_minmes"><para>Min MES based on us analyzing the received RTP stream</para></enum>
<enum name="local_normdevmes"><para>Average MES based on us analyzing the received RTP stream</para></enum>
<enum name="local_stdevmes"><para>Standard deviation MES based on us analyzing the received RTP stream</para></enum>
</enumlist>
</parameter>
<parameter name="media_type" required="false">
@@ -678,6 +733,8 @@ static int channel_read_rtcp(struct ast_channel *chan, const char *type, const c
stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT;
} else if (!strcasecmp(type, "all_loss")) {
stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS;
} else if (!strcasecmp(type, "all_mes")) {
stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY_MES;
}
if (!ast_rtp_instance_get_quality(media->rtp, stat_field, buf, buflen)) {
@@ -724,6 +781,16 @@ static int channel_read_rtcp(struct ast_channel *chan, const char *type, const c
{ "stdevrtt", DBL, { .d8 = &stats.stdevrtt, }, },
{ "local_ssrc", INT, { .i4 = &stats.local_ssrc, }, },
{ "remote_ssrc", INT, { .i4 = &stats.remote_ssrc, }, },
{ "txmes", DBL, { .d8 = &stats.txmes, }, },
{ "rxmes", DBL, { .d8 = &stats.rxmes, }, },
{ "remote_maxmes", DBL, { .d8 = &stats.remote_maxmes, }, },
{ "remote_minmes", DBL, { .d8 = &stats.remote_minmes, }, },
{ "remote_normdevmes", DBL, { .d8 = &stats.remote_normdevmes, }, },
{ "remote_stdevmes", DBL, { .d8 = &stats.remote_stdevmes, }, },
{ "local_maxmes", DBL, { .d8 = &stats.local_maxmes, }, },
{ "local_minmes", DBL, { .d8 = &stats.local_minmes, }, },
{ "local_normdevmes", DBL, { .d8 = &stats.local_normdevmes, }, },
{ "local_stdevmes", DBL, { .d8 = &stats.local_stdevmes, }, },
{ NULL, },
};