Revert "res_rtp_asterisk: Asterisk Media Experience Score (MES)"
This reverts commit 62745013a4
.
Reason for revert: Issue when transcoding to/from g722
Change-Id: I1665a5442bfb6d7bfa06fdcea3374f4581395b4a
This commit is contained in:
parent
bde2689e1b
commit
8067229418
|
@ -2513,15 +2513,6 @@ 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
|
||||
|
@ -3002,16 +2993,6 @@ 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);
|
||||
|
|
|
@ -304,12 +304,6 @@
|
|||
<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">
|
||||
|
@ -393,37 +387,6 @@
|
|||
</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>
|
||||
|
@ -453,24 +416,6 @@
|
|||
<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">
|
||||
|
@ -733,8 +678,6 @@ 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)) {
|
||||
|
@ -781,16 +724,6 @@ 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, },
|
||||
};
|
||||
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
Subject: res_rtp_asterisk
|
||||
|
||||
This module has been updated to provide additional
|
||||
quality statistics in the form of an Asterisk
|
||||
Media Experience Score. The score is available 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
|
|
@ -174,8 +174,6 @@ enum ast_rtp_instance_stat_field {
|
|||
AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS,
|
||||
/*! Retrieve quality information about round trip time */
|
||||
AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT,
|
||||
/*! Retrieve quality information about Media Experience Score */
|
||||
AST_RTP_INSTANCE_STAT_FIELD_QUALITY_MES,
|
||||
};
|
||||
|
||||
/*! Statistics that can be retrieved from an RTP instance */
|
||||
|
@ -252,29 +250,6 @@ enum ast_rtp_instance_stat {
|
|||
AST_RTP_INSTANCE_STAT_TXOCTETCOUNT,
|
||||
/*! Retrieve number of octets received */
|
||||
AST_RTP_INSTANCE_STAT_RXOCTETCOUNT,
|
||||
|
||||
/*! Retrieve ALL statistics relating to Media Experience Score */
|
||||
AST_RTP_INSTANCE_STAT_COMBINED_MES,
|
||||
/*! Retrieve MES on transmitted packets */
|
||||
AST_RTP_INSTANCE_STAT_TXMES,
|
||||
/*! Retrieve MES on received packets */
|
||||
AST_RTP_INSTANCE_STAT_RXMES,
|
||||
/*! Retrieve maximum MES on remote side */
|
||||
AST_RTP_INSTANCE_STAT_REMOTE_MAXMES,
|
||||
/*! Retrieve minimum MES on remote side */
|
||||
AST_RTP_INSTANCE_STAT_REMOTE_MINMES,
|
||||
/*! Retrieve average MES on remote side */
|
||||
AST_RTP_INSTANCE_STAT_REMOTE_NORMDEVMES,
|
||||
/*! Retrieve standard deviation MES on remote side */
|
||||
AST_RTP_INSTANCE_STAT_REMOTE_STDEVMES,
|
||||
/*! Retrieve maximum MES on local side */
|
||||
AST_RTP_INSTANCE_STAT_LOCAL_MAXMES,
|
||||
/*! Retrieve minimum MES on local side */
|
||||
AST_RTP_INSTANCE_STAT_LOCAL_MINMES,
|
||||
/*! Retrieve average MES on local side */
|
||||
AST_RTP_INSTANCE_STAT_LOCAL_NORMDEVMES,
|
||||
/*! Retrieve standard deviation MES on local side */
|
||||
AST_RTP_INSTANCE_STAT_LOCAL_STDEVMES,
|
||||
};
|
||||
|
||||
enum ast_rtp_instance_rtcp {
|
||||
|
@ -453,27 +428,6 @@ struct ast_rtp_instance_stats {
|
|||
unsigned int txoctetcount;
|
||||
/*! Number of octets received */
|
||||
unsigned int rxoctetcount;
|
||||
|
||||
/*! Media Experience Score on transmitted packets */
|
||||
double txmes;
|
||||
/*! Media Experience Score on received packets */
|
||||
double rxmes;
|
||||
/*! Maximum MES on remote side */
|
||||
double remote_maxmes;
|
||||
/*! Minimum MES on remote side */
|
||||
double remote_minmes;
|
||||
/*! Average MES on remote side */
|
||||
double remote_normdevmes;
|
||||
/*! Standard deviation MES on remote side */
|
||||
double remote_stdevmes;
|
||||
/*! Maximum MES on local side */
|
||||
double local_maxmes;
|
||||
/*! Minimum MES on local side */
|
||||
double local_minmes;
|
||||
/*! Average MES on local side */
|
||||
double local_normdevmes;
|
||||
/*! Standard deviation MES on local side */
|
||||
double local_stdevmes;
|
||||
};
|
||||
|
||||
#define AST_RTP_STAT_SET(current_stat, combined, placement, value) \
|
||||
|
@ -2906,10 +2860,6 @@ uintmax_t ast_debug_category_ice_id(void);
|
|||
#define ast_debug_rtp(sublevel, ...) \
|
||||
ast_debug_category(sublevel, AST_DEBUG_CATEGORY_RTP, __VA_ARGS__)
|
||||
|
||||
/* Allow logging of RTP? */
|
||||
#define ast_debug_rtp_is_allowed \
|
||||
ast_debug_category_is_allowed(AST_LOG_CATEGORY_ENABLED, AST_DEBUG_CATEGORY_RTP)
|
||||
|
||||
/* Allow logging of RTP packets? */
|
||||
#define ast_debug_rtp_packet_is_allowed \
|
||||
ast_debug_category_is_allowed(AST_LOG_CATEGORY_ENABLED, AST_DEBUG_CATEGORY_RTP_PACKET)
|
||||
|
@ -2923,10 +2873,6 @@ uintmax_t ast_debug_category_ice_id(void);
|
|||
#define ast_debug_rtcp(sublevel, ...) \
|
||||
ast_debug_category(sublevel, AST_DEBUG_CATEGORY_RTCP, __VA_ARGS__)
|
||||
|
||||
/* Allow logging of RTCP? */
|
||||
#define ast_debug_rtcp_is_allowed \
|
||||
ast_debug_category_is_allowed(AST_LOG_CATEGORY_ENABLED, AST_DEBUG_CATEGORY_RTCP)
|
||||
|
||||
/* Allow logging of RTCP packets? */
|
||||
#define ast_debug_rtcp_packet_is_allowed \
|
||||
ast_debug_category_is_allowed(AST_LOG_CATEGORY_ENABLED, AST_DEBUG_CATEGORY_RTCP_PACKET)
|
||||
|
|
|
@ -33,8 +33,6 @@
|
|||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "asterisk/inline_api.h"
|
||||
|
||||
/* A time_t can be represented as an unsigned long long (or uint64_t).
|
||||
|
@ -234,41 +232,6 @@ struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec),
|
|||
}
|
||||
)
|
||||
|
||||
/*!
|
||||
* \brief Returns a timeval structure corresponding to the
|
||||
* number of seconds in the double _td.
|
||||
*
|
||||
* \param _td The number of seconds.
|
||||
* \returns A timeval structure containing the number of seconds.
|
||||
*
|
||||
* This is the inverse of ast_tv2double().
|
||||
*/
|
||||
AST_INLINE_API(
|
||||
struct timeval ast_double2tv(double _td),
|
||||
{
|
||||
struct timeval t;
|
||||
t.tv_sec = (typeof(t.tv_sec))floor(_td);
|
||||
t.tv_usec = (typeof(t.tv_usec))(_td - t.tv_sec) / 1000000.0;
|
||||
return t;
|
||||
}
|
||||
)
|
||||
|
||||
/*!
|
||||
* \brief Returns a double corresponding to the number of seconds
|
||||
* in the timeval _tv.
|
||||
*
|
||||
* \param _tv A pointer to a timeval structure.
|
||||
* \returns A double containing the number of seconds.
|
||||
*
|
||||
* This is the inverse of ast_double2tv().
|
||||
*/
|
||||
AST_INLINE_API(
|
||||
double ast_tv2double(const struct timeval *tv),
|
||||
{
|
||||
return tv->tv_sec + ((double)tv->tv_usec) / 1000000.0;
|
||||
}
|
||||
)
|
||||
|
||||
/*!
|
||||
* \brief Returns a timeval corresponding to the duration of n samples at rate r.
|
||||
* Useful to convert samples to timevals, or even milliseconds to timevals
|
||||
|
@ -281,57 +244,6 @@ struct timeval ast_samp2tv(unsigned int _nsamp, unsigned int _rate),
|
|||
}
|
||||
)
|
||||
|
||||
/*!
|
||||
* \brief Returns the number of samples at rate _rate in the
|
||||
* duration specified by _tv.
|
||||
*
|
||||
* \param _tv A pointer to a timeval structure.
|
||||
* \param _rate The sample rate in Hz.
|
||||
* \returns A time_t containing the number of samples.
|
||||
*
|
||||
* This is the inverse of ast_samp2tv().
|
||||
*/
|
||||
AST_INLINE_API(
|
||||
time_t ast_tv2samp(const struct timeval *_tv, int _rate),
|
||||
{
|
||||
return (time_t)(ast_tv2double(_tv) * (double)_rate);
|
||||
}
|
||||
)
|
||||
|
||||
/*!
|
||||
* \brief Returns the duration in seconds of _nsamp samples
|
||||
* at rate _rate.
|
||||
*
|
||||
* \param _nsamp The number of samples
|
||||
* \param _rate The sample rate in Hz.
|
||||
* \returns A double containing the number of seconds.
|
||||
*
|
||||
* This is the inverse of ast_sec2samp().
|
||||
*/
|
||||
AST_INLINE_API(
|
||||
double ast_samp2sec(int _nsamp, unsigned int _rate),
|
||||
{
|
||||
return ((double)_nsamp) / ((double)_rate);
|
||||
}
|
||||
)
|
||||
|
||||
/*!
|
||||
* \brief Returns the number of samples at _rate in the duration
|
||||
* in _seconds.
|
||||
*
|
||||
* \param _seconds The time interval in seconds.
|
||||
* \param _rate The sample rate in Hz.
|
||||
* \returns The number of samples.
|
||||
*
|
||||
* This is the inverse of ast_samp2sec().
|
||||
*/
|
||||
AST_INLINE_API(
|
||||
unsigned int ast_sec2samp(double _seconds, int _rate),
|
||||
{
|
||||
return (unsigned int)(_seconds * _rate);
|
||||
}
|
||||
)
|
||||
|
||||
/*!
|
||||
* \brief Time units enumeration.
|
||||
*/
|
||||
|
|
|
@ -143,6 +143,7 @@
|
|||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include <math.h> /* for sqrt, MAX */
|
||||
#include <sched.h> /* for sched_yield */
|
||||
#include <sys/time.h> /* for timeval */
|
||||
#include <time.h> /* for time_t */
|
||||
|
@ -456,28 +457,6 @@ static void instance_destructor(void *obj)
|
|||
|
||||
int ast_rtp_instance_destroy(struct ast_rtp_instance *instance)
|
||||
{
|
||||
if (!instance) {
|
||||
return 0;
|
||||
}
|
||||
if (ast_debug_rtp_is_allowed) {
|
||||
char buffer[4][512];
|
||||
ast_debug_rtp(1, "%s:\n"
|
||||
" RTT: %s\n"
|
||||
" Loss: %s\n"
|
||||
" Jitter: %s\n"
|
||||
" MES: %s\n",
|
||||
instance->channel_uniqueid,
|
||||
ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT,
|
||||
buffer[0], sizeof(buffer[0])),
|
||||
ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS,
|
||||
buffer[1], sizeof(buffer[1])),
|
||||
ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER,
|
||||
buffer[2], sizeof(buffer[2])),
|
||||
ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_MES,
|
||||
buffer[3], sizeof(buffer[3]))
|
||||
);
|
||||
}
|
||||
|
||||
ao2_cleanup(instance);
|
||||
|
||||
return 0;
|
||||
|
@ -2484,8 +2463,6 @@ char *ast_rtp_instance_get_quality(struct ast_rtp_instance *instance, enum ast_r
|
|||
stat = AST_RTP_INSTANCE_STAT_COMBINED_LOSS;
|
||||
} else if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT) {
|
||||
stat = AST_RTP_INSTANCE_STAT_COMBINED_RTT;
|
||||
} else if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_MES) {
|
||||
stat = AST_RTP_INSTANCE_STAT_COMBINED_MES;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -2497,25 +2474,16 @@ char *ast_rtp_instance_get_quality(struct ast_rtp_instance *instance, enum ast_r
|
|||
|
||||
/* Now actually fill the buffer with the good information */
|
||||
if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY) {
|
||||
snprintf(buf, size, "ssrc=%u;themssrc=%u;lp=%u;rxjitter=%f;rxcount=%u;"
|
||||
"txjitter=%f;txcount=%u;rlp=%u;rtt=%f;rxmes=%f;txmes=%f",
|
||||
stats.local_ssrc, stats.remote_ssrc, stats.rxploss, stats.rxjitter,
|
||||
stats.rxcount, stats.txjitter, stats.txcount, stats.txploss, stats.rtt,
|
||||
stats.rxmes, stats.txmes);
|
||||
snprintf(buf, size, "ssrc=%u;themssrc=%u;lp=%u;rxjitter=%f;rxcount=%u;txjitter=%f;txcount=%u;rlp=%u;rtt=%f",
|
||||
stats.local_ssrc, stats.remote_ssrc, stats.rxploss, stats.rxjitter, stats.rxcount, stats.txjitter, stats.txcount, stats.txploss, stats.rtt);
|
||||
} else if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER) {
|
||||
snprintf(buf, size, "minrxjitter=%010.6f;maxrxjitter=%010.6f;avgrxjitter=%010.6f;stdevrxjitter=%010.6f;mintxjitter=%010.6f;maxtxjitter=%010.6f;avgtxjitter=%010.6f;stdevtxjitter=%010.6f;",
|
||||
stats.local_minjitter, stats.local_maxjitter, stats.local_normdevjitter, stats.local_stdevjitter, stats.remote_minjitter, stats.remote_maxjitter, stats.remote_normdevjitter, stats.remote_stdevjitter);
|
||||
snprintf(buf, size, "minrxjitter=%f;maxrxjitter=%f;avgrxjitter=%f;stdevrxjitter=%f;reported_minjitter=%f;reported_maxjitter=%f;reported_avgjitter=%f;reported_stdevjitter=%f;",
|
||||
stats.local_minjitter, stats.local_maxjitter, stats.local_normdevjitter, sqrt(stats.local_stdevjitter), stats.remote_minjitter, stats.remote_maxjitter, stats.remote_normdevjitter, sqrt(stats.remote_stdevjitter));
|
||||
} else if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS) {
|
||||
snprintf(buf, size, " minrxlost=%010.6f; maxrxlost=%010.6f; avgrxlost=%010.6f; stdevrxlost=%010.6f; mintxlost=%010.6f; maxtxlost=%010.6f; avgtxlost=%010.6f; stdevtxlost=%010.6f;",
|
||||
stats.local_minrxploss, stats.local_maxrxploss, stats.local_normdevrxploss, stats.local_stdevrxploss, stats.remote_minrxploss, stats.remote_maxrxploss, stats.remote_normdevrxploss, stats.remote_stdevrxploss);
|
||||
snprintf(buf, size, "minrxlost=%f;maxrxlost=%f;avgrxlost=%f;stdevrxlost=%f;reported_minlost=%f;reported_maxlost=%f;reported_avglost=%f;reported_stdevlost=%f;",
|
||||
stats.local_minrxploss, stats.local_maxrxploss, stats.local_normdevrxploss, sqrt(stats.local_stdevrxploss), stats.remote_minrxploss, stats.remote_maxrxploss, stats.remote_normdevrxploss, sqrt(stats.remote_stdevrxploss));
|
||||
} else if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT) {
|
||||
snprintf(buf, size, " minrtt=%010.6f; maxrtt=%010.6f; avgrtt=%010.6f; stdevrtt=%010.6f;", stats.minrtt, stats.maxrtt, stats.normdevrtt, stats.stdevrtt);
|
||||
} else if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_MES) {
|
||||
snprintf(buf, size, " minrxmes=%010.6f; maxrxmes=%010.6f; avgrxmes=%010.6f; stdevrxmes=%010.6f; mintxmes=%010.6f; maxtxmes=%010.6f; avgtxmes=%010.6f; stdevtxmes=%010.6f;",
|
||||
stats.local_minmes, stats.local_maxmes,
|
||||
stats.local_normdevmes, stats.local_stdevmes,
|
||||
stats.remote_minmes, stats.remote_maxmes,
|
||||
stats.remote_normdevmes, stats.remote_stdevmes);
|
||||
snprintf(buf, size, "minrtt=%f;maxrtt=%f;avgrtt=%f;stdevrtt=%f;", stats.minrtt, stats.maxrtt, stats.normdevrtt, stats.stdevrtt);
|
||||
}
|
||||
|
||||
return buf;
|
||||
|
@ -2572,15 +2540,6 @@ void ast_rtp_instance_set_stats_vars(struct ast_channel *chan, struct ast_rtp_in
|
|||
}
|
||||
}
|
||||
|
||||
quality = ast_rtp_instance_get_quality(instance,
|
||||
AST_RTP_INSTANCE_STAT_FIELD_QUALITY_MES, quality_buf, sizeof(quality_buf));
|
||||
if (quality) {
|
||||
pbx_builtin_setvar_helper(chan, "RTPAUDIOQOSMES", quality);
|
||||
if (bridge) {
|
||||
pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSMESBRIDGED", quality);
|
||||
}
|
||||
}
|
||||
|
||||
ast_channel_stage_snapshot_done(chan);
|
||||
ast_channel_unlock(chan);
|
||||
if (bridge) {
|
||||
|
@ -3353,7 +3312,6 @@ static struct ast_manager_event_blob *rtcp_report_to_ami(struct stasis_message *
|
|||
struct ast_json *to = ast_json_object_get(payload->blob, "to");
|
||||
struct ast_json *from = ast_json_object_get(payload->blob, "from");
|
||||
struct ast_json *rtt = ast_json_object_get(payload->blob, "rtt");
|
||||
struct ast_json *mes = ast_json_object_get(payload->blob, "mes");
|
||||
if (to) {
|
||||
ast_str_append(&packet_string, 0, "To: %s\r\n", ast_json_string_get(to));
|
||||
}
|
||||
|
@ -3363,9 +3321,6 @@ static struct ast_manager_event_blob *rtcp_report_to_ami(struct stasis_message *
|
|||
if (rtt) {
|
||||
ast_str_append(&packet_string, 0, "RTT: %4.4f\r\n", ast_json_real_get(rtt));
|
||||
}
|
||||
if (mes) {
|
||||
ast_str_append(&packet_string, 0, "MES: %4.1f\r\n", ast_json_real_get(mes));
|
||||
}
|
||||
}
|
||||
|
||||
ast_str_append(&packet_string, 0, "SSRC: 0x%.8x\r\n", ssrc);
|
||||
|
@ -4051,19 +4006,6 @@ struct ast_json *ast_rtp_convert_stats_json(const struct ast_rtp_instance_stats
|
|||
SET_AST_JSON_OBJ(j_res, "normdevrtt", ast_json_real_create(stats->normdevrtt));
|
||||
SET_AST_JSON_OBJ(j_res, "stdevrtt", ast_json_real_create(stats->stdevrtt));
|
||||
|
||||
SET_AST_JSON_OBJ(j_res, "txmes", ast_json_integer_create(stats->txmes));
|
||||
SET_AST_JSON_OBJ(j_res, "rxmes", ast_json_integer_create(stats->rxmes));
|
||||
|
||||
SET_AST_JSON_OBJ(j_res, "remote_maxmes", ast_json_real_create(stats->remote_maxmes));
|
||||
SET_AST_JSON_OBJ(j_res, "remote_minmes", ast_json_real_create(stats->remote_minmes));
|
||||
SET_AST_JSON_OBJ(j_res, "remote_normdevmes", ast_json_real_create(stats->remote_normdevmes));
|
||||
SET_AST_JSON_OBJ(j_res, "remote_stdevmes", ast_json_real_create(stats->remote_stdevmes));
|
||||
|
||||
SET_AST_JSON_OBJ(j_res, "local_maxmes", ast_json_real_create(stats->local_maxmes));
|
||||
SET_AST_JSON_OBJ(j_res, "local_minmes", ast_json_real_create(stats->local_minmes));
|
||||
SET_AST_JSON_OBJ(j_res, "local_normdevmes", ast_json_real_create(stats->local_normdevmes));
|
||||
SET_AST_JSON_OBJ(j_res, "local_stdevmes", ast_json_real_create(stats->local_stdevmes));
|
||||
|
||||
return j_res;
|
||||
}
|
||||
|
||||
|
|
|
@ -194,16 +194,6 @@ enum strict_rtp_mode {
|
|||
#define DEFAULT_STUN_SOFTWARE_ATTRIBUTE 1
|
||||
#define DEFAULT_DTLS_MTU 1200
|
||||
|
||||
/*!
|
||||
* Because both ends usually don't start sending RTP
|
||||
* at the same time, some of the calculations like
|
||||
* rtt and jitter will probably be unstable for a while
|
||||
* so we'll skip some received packets before starting
|
||||
* analyzing. This just affects analyzing; we still
|
||||
* process the RTP as normal.
|
||||
*/
|
||||
#define RTP_IGNORE_FIRST_PACKETS_COUNT 15
|
||||
|
||||
extern struct ast_srtp_res *res_srtp;
|
||||
extern struct ast_srtp_policy_res *res_srtp_policy;
|
||||
|
||||
|
@ -401,32 +391,22 @@ struct ast_rtp {
|
|||
unsigned int lastovidtimestamp;
|
||||
unsigned int lastitexttimestamp;
|
||||
unsigned int lastotexttimestamp;
|
||||
int prevrxseqno; /*!< Previous received packeted sequence number, from the network */
|
||||
int lastrxseqno; /*!< Last received sequence number, from the network */
|
||||
int expectedrxseqno; /*!< Next expected sequence number, from the network */
|
||||
int expectedrxseqno; /*!< Next expected sequence number, from the network */
|
||||
AST_VECTOR(, int) missing_seqno; /*!< A vector of sequence numbers we never received */
|
||||
int expectedseqno; /*!< Next expected sequence number, from the core */
|
||||
unsigned short seedrxseqno; /*!< What sequence number did they start with?*/
|
||||
unsigned int seedrxts; /*!< What RTP timestamp did they start with? */
|
||||
unsigned int rxcount; /*!< How many packets have we received? */
|
||||
unsigned int rxoctetcount; /*!< How many octets have we received? should be rxcount *160*/
|
||||
unsigned int txcount; /*!< How many packets have we sent? */
|
||||
unsigned int txoctetcount; /*!< How many octets have we sent? (txcount*160)*/
|
||||
unsigned int cycles; /*!< Shifted count of sequence number cycles */
|
||||
double rxjitter; /*!< Interarrival jitter at the moment in seconds to be reported */
|
||||
double rxtransit; /*!< Relative transit time for previous packet */
|
||||
struct ast_format *lasttxformat;
|
||||
struct ast_format *lastrxformat;
|
||||
|
||||
/*
|
||||
* RX RTP Timestamp and Jitter calculation.
|
||||
*/
|
||||
double rxstart; /*!< RX time of the first packet in the session in seconds since EPOCH. */
|
||||
double rxstart_stable; /*!< RX time of the first packet after RTP_IGNORE_FIRST_PACKETS_COUNT */
|
||||
unsigned int remote_seed_rx_rtp_ts; /*!< RTP timestamp of first RX packet. */
|
||||
unsigned int remote_seed_rx_rtp_ts_stable; /*!< RTP timestamp of first packet after RTP_IGNORE_FIRST_PACKETS_COUNT */
|
||||
unsigned int last_transit_time_samples; /*!< The last transit time in samples */
|
||||
double rxjitter; /*!< Last calculated Interarrival jitter in seconds. */
|
||||
double rxjitter_samples; /*!< Last calculated Interarrival jitter in samples. */
|
||||
double rxmes; /*!< Media Experince Score at the moment to be reported */
|
||||
|
||||
/* DTMF Reception Variables */
|
||||
char resp; /*!< The current digit being processed */
|
||||
unsigned int last_seqno; /*!< The last known sequence number for any DTMF packet */
|
||||
|
@ -442,8 +422,9 @@ struct ast_rtp {
|
|||
int send_payload;
|
||||
int send_duration;
|
||||
unsigned int flags;
|
||||
struct timeval rxcore;
|
||||
struct timeval txcore;
|
||||
|
||||
double drxcore; /*!< The double representation of the first received packet */
|
||||
struct timeval dtmfmute;
|
||||
struct ast_smoother *smoother;
|
||||
unsigned short seqno; /*!< Sequence number, RFC 3550, page 13. */
|
||||
|
@ -452,12 +433,6 @@ struct ast_rtp {
|
|||
unsigned int asymmetric_codec; /*!< Indicate if asymmetric send/receive codecs are allowed */
|
||||
|
||||
struct ast_rtp_instance *bundled; /*!< The RTP instance we are bundled to */
|
||||
/*!
|
||||
* \brief The RTP instance owning us (used for debugging purposes)
|
||||
* We don't hold a reference to the instance because it created
|
||||
* us in the first place. It can't go away.
|
||||
*/
|
||||
struct ast_rtp_instance *owner;
|
||||
int stream_num; /*!< Stream num for this RTP instance */
|
||||
AST_VECTOR(, struct rtp_ssrc_mapping) ssrc_mapping; /*!< Mappings of SSRC to RTP instances */
|
||||
struct ast_sockaddr bind_address; /*!< Requested bind address for the sockets */
|
||||
|
@ -551,7 +526,7 @@ struct ast_rtcp {
|
|||
unsigned int lastsrtxcount; /*!< Transmit packet count when last SR sent */
|
||||
double accumulated_transit; /*!< accumulated a-dlsr-lsr */
|
||||
double rtt; /*!< Last reported rtt */
|
||||
double reported_jitter; /*!< The contents of their last jitter entry in the RR in seconds */
|
||||
unsigned int reported_jitter; /*!< The contents of their last jitter entry in the RR */
|
||||
unsigned int reported_lost; /*!< Reported lost packets in their RR */
|
||||
|
||||
double reported_maxjitter; /*!< Maximum reported interarrival jitter */
|
||||
|
@ -585,19 +560,6 @@ struct ast_rtcp {
|
|||
double stdevrtt; /*!< Standard deviation of calculated round trip time */
|
||||
unsigned int rtt_count; /*!< Calculated round trip time count */
|
||||
|
||||
double reported_mes; /*!< The calculated MES from their last RR */
|
||||
double reported_maxmes; /*!< Maximum reported mes */
|
||||
double reported_minmes; /*!< Minimum reported mes */
|
||||
double reported_normdev_mes; /*!< Mean of reported mes */
|
||||
double reported_stdev_mes; /*!< Standard deviation of reported mes */
|
||||
unsigned int reported_mes_count; /*!< Reported mes count */
|
||||
|
||||
double maxrxmes; /*!< Maximum of calculated mes */
|
||||
double minrxmes; /*!< Minimum of calculated mes */
|
||||
double normdev_rxmes; /*!< Mean of calculated mes */
|
||||
double stdev_rxmes; /*!< Standard deviation of calculated mes */
|
||||
unsigned int rxmes_count; /*!< mes count */
|
||||
|
||||
/* VP8: sequence number for the RTCP FIR FCI */
|
||||
int firseq;
|
||||
|
||||
|
@ -668,8 +630,6 @@ static void ast_rtp_set_remote_ssrc(struct ast_rtp_instance *instance, unsigned
|
|||
static void ast_rtp_set_stream_num(struct ast_rtp_instance *instance, int stream_num);
|
||||
static int ast_rtp_extension_enable(struct ast_rtp_instance *instance, enum ast_rtp_extension extension);
|
||||
static int ast_rtp_bundle(struct ast_rtp_instance *child, struct ast_rtp_instance *parent);
|
||||
static void update_reported_mes_stats(struct ast_rtp *rtp);
|
||||
static void update_local_mes_stats(struct ast_rtp *rtp);
|
||||
|
||||
#if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP)
|
||||
static int ast_rtp_activate(struct ast_rtp_instance *instance);
|
||||
|
@ -4064,16 +4024,16 @@ static int ast_rtp_new(struct ast_rtp_instance *instance,
|
|||
if (!(rtp = ast_calloc(1, sizeof(*rtp)))) {
|
||||
return -1;
|
||||
}
|
||||
rtp->owner = instance;
|
||||
|
||||
/* Set default parameters on the newly created RTP structure */
|
||||
rtp->ssrc = ast_random();
|
||||
ast_uuid_generate_str(rtp->cname, sizeof(rtp->cname));
|
||||
rtp->seqno = ast_random() & 0x7fff;
|
||||
rtp->expectedrxseqno = -1;
|
||||
rtp->expectedseqno = -1;
|
||||
rtp->rxstart = -1;
|
||||
rtp->sched = sched;
|
||||
ast_sockaddr_copy(&rtp->bind_address, addr);
|
||||
|
||||
/* Transport creation operations can grab the RTP data from the instance, so set it */
|
||||
ast_rtp_instance_set_data(instance, rtp);
|
||||
|
||||
|
@ -4175,7 +4135,6 @@ static int ast_rtp_destroy(struct ast_rtp_instance *instance)
|
|||
AST_VECTOR_FREE(&rtp->missing_seqno);
|
||||
|
||||
/* Finally destroy ourselves */
|
||||
rtp->owner = NULL;
|
||||
ast_free(rtp);
|
||||
|
||||
return 0;
|
||||
|
@ -4587,11 +4546,6 @@ static int ast_rtcp_generate_report(struct ast_rtp_instance *instance, unsigned
|
|||
|
||||
/* Compute statistics */
|
||||
calculate_lost_packet_statistics(rtp, &lost_packets, &fraction_lost);
|
||||
/*
|
||||
* update_local_mes_stats must be called AFTER
|
||||
* calculate_lost_packet_statistics
|
||||
*/
|
||||
update_local_mes_stats(rtp);
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
rtcp_report->reception_report_count = rtp->themssrc_valid ? 1 : 0;
|
||||
|
@ -4615,7 +4569,7 @@ static int ast_rtcp_generate_report(struct ast_rtp_instance *instance, unsigned
|
|||
report_block->lost_count.fraction = (fraction_lost & 0xff);
|
||||
report_block->lost_count.packets = (lost_packets & 0xffffff);
|
||||
report_block->highest_seq_no = (rtp->cycles | (rtp->lastrxseqno & 0xffff));
|
||||
report_block->ia_jitter = (unsigned int)rtp->rxjitter_samples;
|
||||
report_block->ia_jitter = (unsigned int)(rtp->rxjitter * ast_rtp_get_rate(rtp->f.subclass.format));
|
||||
report_block->lsr = rtp->rtcp->themrxlsr;
|
||||
/* If we haven't received an SR report, DLSR should be 0 */
|
||||
if (!ast_tvzero(rtp->rtcp->rxlsr)) {
|
||||
|
@ -4692,24 +4646,20 @@ static int ast_rtcp_calculate_sr_rr_statistics(struct ast_rtp_instance *instance
|
|||
ast_verbose(" Sent octets: %u\n", rtcp_report->sender_information.octet_count);
|
||||
}
|
||||
if (report_block) {
|
||||
int rate = ast_rtp_get_rate(rtp->f.subclass.format);
|
||||
ast_verbose(" Report block:\n");
|
||||
ast_verbose(" Their SSRC: %u\n", report_block->source_ssrc);
|
||||
ast_verbose(" Fraction lost: %d\n", report_block->lost_count.fraction);
|
||||
ast_verbose(" Cumulative loss: %u\n", report_block->lost_count.packets);
|
||||
ast_verbose(" Highest seq no: %u\n", report_block->highest_seq_no);
|
||||
ast_verbose(" IA jitter (samp): %u\n", report_block->ia_jitter);
|
||||
ast_verbose(" IA jitter (secs): %.6f\n", ast_samp2sec(report_block->ia_jitter, rate));
|
||||
ast_verbose(" IA jitter: %.4f\n", (double)report_block->ia_jitter / ast_rtp_get_rate(rtp->f.subclass.format));
|
||||
ast_verbose(" Their last SR: %u\n", report_block->lsr);
|
||||
ast_verbose(" DLSR: %4.4f (sec)\n\n", (double)(report_block->dlsr / 65536.0));
|
||||
}
|
||||
}
|
||||
|
||||
message_blob = ast_json_pack("{s: s, s: s, s: f}",
|
||||
message_blob = ast_json_pack("{s: s, s: s}",
|
||||
"to", ast_sockaddr_stringify(&remote_address),
|
||||
"from", rtp->rtcp->local_addr_str,
|
||||
"mes", rtp->rxmes);
|
||||
|
||||
"from", rtp->rtcp->local_addr_str);
|
||||
ast_rtp_publish_rtcp_message(instance, ast_rtp_rtcp_sent_type(),
|
||||
rtcp_report, message_blob);
|
||||
|
||||
|
@ -5166,8 +5116,7 @@ static int rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame *fr
|
|||
}
|
||||
} else {
|
||||
if (rtp->rtcp && rtp->rtcp->schedid < 0) {
|
||||
ast_debug_rtcp(2, "(%s) RTCP starting transmission in %u ms\n",
|
||||
ast_rtp_instance_get_channel_id(instance), ast_rtcp_calc_interval(rtp));
|
||||
ast_debug_rtcp(1, "(%p) RTCP starting transmission\n", instance);
|
||||
ao2_ref(instance, +1);
|
||||
rtp->rtcp->schedid = ast_sched_add(rtp->sched, ast_rtcp_calc_interval(rtp), ast_rtcp_write, instance);
|
||||
if (rtp->rtcp->schedid < 0) {
|
||||
|
@ -5425,9 +5374,8 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr
|
|||
format = frame->subclass.format;
|
||||
if (ast_format_cmp(rtp->lasttxformat, format) == AST_FORMAT_CMP_NOT_EQUAL) {
|
||||
/* Oh dear, if the format changed we will have to set up a new smoother */
|
||||
ast_debug_rtp(1, "(%s) RTP ooh, format changed from %s to %s\n",
|
||||
ast_rtp_instance_get_channel_id(instance),
|
||||
ast_format_get_name(rtp->lasttxformat),
|
||||
ast_debug_rtp(1, "(%p) RTP ooh, format changed from %s to %s\n",
|
||||
instance, ast_format_get_name(rtp->lasttxformat),
|
||||
ast_format_get_name(frame->subclass.format));
|
||||
ao2_replace(rtp->lasttxformat, format);
|
||||
if (rtp->smoother) {
|
||||
|
@ -5490,164 +5438,43 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void calc_rxstamp_and_jitter(struct timeval *tv,
|
||||
struct ast_rtp *rtp, unsigned int rx_rtp_ts,
|
||||
int mark)
|
||||
static void calc_rxstamp(struct timeval *tv, struct ast_rtp *rtp, unsigned int timestamp, int mark)
|
||||
{
|
||||
struct timeval now;
|
||||
struct timeval tmp;
|
||||
double transit;
|
||||
double current_time;
|
||||
double d;
|
||||
double dtv;
|
||||
double prog;
|
||||
int rate = ast_rtp_get_rate(rtp->f.subclass.format);
|
||||
|
||||
double estimated_elapsed;
|
||||
double jitter = 0.0;
|
||||
double prev_jitter = 0.0;
|
||||
struct timeval now;
|
||||
double rxnow;
|
||||
double arrival_sec;
|
||||
unsigned int arrival;
|
||||
int transit;
|
||||
int d;
|
||||
if ((!rtp->rxcore.tv_sec && !rtp->rxcore.tv_usec) || mark) {
|
||||
gettimeofday(&rtp->rxcore, NULL);
|
||||
rtp->drxcore = (double) rtp->rxcore.tv_sec + (double) rtp->rxcore.tv_usec / 1000000;
|
||||
/* map timestamp to a real time */
|
||||
rtp->seedrxts = timestamp; /* Their RTP timestamp started with this */
|
||||
tmp = ast_samp2tv(timestamp, rate);
|
||||
rtp->rxcore = ast_tvsub(rtp->rxcore, tmp);
|
||||
/* Round to 0.1ms for nice, pretty timestamps */
|
||||
rtp->rxcore.tv_usec -= rtp->rxcore.tv_usec % 100;
|
||||
}
|
||||
|
||||
gettimeofday(&now,NULL);
|
||||
/* rxcore is the mapping between the RTP timestamp and _our_ real time from gettimeofday() */
|
||||
tmp = ast_samp2tv(timestamp, rate);
|
||||
*tv = ast_tvadd(rtp->rxcore, tmp);
|
||||
|
||||
if (rtp->rxcount == 1 || mark) {
|
||||
rtp->rxstart = ast_tv2double(&now);
|
||||
rtp->remote_seed_rx_rtp_ts = rx_rtp_ts;
|
||||
|
||||
*tv = ast_double2tv(rtp->rxstart);
|
||||
|
||||
ast_debug_rtcp(3, "%s: "
|
||||
"Seed ts: %u current time: %f\n",
|
||||
ast_rtp_instance_get_channel_id(rtp->owner)
|
||||
, rx_rtp_ts
|
||||
, rtp->rxstart
|
||||
);
|
||||
|
||||
return;
|
||||
prog = (double)((timestamp-rtp->seedrxts)/(float)(rate));
|
||||
dtv = (double)rtp->drxcore + (double)(prog);
|
||||
current_time = (double)now.tv_sec + (double)now.tv_usec/1000000;
|
||||
transit = current_time - dtv;
|
||||
d = transit - rtp->rxtransit;
|
||||
rtp->rxtransit = transit;
|
||||
if (d<0) {
|
||||
d=-d;
|
||||
}
|
||||
|
||||
estimated_elapsed = ast_samp2sec(rx_rtp_ts - rtp->remote_seed_rx_rtp_ts, rate);
|
||||
*tv = ast_double2tv(rtp->rxstart + estimated_elapsed);
|
||||
|
||||
/*
|
||||
* The first few packets are generally unstable so let's
|
||||
* not use them in the calculations.
|
||||
*/
|
||||
if (rtp->rxcount < RTP_IGNORE_FIRST_PACKETS_COUNT) {
|
||||
ast_debug_rtcp(3, "%s: Packet %d < %d. Ignoring\n",
|
||||
ast_rtp_instance_get_channel_id(rtp->owner)
|
||||
, rtp->rxcount
|
||||
, RTP_IGNORE_FIRST_PACKETS_COUNT
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* First good packet. Capture the start time and timestamp
|
||||
* but don't actually use this packet for calculation.
|
||||
*/
|
||||
if (rtp->rxcount == RTP_IGNORE_FIRST_PACKETS_COUNT) {
|
||||
rtp->rxstart_stable = ast_tv2double(&now);
|
||||
rtp->remote_seed_rx_rtp_ts_stable = rx_rtp_ts;
|
||||
rtp->last_transit_time_samples = -rx_rtp_ts;
|
||||
|
||||
ast_debug_rtcp(3, "%s: "
|
||||
"pkt: %5u Stable Seed ts: %u current time: %f\n",
|
||||
ast_rtp_instance_get_channel_id(rtp->owner)
|
||||
, rtp->rxcount
|
||||
, rx_rtp_ts
|
||||
, rtp->rxstart_stable
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the current packet isn't in sequence, don't
|
||||
* use it in any calculations as remote_current_rx_rtp_ts
|
||||
* is not going to be correct.
|
||||
*/
|
||||
if (rtp->lastrxseqno != rtp->prevrxseqno + 1) {
|
||||
ast_debug_rtcp(3, "%s: Current packet seq %d != last packet seq %d + 1. Ignoring\n",
|
||||
ast_rtp_instance_get_channel_id(rtp->owner)
|
||||
, rtp->lastrxseqno
|
||||
, rtp->prevrxseqno
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The following calculations are taken from
|
||||
* https://www.rfc-editor.org/rfc/rfc3550#appendix-A.8
|
||||
*
|
||||
* The received rtp timestamp is the random "seed"
|
||||
* timestamp chosen by the sender when they sent the
|
||||
* first packet, plus the number of samples since then.
|
||||
*
|
||||
* To get our arrival time in the same units, we
|
||||
* calculate the time difference in seconds between
|
||||
* when we received the first packet and when we
|
||||
* received this packet and convert that to samples.
|
||||
*/
|
||||
rxnow = ast_tv2double(&now);
|
||||
arrival_sec = rxnow - rtp->rxstart_stable;
|
||||
arrival = ast_sec2samp(arrival_sec, rate);
|
||||
|
||||
/*
|
||||
* Now we can use the exact formula in
|
||||
* https://www.rfc-editor.org/rfc/rfc3550#appendix-A.8 :
|
||||
*
|
||||
* int transit = arrival - r->ts;
|
||||
* int d = transit - s->transit;
|
||||
* s->transit = transit;
|
||||
* if (d < 0) d = -d;
|
||||
* s->jitter += (1./16.) * ((double)d - s->jitter);
|
||||
*
|
||||
* Our rx_rtp_ts is their r->ts.
|
||||
* Our rtp->last_transit_time_samples is their s->transit.
|
||||
* Our rtp->rxjitter is their s->jitter.
|
||||
*/
|
||||
transit = arrival - rx_rtp_ts;
|
||||
d = transit - rtp->last_transit_time_samples;
|
||||
|
||||
if (d < 0) {
|
||||
d = -d;
|
||||
}
|
||||
|
||||
prev_jitter = rtp->rxjitter_samples;
|
||||
jitter = (1.0/16.0) * (((double)d) - prev_jitter);
|
||||
rtp->rxjitter_samples = prev_jitter + jitter;
|
||||
|
||||
/*
|
||||
* We need to hang on to jitter in both samples and seconds.
|
||||
*/
|
||||
rtp->rxjitter = ast_samp2sec(rtp->rxjitter_samples, rate);
|
||||
|
||||
ast_debug_rtcp(3, "%s: pkt: %5u "
|
||||
"Arrival sec: %7.3f Arrival ts: %10u RX ts: %10u "
|
||||
"Transit samp: %6d Last transit samp: %6d d: %4d "
|
||||
"Curr jitter: %7.0f(%7.3f) Prev Jitter: %7.0f(%7.3f) New Jitter: %7.0f(%7.3f)\n",
|
||||
ast_rtp_instance_get_channel_id(rtp->owner)
|
||||
, rtp->rxcount
|
||||
, arrival_sec
|
||||
, arrival
|
||||
, rx_rtp_ts
|
||||
, transit
|
||||
, rtp->last_transit_time_samples
|
||||
, d
|
||||
, jitter
|
||||
, ast_samp2sec(jitter, rate)
|
||||
, prev_jitter
|
||||
, ast_samp2sec(prev_jitter, rate)
|
||||
, rtp->rxjitter_samples
|
||||
, rtp->rxjitter
|
||||
);
|
||||
|
||||
rtp->last_transit_time_samples = transit;
|
||||
|
||||
/*
|
||||
* Update all the stats.
|
||||
*/
|
||||
rtp->rxjitter += (1./16.) * (d - rtp->rxjitter);
|
||||
if (rtp->rtcp) {
|
||||
if (rtp->rxjitter > rtp->rtcp->maxrxjitter)
|
||||
rtp->rtcp->maxrxjitter = rtp->rxjitter;
|
||||
|
@ -5656,12 +5483,9 @@ static void calc_rxstamp_and_jitter(struct timeval *tv,
|
|||
if (rtp->rtcp && rtp->rxjitter < rtp->rtcp->minrxjitter)
|
||||
rtp->rtcp->minrxjitter = rtp->rxjitter;
|
||||
|
||||
calc_mean_and_standard_deviation(rtp->rxjitter,
|
||||
&rtp->rtcp->normdev_rxjitter, &rtp->rtcp->stdev_rxjitter,
|
||||
&rtp->rtcp->rxjitter_count);
|
||||
calc_mean_and_standard_deviation(rtp->rxjitter, &rtp->rtcp->normdev_rxjitter,
|
||||
&rtp->rtcp->stdev_rxjitter, &rtp->rtcp->rxjitter_count);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static struct ast_frame *create_dtmf_frame(struct ast_rtp_instance *instance, enum ast_frame_type type, int compensate)
|
||||
|
@ -6027,23 +5851,22 @@ static int update_rtt_stats(struct ast_rtp *rtp, unsigned int lsr, unsigned int
|
|||
*/
|
||||
static void update_jitter_stats(struct ast_rtp *rtp, unsigned int ia_jitter)
|
||||
{
|
||||
int rate = ast_rtp_get_rate(rtp->f.subclass.format);
|
||||
|
||||
rtp->rtcp->reported_jitter = ast_samp2sec(ia_jitter, rate);
|
||||
double reported_jitter;
|
||||
|
||||
rtp->rtcp->reported_jitter = ia_jitter;
|
||||
reported_jitter = (double) rtp->rtcp->reported_jitter;
|
||||
if (rtp->rtcp->reported_jitter_count == 0) {
|
||||
rtp->rtcp->reported_minjitter = rtp->rtcp->reported_jitter;
|
||||
rtp->rtcp->reported_minjitter = reported_jitter;
|
||||
}
|
||||
if (rtp->rtcp->reported_jitter < rtp->rtcp->reported_minjitter) {
|
||||
rtp->rtcp->reported_minjitter = rtp->rtcp->reported_jitter;
|
||||
if (reported_jitter < rtp->rtcp->reported_minjitter) {
|
||||
rtp->rtcp->reported_minjitter = reported_jitter;
|
||||
}
|
||||
if (rtp->rtcp->reported_jitter > rtp->rtcp->reported_maxjitter) {
|
||||
rtp->rtcp->reported_maxjitter = rtp->rtcp->reported_jitter;
|
||||
if (reported_jitter > rtp->rtcp->reported_maxjitter) {
|
||||
rtp->rtcp->reported_maxjitter = reported_jitter;
|
||||
}
|
||||
|
||||
calc_mean_and_standard_deviation(rtp->rtcp->reported_jitter,
|
||||
&rtp->rtcp->reported_normdev_jitter, &rtp->rtcp->reported_stdev_jitter,
|
||||
&rtp->rtcp->reported_jitter_count);
|
||||
calc_mean_and_standard_deviation(reported_jitter, &rtp->rtcp->reported_normdev_jitter,
|
||||
&rtp->rtcp->reported_stdev_jitter, &rtp->rtcp->reported_jitter_count);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -6070,158 +5893,6 @@ static void update_lost_stats(struct ast_rtp *rtp, unsigned int lost_packets)
|
|||
&rtp->rtcp->reported_stdev_lost, &rtp->rtcp->reported_lost_count);
|
||||
}
|
||||
|
||||
#define RESCALE(in, inmin, inmax, outmin, outmax) ((((in - inmin)/(inmax-inmin))*(outmax-outmin))+outmin)
|
||||
/*!
|
||||
* \brief Calculate a "media experience score" based on given data
|
||||
*
|
||||
* Technically, a mean opinion score (MOS) cannot be calculated without the involvement
|
||||
* of human eyes (video) and ears (audio). Thus instead we'll approximate an opinion
|
||||
* using the given parameters, and call it a media experience score.
|
||||
*
|
||||
* The tallied score is based upon recommendations and formulas from ITU-T G.107,
|
||||
* ITU-T G.109, ITU-T G.113, and other various internet sources.
|
||||
*
|
||||
* \param normdevrtt The average round trip time
|
||||
* \param rxjitter The smoothed jitter
|
||||
* \param stdev_rxjitter The jitter standard deviation value
|
||||
* \param normdev_rxlost The average number of packets lost since last check
|
||||
*
|
||||
* \return A media experience score.
|
||||
*
|
||||
* \note The calculations in this function could probably be simplified
|
||||
* but calculating a MOS using the information available publicly,
|
||||
* then re-scaling it to 0.0 -> 100.0 makes the process clearer and
|
||||
* easier to troubleshoot or change.
|
||||
*/
|
||||
static double calc_media_experience_score(struct ast_rtp_instance *instance,
|
||||
double normdevrtt, double normdev_rxjitter, double stdev_rxjitter,
|
||||
double normdev_rxlost)
|
||||
{
|
||||
double r_value;
|
||||
double pseudo_mos;
|
||||
double mes = 0;
|
||||
|
||||
/*
|
||||
* While the media itself might be okay, a significant enough delay could make
|
||||
* for an unpleasant user experience.
|
||||
*
|
||||
* Calculate the effective latency by using the given round trip time, and adding
|
||||
* jitter scaled according to its standard deviation. The scaling is done in order
|
||||
* to increase jitter's weight since a higher deviation can result in poorer overall
|
||||
* quality.
|
||||
*/
|
||||
double effective_latency = (normdevrtt * 1000)
|
||||
+ ((normdev_rxjitter * 2) * (stdev_rxjitter / 3))
|
||||
+ 10;
|
||||
|
||||
/*
|
||||
* Using the defaults for the standard transmission rating factor ("R" value)
|
||||
* one arrives at 93.2 (see ITU-T G.107 for more details), so we'll use that
|
||||
* as the starting value and subtract deficiencies that could affect quality.
|
||||
*
|
||||
* Calculate the impact of the effective latency. Influence increases with
|
||||
* values over 160 as the significant "lag" can degrade user experience.
|
||||
*/
|
||||
if (effective_latency < 160) {
|
||||
r_value = 93.2 - (effective_latency / 40);
|
||||
} else {
|
||||
r_value = 93.2 - (effective_latency - 120) / 10;
|
||||
}
|
||||
|
||||
/* Next evaluate the impact of lost packets */
|
||||
r_value = r_value - (normdev_rxlost * 2.0);
|
||||
|
||||
/*
|
||||
* Finally convert the "R" value into a opinion/quality score between 1 (really anything
|
||||
* below 3 should be considered poor) and 4.5 (the highest achievable for VOIP).
|
||||
*/
|
||||
if (r_value < 0) {
|
||||
pseudo_mos = 1.0;
|
||||
} else if (r_value > 100) {
|
||||
pseudo_mos = 4.5;
|
||||
} else {
|
||||
pseudo_mos = 1 + (0.035 * r_value) + (r_value * (r_value - 60) * (100 - r_value) * 0.0000007);
|
||||
}
|
||||
|
||||
/*
|
||||
* We're going to rescale the 0.0->5.0 pseudo_mos to the 0.0->100.0 MES.
|
||||
* For those ranges, we could actually just multiply the pseudo_mos
|
||||
* by 20 but we may want to change the scale later.
|
||||
*/
|
||||
mes = RESCALE(pseudo_mos, 0.0, 5.0, 0.0, 100.0);
|
||||
|
||||
return mes;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Update MES stats based on info received in an SR or RR.
|
||||
* This is RTP we sent and they received.
|
||||
*/
|
||||
static void update_reported_mes_stats(struct ast_rtp *rtp)
|
||||
{
|
||||
double mes = calc_media_experience_score(rtp->owner,
|
||||
rtp->rtcp->normdevrtt,
|
||||
rtp->rtcp->reported_jitter,
|
||||
rtp->rtcp->reported_stdev_jitter,
|
||||
rtp->rtcp->reported_normdev_lost);
|
||||
|
||||
rtp->rtcp->reported_mes = mes;
|
||||
if (rtp->rtcp->reported_mes_count == 0) {
|
||||
rtp->rtcp->reported_minmes = mes;
|
||||
}
|
||||
if (mes < rtp->rtcp->reported_minmes) {
|
||||
rtp->rtcp->reported_minmes = mes;
|
||||
}
|
||||
if (mes > rtp->rtcp->reported_maxmes) {
|
||||
rtp->rtcp->reported_maxmes = mes;
|
||||
}
|
||||
|
||||
calc_mean_and_standard_deviation(mes, &rtp->rtcp->reported_normdev_mes,
|
||||
&rtp->rtcp->reported_stdev_mes, &rtp->rtcp->reported_mes_count);
|
||||
|
||||
ast_debug_rtcp(2, "%s: rtt: %.9f j: %.9f sjh: %.9f lost: %.9f mes: %4.1f\n",
|
||||
ast_rtp_instance_get_channel_id(rtp->owner),
|
||||
rtp->rtcp->normdevrtt,
|
||||
rtp->rtcp->reported_jitter,
|
||||
rtp->rtcp->reported_stdev_jitter,
|
||||
rtp->rtcp->reported_normdev_lost, mes);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Update MES stats based on info we will send in an SR or RR.
|
||||
* This is RTP they sent and we received.
|
||||
*/
|
||||
static void update_local_mes_stats(struct ast_rtp *rtp)
|
||||
{
|
||||
rtp->rxmes = calc_media_experience_score(rtp->owner,
|
||||
rtp->rtcp->normdevrtt,
|
||||
rtp->rxjitter,
|
||||
rtp->rtcp->stdev_rxjitter,
|
||||
rtp->rtcp->normdev_rxlost);
|
||||
|
||||
if (rtp->rtcp->rxmes_count == 0) {
|
||||
rtp->rtcp->minrxmes = rtp->rxmes;
|
||||
}
|
||||
if (rtp->rxmes < rtp->rtcp->minrxmes) {
|
||||
rtp->rtcp->minrxmes = rtp->rxmes;
|
||||
}
|
||||
if (rtp->rxmes > rtp->rtcp->maxrxmes) {
|
||||
rtp->rtcp->maxrxmes = rtp->rxmes;
|
||||
}
|
||||
|
||||
calc_mean_and_standard_deviation(rtp->rxmes, &rtp->rtcp->normdev_rxmes,
|
||||
&rtp->rtcp->stdev_rxmes, &rtp->rtcp->rxmes_count);
|
||||
|
||||
ast_debug_rtcp(2, " %s: rtt: %.9f j: %.9f sjh: %.9f lost: %.9f mes: %4.1f\n",
|
||||
ast_rtp_instance_get_channel_id(rtp->owner),
|
||||
rtp->rtcp->normdevrtt,
|
||||
rtp->rxjitter,
|
||||
rtp->rtcp->stdev_rxjitter,
|
||||
rtp->rtcp->normdev_rxlost, rtp->rxmes);
|
||||
}
|
||||
|
||||
/*! \pre instance is locked */
|
||||
static struct ast_rtp_instance *__rtp_find_instance_by_ssrc(struct ast_rtp_instance *instance,
|
||||
struct ast_rtp *rtp, unsigned int ssrc, int source)
|
||||
|
@ -6480,26 +6151,23 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, s
|
|||
|
||||
packetwords = len / 4;
|
||||
|
||||
ast_debug_rtcp(2, "(%s) RTCP got report of %d bytes from %s\n",
|
||||
ast_rtp_instance_get_channel_id(instance),
|
||||
len, ast_sockaddr_stringify(addr));
|
||||
ast_debug_rtcp(1, "(%p) RTCP got report of %d bytes from %s\n",
|
||||
instance, len, ast_sockaddr_stringify(addr));
|
||||
|
||||
/*
|
||||
* Validate the RTCP packet according to an adapted and slightly
|
||||
* modified RFC3550 validation algorithm.
|
||||
*/
|
||||
if (packetwords < RTCP_HEADER_SSRC_LENGTH) {
|
||||
ast_debug_rtcp(2, "(%s) RTCP %p -- from %s: Frame size (%u words) is too short\n",
|
||||
ast_rtp_instance_get_channel_id(instance),
|
||||
transport_rtp, ast_sockaddr_stringify(addr), packetwords);
|
||||
ast_debug_rtcp(1, "(%p) RTCP %p -- from %s: Frame size (%u words) is too short\n",
|
||||
instance, transport_rtp, ast_sockaddr_stringify(addr), packetwords);
|
||||
return &ast_null_frame;
|
||||
}
|
||||
position = 0;
|
||||
first_word = ntohl(rtcpheader[position]);
|
||||
if ((first_word & RTCP_VALID_MASK) != RTCP_VALID_VALUE) {
|
||||
ast_debug_rtcp(2, "(%s) RTCP %p -- from %s: Failed first packet validity check\n",
|
||||
ast_rtp_instance_get_channel_id(instance),
|
||||
transport_rtp, ast_sockaddr_stringify(addr));
|
||||
ast_debug_rtcp(1, "(%p) RTCP %p -- from %s: Failed first packet validity check\n",
|
||||
instance, transport_rtp, ast_sockaddr_stringify(addr));
|
||||
return &ast_null_frame;
|
||||
}
|
||||
do {
|
||||
|
@ -6510,9 +6178,8 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, s
|
|||
first_word = ntohl(rtcpheader[position]);
|
||||
} while ((first_word & RTCP_VERSION_MASK_SHIFTED) == RTCP_VERSION_SHIFTED);
|
||||
if (position != packetwords) {
|
||||
ast_debug_rtcp(2, "(%s) RTCP %p -- from %s: Failed packet version or length check\n",
|
||||
ast_rtp_instance_get_channel_id(instance),
|
||||
transport_rtp, ast_sockaddr_stringify(addr));
|
||||
ast_debug_rtcp(1, "(%p) RTCP %p -- from %s: Failed packet version or length check\n",
|
||||
instance, transport_rtp, ast_sockaddr_stringify(addr));
|
||||
return &ast_null_frame;
|
||||
}
|
||||
|
||||
|
@ -6779,55 +6446,43 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, s
|
|||
report_block->ia_jitter = ntohl(rtcpheader[i + 3]);
|
||||
report_block->lsr = ntohl(rtcpheader[i + 4]);
|
||||
report_block->dlsr = ntohl(rtcpheader[i + 5]);
|
||||
if (report_block->lsr) {
|
||||
int skewed = update_rtt_stats(rtp, report_block->lsr, report_block->dlsr);
|
||||
if (skewed && rtcp_debug_test_addr(addr)) {
|
||||
struct timeval now;
|
||||
unsigned int lsr_now, lsw, msw;
|
||||
gettimeofday(&now, NULL);
|
||||
timeval2ntp(now, &msw, &lsw);
|
||||
lsr_now = (((msw & 0xffff) << 16) | ((lsw & 0xffff0000) >> 16));
|
||||
ast_verbose("Internal RTCP NTP clock skew detected: "
|
||||
"lsr=%u, now=%u, dlsr=%u (%u:%03ums), "
|
||||
if (report_block->lsr
|
||||
&& update_rtt_stats(rtp, report_block->lsr, report_block->dlsr)
|
||||
&& rtcp_debug_test_addr(addr)) {
|
||||
struct timeval now;
|
||||
unsigned int lsr_now, lsw, msw;
|
||||
gettimeofday(&now, NULL);
|
||||
timeval2ntp(now, &msw, &lsw);
|
||||
lsr_now = (((msw & 0xffff) << 16) | ((lsw & 0xffff0000) >> 16));
|
||||
ast_verbose("Internal RTCP NTP clock skew detected: "
|
||||
"lsr=%u, now=%u, dlsr=%u (%u:%03ums), "
|
||||
"diff=%u\n",
|
||||
report_block->lsr, lsr_now, report_block->dlsr, report_block->dlsr / 65536,
|
||||
(report_block->dlsr % 65536) * 1000 / 65536,
|
||||
report_block->dlsr - (lsr_now - report_block->lsr));
|
||||
}
|
||||
}
|
||||
update_jitter_stats(rtp, report_block->ia_jitter);
|
||||
update_lost_stats(rtp, report_block->lost_count.packets);
|
||||
/*
|
||||
* update_reported_mes_stats must be called AFTER
|
||||
* update_rtt_stats, update_jitter_stats and
|
||||
* update_lost_stats.
|
||||
*/
|
||||
update_reported_mes_stats(rtp);
|
||||
|
||||
if (rtcp_debug_test_addr(addr)) {
|
||||
int rate = ast_rtp_get_rate(rtp->f.subclass.format);
|
||||
|
||||
ast_verbose(" Fraction lost: %d\n", report_block->lost_count.fraction);
|
||||
ast_verbose(" Packets lost so far: %u\n", report_block->lost_count.packets);
|
||||
ast_verbose(" Highest sequence number: %u\n", report_block->highest_seq_no & 0x0000ffff);
|
||||
ast_verbose(" Sequence number cycles: %u\n", report_block->highest_seq_no >> 16);
|
||||
ast_verbose(" Interarrival jitter (samp): %u\n", report_block->ia_jitter);
|
||||
ast_verbose(" Interarrival jitter (secs): %.6f\n", ast_samp2sec(report_block->ia_jitter, rate));
|
||||
ast_verbose(" Interarrival jitter: %u\n", report_block->ia_jitter);
|
||||
ast_verbose(" Last SR(our NTP): %lu.%010lu\n",(unsigned long)(report_block->lsr) >> 16,((unsigned long)(report_block->lsr) << 16) * 4096);
|
||||
ast_verbose(" DLSR: %4.4f (sec)\n",(double)report_block->dlsr / 65536.0);
|
||||
ast_verbose(" RTT: %4.4f(sec)\n", rtp->rtcp->rtt);
|
||||
ast_verbose(" MES: %4.1f\n", rtp->rtcp->reported_mes);
|
||||
}
|
||||
}
|
||||
/* If and when we handle more than one report block, this should occur outside
|
||||
* this loop.
|
||||
*/
|
||||
|
||||
message_blob = ast_json_pack("{s: s, s: s, s: f, s: f}",
|
||||
message_blob = ast_json_pack("{s: s, s: s, s: f}",
|
||||
"from", ast_sockaddr_stringify(addr),
|
||||
"to", transport_rtp->rtcp->local_addr_str,
|
||||
"rtt", rtp->rtcp->rtt,
|
||||
"mes", rtp->rtcp->reported_mes);
|
||||
"rtt", rtp->rtcp->rtt);
|
||||
ast_rtp_publish_rtcp_message(instance, ast_rtp_rtcp_received_type(),
|
||||
rtcp_report,
|
||||
message_blob);
|
||||
|
@ -7711,8 +7366,7 @@ static struct ast_frame *ast_rtp_interpret(struct ast_rtp_instance *instance, st
|
|||
struct ast_frame *f;
|
||||
|
||||
/* Update statistics for jitter so they are correct in RTCP */
|
||||
calc_rxstamp_and_jitter(&rxtime, rtp, timestamp, mark);
|
||||
|
||||
calc_rxstamp(&rxtime, rtp, timestamp, mark);
|
||||
|
||||
/* When doing P2P we don't need to raise any frames about SSRC change to the core */
|
||||
while ((f = AST_LIST_REMOVE_HEAD(&frames, frame_list)) != NULL) {
|
||||
|
@ -7863,7 +7517,7 @@ static struct ast_frame *ast_rtp_interpret(struct ast_rtp_instance *instance, st
|
|||
if (ast_format_cache_is_slinear(rtp->f.subclass.format)) {
|
||||
ast_frame_byteswap_be(&rtp->f);
|
||||
}
|
||||
calc_rxstamp_and_jitter(&rtp->f.delivery, rtp, timestamp, mark);
|
||||
calc_rxstamp(&rtp->f.delivery, rtp, timestamp, mark);
|
||||
/* Add timing data to let ast_generic_bridge() put the frame into a jitterbuf */
|
||||
ast_set_flag(&rtp->f, AST_FRFLAG_HAS_TIMING_INFO);
|
||||
rtp->f.ts = timestamp / (ast_rtp_get_rate(rtp->f.subclass.format) / 1000);
|
||||
|
@ -7872,7 +7526,7 @@ static struct ast_frame *ast_rtp_interpret(struct ast_rtp_instance *instance, st
|
|||
/* Video -- samples is # of samples vs. 90000 */
|
||||
if (!rtp->lastividtimestamp)
|
||||
rtp->lastividtimestamp = timestamp;
|
||||
calc_rxstamp_and_jitter(&rtp->f.delivery, rtp, timestamp, mark);
|
||||
calc_rxstamp(&rtp->f.delivery, rtp, timestamp, mark);
|
||||
ast_set_flag(&rtp->f, AST_FRFLAG_HAS_TIMING_INFO);
|
||||
rtp->f.ts = timestamp / (ast_rtp_get_rate(rtp->f.subclass.format) / 1000);
|
||||
rtp->f.samples = timestamp - rtp->lastividtimestamp;
|
||||
|
@ -8321,8 +7975,6 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
|
|||
bundled = (child || AST_VECTOR_SIZE(&rtp->ssrc_mapping)) ? 1 : 0;
|
||||
|
||||
prev_seqno = rtp->lastrxseqno;
|
||||
/* We need to save lastrxseqno for use by jitter before resetting it. */
|
||||
rtp->prevrxseqno = rtp->lastrxseqno;
|
||||
rtp->lastrxseqno = seqno;
|
||||
|
||||
if (!rtp->recv_buffer) {
|
||||
|
@ -8786,8 +8438,7 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro
|
|||
#endif
|
||||
}
|
||||
|
||||
ast_debug_rtcp(1, "(%s) RTCP setup on RTP instance\n",
|
||||
ast_rtp_instance_get_channel_id(instance));
|
||||
ast_debug_rtcp(1, "(%p) RTCP setup on RTP instance\n", instance);
|
||||
} else {
|
||||
if (rtp->rtcp) {
|
||||
if (rtp->rtcp->schedid > -1) {
|
||||
|
@ -8831,8 +8482,6 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro
|
|||
ast_free(rtp->rtcp->local_addr_str);
|
||||
ast_free(rtp->rtcp);
|
||||
rtp->rtcp = NULL;
|
||||
ast_debug_rtcp(1, "(%s) RTCP torn down on RTP instance\n",
|
||||
ast_rtp_instance_get_channel_id(instance));
|
||||
}
|
||||
}
|
||||
} else if (property == AST_RTP_PROPERTY_ASYMMETRIC_CODEC) {
|
||||
|
@ -9073,7 +8722,7 @@ static int ast_rtp_get_stat(struct ast_rtp_instance *instance, struct ast_rtp_in
|
|||
AST_RTP_STAT_TERMINATOR(AST_RTP_INSTANCE_STAT_COMBINED_LOSS);
|
||||
|
||||
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_TXJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->txjitter, rtp->rxjitter);
|
||||
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_RXJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->rxjitter, rtp->rtcp->reported_jitter);
|
||||
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_RXJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->rxjitter, rtp->rtcp->reported_jitter / (unsigned int) 65536.0);
|
||||
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_MAXJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->remote_maxjitter, rtp->rtcp->reported_maxjitter);
|
||||
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_MINJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->remote_minjitter, rtp->rtcp->reported_minjitter);
|
||||
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_NORMDEVJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->remote_normdevjitter, rtp->rtcp->reported_normdev_jitter);
|
||||
|
@ -9091,19 +8740,6 @@ static int ast_rtp_get_stat(struct ast_rtp_instance *instance, struct ast_rtp_in
|
|||
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_STDEVRTT, AST_RTP_INSTANCE_STAT_COMBINED_RTT, stats->stdevrtt, rtp->rtcp->stdevrtt);
|
||||
AST_RTP_STAT_TERMINATOR(AST_RTP_INSTANCE_STAT_COMBINED_RTT);
|
||||
|
||||
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_TXMES, AST_RTP_INSTANCE_STAT_COMBINED_MES, stats->txmes, rtp->rxmes);
|
||||
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_RXMES, AST_RTP_INSTANCE_STAT_COMBINED_MES, stats->rxmes, rtp->rtcp->reported_mes);
|
||||
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_MAXMES, AST_RTP_INSTANCE_STAT_COMBINED_MES, stats->remote_maxmes, rtp->rtcp->reported_maxmes);
|
||||
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_MINMES, AST_RTP_INSTANCE_STAT_COMBINED_MES, stats->remote_minmes, rtp->rtcp->reported_minmes);
|
||||
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_NORMDEVMES, AST_RTP_INSTANCE_STAT_COMBINED_MES, stats->remote_normdevmes, rtp->rtcp->reported_normdev_mes);
|
||||
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_STDEVMES, AST_RTP_INSTANCE_STAT_COMBINED_MES, stats->remote_stdevmes, rtp->rtcp->reported_stdev_mes);
|
||||
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_MAXMES, AST_RTP_INSTANCE_STAT_COMBINED_MES, stats->local_maxmes, rtp->rtcp->maxrxmes);
|
||||
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_MINMES, AST_RTP_INSTANCE_STAT_COMBINED_MES, stats->local_minmes, rtp->rtcp->minrxmes);
|
||||
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_NORMDEVMES, AST_RTP_INSTANCE_STAT_COMBINED_MES, stats->local_normdevmes, rtp->rtcp->normdev_rxmes);
|
||||
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_STDEVMES, AST_RTP_INSTANCE_STAT_COMBINED_MES, stats->local_stdevmes, rtp->rtcp->stdev_rxjitter);
|
||||
AST_RTP_STAT_TERMINATOR(AST_RTP_INSTANCE_STAT_COMBINED_MES);
|
||||
|
||||
|
||||
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_SSRC, -1, stats->local_ssrc, rtp->ssrc);
|
||||
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_SSRC, -1, stats->remote_ssrc, rtp->themssrc);
|
||||
AST_RTP_STAT_STRCPY(AST_RTP_INSTANCE_STAT_CHANNEL_UNIQUEID, -1, stats->channel_uniqueid, ast_rtp_instance_get_channel_id(instance));
|
||||
|
@ -9159,8 +8795,6 @@ static void ast_rtp_stop(struct ast_rtp_instance *instance)
|
|||
}
|
||||
ao2_lock(instance);
|
||||
#endif
|
||||
ast_debug_rtp(1, "(%s) RTP Stop\n",
|
||||
ast_rtp_instance_get_channel_id(instance));
|
||||
|
||||
if (rtp->rtcp && rtp->rtcp->schedid > -1) {
|
||||
ao2_unlock(instance);
|
||||
|
|
|
@ -36,14 +36,11 @@
|
|||
#include "asterisk/rtp_engine.h"
|
||||
#include "asterisk/data_buffer.h"
|
||||
#include "asterisk/format_cache.h"
|
||||
#include <assert.h>
|
||||
#include <sched.h>
|
||||
|
||||
enum test_type {
|
||||
TEST_TYPE_NONE = 0, /* No special setup required */
|
||||
TEST_TYPE_NACK, /* Enable NACK */
|
||||
TEST_TYPE_REMB, /* Enable REMB */
|
||||
TEST_TYPE_STD_RTCP, /* Let the stack do RTCP */
|
||||
};
|
||||
|
||||
static void ast_sched_context_destroy_wrapper(struct ast_sched_context *sched)
|
||||
|
@ -57,30 +54,18 @@ static int test_init_rtp_instances(struct ast_rtp_instance **instance1,
|
|||
struct ast_rtp_instance **instance2, struct ast_sched_context *test_sched,
|
||||
enum test_type type)
|
||||
{
|
||||
struct ast_sockaddr addr1;
|
||||
struct ast_sockaddr addr2;
|
||||
enum ast_rtp_instance_rtcp rtcp_type = AST_RTP_INSTANCE_RTCP_MUX;
|
||||
struct ast_sockaddr addr;
|
||||
|
||||
ast_sockaddr_parse(&addr1, "127.0.0.1", 0);
|
||||
ast_sockaddr_parse(&addr2, "127.0.0.1", 0);
|
||||
ast_sockaddr_parse(&addr, "127.0.0.1", 0);
|
||||
|
||||
*instance1 = ast_rtp_instance_new("asterisk", test_sched, &addr1, "instance1");
|
||||
*instance2 = ast_rtp_instance_new("asterisk", test_sched, &addr2, "instance2");
|
||||
*instance1 = ast_rtp_instance_new("asterisk", test_sched, &addr, NULL);
|
||||
*instance2 = ast_rtp_instance_new("asterisk", test_sched, &addr, NULL);
|
||||
if (!instance1 || !instance2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_rtp_instance_set_channel_id(*instance1, "instance1");
|
||||
ast_rtp_instance_set_channel_id(*instance2, "instance2");
|
||||
|
||||
if (type == TEST_TYPE_STD_RTCP) {
|
||||
rtcp_type = AST_RTP_INSTANCE_RTCP_STANDARD;
|
||||
}
|
||||
|
||||
ast_rtp_instance_set_prop(*instance1,
|
||||
AST_RTP_PROPERTY_RTCP, rtcp_type);
|
||||
ast_rtp_instance_set_prop(*instance2,
|
||||
AST_RTP_PROPERTY_RTCP, rtcp_type);
|
||||
ast_rtp_instance_set_prop(*instance1, AST_RTP_PROPERTY_RTCP, AST_RTP_INSTANCE_RTCP_MUX);
|
||||
ast_rtp_instance_set_prop(*instance2, AST_RTP_PROPERTY_RTCP, AST_RTP_INSTANCE_RTCP_MUX);
|
||||
|
||||
if (type == TEST_TYPE_NACK) {
|
||||
ast_rtp_instance_set_prop(*instance1, AST_RTP_PROPERTY_RETRANS_RECV, 1);
|
||||
|
@ -92,11 +77,11 @@ static int test_init_rtp_instances(struct ast_rtp_instance **instance1,
|
|||
ast_rtp_instance_set_prop(*instance2, AST_RTP_PROPERTY_REMB, 1);
|
||||
}
|
||||
|
||||
ast_rtp_instance_get_local_address(*instance1, &addr1);
|
||||
ast_rtp_instance_set_remote_address(*instance2, &addr1);
|
||||
ast_rtp_instance_get_local_address(*instance1, &addr);
|
||||
ast_rtp_instance_set_remote_address(*instance2, &addr);
|
||||
|
||||
ast_rtp_instance_get_local_address(*instance2, &addr2);
|
||||
ast_rtp_instance_set_remote_address(*instance1, &addr2);
|
||||
ast_rtp_instance_get_local_address(*instance2, &addr);
|
||||
ast_rtp_instance_set_remote_address(*instance1, &addr);
|
||||
|
||||
ast_rtp_instance_reset_test_engine(*instance1);
|
||||
|
||||
|
@ -145,120 +130,6 @@ static void test_write_and_read_frames(struct ast_rtp_instance *instance1,
|
|||
test_read_frames(instance2, num);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Unfortunately, we can't use usleep() to create
|
||||
* packet spacing because there are signals in use
|
||||
* which cause usleep to immediately return. Instead
|
||||
* we have to spin. :(
|
||||
*/
|
||||
static void SLEEP_SPINNER(int ms)
|
||||
{
|
||||
struct timeval a = ast_tvnow();
|
||||
|
||||
while(1) {
|
||||
sched_yield();
|
||||
if (ast_remaining_ms(a, ms) <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is NOT really a reliable implementation.
|
||||
* Its purpose is only to aid in code development in res_rtp_asterisk.
|
||||
*/
|
||||
static void test_write_and_read_interleaved_frames(struct ast_rtp_instance *instance1,
|
||||
struct ast_rtp_instance *instance2, int howlong, int rtcp_interval)
|
||||
{
|
||||
char data[320] = "";
|
||||
int pktinterval = 20;
|
||||
|
||||
struct ast_frame frame_out1 = {
|
||||
.frametype = AST_FRAME_VOICE,
|
||||
.subclass.format = ast_format_ulaw,
|
||||
.seqno = 4556,
|
||||
.data.ptr = data,
|
||||
.datalen = 160,
|
||||
.samples = 1,
|
||||
.len = pktinterval,
|
||||
.ts = 4622295,
|
||||
};
|
||||
struct ast_frame frame_out2 = {
|
||||
.frametype = AST_FRAME_VOICE,
|
||||
.subclass.format = ast_format_ulaw,
|
||||
.seqno = 6554,
|
||||
.data.ptr = data,
|
||||
.datalen = 160,
|
||||
.samples = 1,
|
||||
.len = pktinterval,
|
||||
.ts = 8622295,
|
||||
};
|
||||
struct ast_frame *frame_in1;
|
||||
struct ast_frame *frame_in2;
|
||||
int index;
|
||||
int num;
|
||||
int rtcpnum;
|
||||
int reverse = 1;
|
||||
int send_rtcp = 0;
|
||||
|
||||
num = howlong / pktinterval;
|
||||
|
||||
rtcpnum = rtcp_interval / pktinterval;
|
||||
|
||||
ast_set_flag(&frame_out1, AST_FRFLAG_HAS_SEQUENCE_NUMBER);
|
||||
ast_set_flag(&frame_out1, AST_FRFLAG_HAS_TIMING_INFO);
|
||||
ast_set_flag(&frame_out2, AST_FRFLAG_HAS_SEQUENCE_NUMBER);
|
||||
ast_set_flag(&frame_out2, AST_FRFLAG_HAS_TIMING_INFO);
|
||||
|
||||
for (index = 0; index < num; index++) {
|
||||
struct timeval start = ast_tvnow();
|
||||
time_t ms;
|
||||
|
||||
if (index == 1) {
|
||||
ast_clear_flag(&frame_out1, AST_FRFLAG_HAS_SEQUENCE_NUMBER);
|
||||
ast_clear_flag(&frame_out1, AST_FRFLAG_HAS_TIMING_INFO);
|
||||
ast_clear_flag(&frame_out2, AST_FRFLAG_HAS_SEQUENCE_NUMBER);
|
||||
ast_clear_flag(&frame_out2, AST_FRFLAG_HAS_TIMING_INFO);
|
||||
}
|
||||
frame_out1.seqno += index;
|
||||
frame_out1.delivery = start;
|
||||
frame_out1.ts += frame_out1.len;
|
||||
ast_rtp_instance_write(instance1, &frame_out1);
|
||||
|
||||
if (send_rtcp && index && (index % rtcpnum == 0)) {
|
||||
ast_rtp_instance_queue_report(instance1);
|
||||
}
|
||||
|
||||
frame_in2 = ast_rtp_instance_read(instance2, 0);
|
||||
ast_frfree(frame_in2);
|
||||
frame_in2 = ast_rtp_instance_read(instance2, 1);
|
||||
ast_frfree(frame_in2);
|
||||
|
||||
if (reverse) {
|
||||
frame_out2.seqno += index;
|
||||
frame_out2.delivery = ast_tvnow();
|
||||
frame_out2.ts += frame_out2.len;
|
||||
ast_rtp_instance_write(instance2, &frame_out2);
|
||||
|
||||
if (send_rtcp && index && (index % rtcpnum == 0)) {
|
||||
ast_rtp_instance_queue_report(instance2);
|
||||
}
|
||||
|
||||
frame_in1 = ast_rtp_instance_read(instance1, 0);
|
||||
ast_frfree(frame_in1);
|
||||
frame_in1 = ast_rtp_instance_read(instance1, 1);
|
||||
ast_frfree(frame_in1);
|
||||
|
||||
}
|
||||
|
||||
ms = frame_out1.len - ast_tvdiff_ms(ast_tvnow(),start);
|
||||
ms += (index % 2 ? 5 : 12);
|
||||
ms += (index % 3 ? 2 : 30);
|
||||
SLEEP_SPINNER(ms);
|
||||
}
|
||||
}
|
||||
|
||||
AST_TEST_DEFINE(nack_no_packet_loss)
|
||||
{
|
||||
RAII_VAR(struct ast_rtp_instance *, instance1, NULL, ast_rtp_instance_destroy);
|
||||
|
@ -652,47 +523,8 @@ AST_TEST_DEFINE(fir_nominal)
|
|||
return AST_TEST_PASS;
|
||||
}
|
||||
|
||||
/*
|
||||
* This test should not normally be run. Its only purpose is to
|
||||
* aid in code development.
|
||||
*/
|
||||
AST_TEST_DEFINE(mes)
|
||||
{
|
||||
RAII_VAR(struct ast_rtp_instance *, instance1, NULL, ast_rtp_instance_destroy);
|
||||
RAII_VAR(struct ast_rtp_instance *, instance2, NULL, ast_rtp_instance_destroy);
|
||||
RAII_VAR(struct ast_sched_context *, test_sched, NULL, ast_sched_context_destroy_wrapper);
|
||||
|
||||
switch (cmd) {
|
||||
case TEST_INIT:
|
||||
info->name = "mes";
|
||||
info->category = "/res/res_rtp/";
|
||||
info->summary = "Media Experience Score";
|
||||
info->description =
|
||||
"Tests calculation of Media Experience Score (only run by explicit request)";
|
||||
info->explicit_only = 1;
|
||||
return AST_TEST_NOT_RUN;
|
||||
case TEST_EXECUTE:
|
||||
break;
|
||||
}
|
||||
|
||||
test_sched = ast_sched_context_create();
|
||||
ast_sched_start_thread(test_sched);
|
||||
|
||||
if ((test_init_rtp_instances(&instance1, &instance2,
|
||||
test_sched, TEST_TYPE_NONE)) < 0) {
|
||||
ast_log(LOG_ERROR, "Failed to initialize test!\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
test_write_and_read_interleaved_frames(
|
||||
instance1, instance2, 1000, 5000);
|
||||
|
||||
return AST_TEST_PASS;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
AST_TEST_UNREGISTER(mes);
|
||||
AST_TEST_UNREGISTER(nack_no_packet_loss);
|
||||
AST_TEST_UNREGISTER(nack_nominal);
|
||||
AST_TEST_UNREGISTER(nack_overflow);
|
||||
|
@ -712,7 +544,6 @@ static int load_module(void)
|
|||
AST_TEST_REGISTER(remb_nominal);
|
||||
AST_TEST_REGISTER(sr_rr_nominal);
|
||||
AST_TEST_REGISTER(fir_nominal);
|
||||
AST_TEST_REGISTER(mes);
|
||||
return AST_MODULE_LOAD_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue