mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-02 04:22:27 +00:00
rtpsession: Make it possible to favor new sources in case of SSRC conflict
Add a "favor-new" property that tells the session to favor new sources when there is a SSRC conflict. This is useful for SIP calls and other such cases where a remote loop is extremely unlikely. Fixes #607615
This commit is contained in:
parent
f336ea283f
commit
a6dfe96169
4 changed files with 102 additions and 29 deletions
|
@ -66,6 +66,7 @@ enum
|
|||
PROP_NUM_SOURCES,
|
||||
PROP_NUM_ACTIVE_SOURCES,
|
||||
PROP_SOURCES,
|
||||
PROP_FAVOR_NEW,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
|
@ -307,6 +308,12 @@ rtp_session_class_init (RTPSessionClass * klass)
|
|||
"An array of all known sources in the session",
|
||||
G_TYPE_VALUE_ARRAY, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_FAVOR_NEW,
|
||||
g_param_spec_boolean ("favor-new", "Favor new sources",
|
||||
"Resolve SSRC conflict in favor of new sources", FALSE,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
|
||||
klass->get_source_by_ssrc =
|
||||
GST_DEBUG_FUNCPTR (rtp_session_get_source_by_ssrc);
|
||||
|
||||
|
@ -431,6 +438,9 @@ rtp_session_set_property (GObject * object, guint prop_id,
|
|||
case PROP_SDES:
|
||||
rtp_session_set_sdes_struct (sess, g_value_get_boxed (value));
|
||||
break;
|
||||
case PROP_FAVOR_NEW:
|
||||
sess->favor_new = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -473,6 +483,9 @@ rtp_session_get_property (GObject * object, guint prop_id,
|
|||
case PROP_SOURCES:
|
||||
g_value_take_boxed (value, rtp_session_create_sources (sess));
|
||||
break;
|
||||
case PROP_FAVOR_NEW:
|
||||
g_value_set_boolean (value, sess->favor_new);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -978,33 +991,70 @@ check_collision (RTPSession * sess, RTPSource * source,
|
|||
return FALSE;
|
||||
|
||||
if (sess->source != source) {
|
||||
GstNetAddress *from;
|
||||
gboolean have_from;
|
||||
|
||||
/* This is not our local source, but lets check if two remote
|
||||
* source collide
|
||||
*/
|
||||
|
||||
if (rtp) {
|
||||
if (source->have_rtp_from) {
|
||||
if (gst_netaddress_equal (&source->rtp_from, &arrival->address))
|
||||
/* Address is the same */
|
||||
return FALSE;
|
||||
} else {
|
||||
/* We don't already have a from address for RTP, just set it */
|
||||
rtp_source_set_rtp_from (source, &arrival->address);
|
||||
from = &source->rtp_from;
|
||||
have_from = source->have_rtp_from;
|
||||
} else {
|
||||
from = &source->rtcp_from;
|
||||
have_from = source->have_rtcp_from;
|
||||
}
|
||||
|
||||
if (have_from) {
|
||||
if (gst_netaddress_equal (from, &arrival->address)) {
|
||||
/* Address is the same */
|
||||
return FALSE;
|
||||
} else {
|
||||
GST_LOG ("we have a third-party collision or loop ssrc:%x",
|
||||
rtp_source_get_ssrc (source));
|
||||
if (sess->favor_new) {
|
||||
if (rtp_source_find_conflicting_address (source,
|
||||
&arrival->address, arrival->current_time)) {
|
||||
gchar buf1[40];
|
||||
gst_netaddress_to_string (&arrival->address, buf1, 40);
|
||||
GST_LOG ("Known conflict on %x for %s, dropping packet",
|
||||
rtp_source_get_ssrc (source), buf1);
|
||||
return TRUE;
|
||||
} else {
|
||||
gchar buf1[40], buf2[40];
|
||||
|
||||
/* Current address is not a known conflict, lets assume this is
|
||||
* a new source. Save old address in possible conflict list
|
||||
*/
|
||||
rtp_source_add_conflicting_address (source, from,
|
||||
arrival->current_time);
|
||||
|
||||
gst_netaddress_to_string (from, buf1, 40);
|
||||
gst_netaddress_to_string (&arrival->address, buf2, 40);
|
||||
GST_DEBUG ("New conflict for ssrc %x, replacing %s with %s,"
|
||||
" saving old as known conflict",
|
||||
rtp_source_get_ssrc (source), buf1, buf2);
|
||||
|
||||
if (rtp)
|
||||
rtp_source_set_rtp_from (source, &arrival->address);
|
||||
else
|
||||
rtp_source_set_rtcp_from (source, &arrival->address);
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
/* Don't need to save old addresses, we ignore new sources */
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (source->have_rtcp_from) {
|
||||
if (gst_netaddress_equal (&source->rtcp_from, &arrival->address))
|
||||
/* Address is the same */
|
||||
return FALSE;
|
||||
} else {
|
||||
/* We don't already have a from address for RTCP, just set it */
|
||||
/* We don't already have a from address for RTP, just set it */
|
||||
if (rtp)
|
||||
rtp_source_set_rtp_from (source, &arrival->address);
|
||||
else
|
||||
rtp_source_set_rtcp_from (source, &arrival->address);
|
||||
return FALSE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
/* We received RTP or RTCP from this source before but the network address
|
||||
* changed. In this case, we have third-party collision or loop */
|
||||
GST_DEBUG ("we have a third-party collision or loop");
|
||||
|
||||
/* FIXME: Log 3rd party collision somehow
|
||||
* Maybe should be done in upper layer, only the SDES can tell us
|
||||
|
@ -1013,7 +1063,7 @@ check_collision (RTPSession * sess, RTPSource * source,
|
|||
} else {
|
||||
/* This is sending with our ssrc, is it an address we already know */
|
||||
|
||||
if (rtp_source_find_add_conflicting_address (source, &arrival->address,
|
||||
if (rtp_source_find_conflicting_address (source, &arrival->address,
|
||||
arrival->current_time)) {
|
||||
/* Its a known conflict, its probably a loop, not a collision
|
||||
* lets just drop the incoming packet
|
||||
|
@ -1022,6 +1072,9 @@ check_collision (RTPSession * sess, RTPSource * source,
|
|||
} else {
|
||||
/* Its a new collision, lets change our SSRC */
|
||||
|
||||
rtp_source_add_conflicting_address (source, &arrival->address,
|
||||
arrival->current_time);
|
||||
|
||||
GST_DEBUG ("Collision for SSRC %x", rtp_source_get_ssrc (source));
|
||||
on_ssrc_collision (sess, source);
|
||||
|
||||
|
|
|
@ -191,6 +191,7 @@ struct _RTPSession {
|
|||
RTPSessionStats stats;
|
||||
|
||||
gboolean change_ssrc;
|
||||
gboolean favor_new;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1587,23 +1587,22 @@ rtp_source_get_last_rb (RTPSource * src, guint8 * fractionlost,
|
|||
}
|
||||
|
||||
/**
|
||||
* rtp_source_find_add_conflicting_address:
|
||||
* rtp_source_find_conflicting_address:
|
||||
* @src: The source the packet came in
|
||||
* @address: address to check for
|
||||
* @time: The time when the packet that is in conflict arrived
|
||||
* @time: The time when the packet that is possibly in conflict arrived
|
||||
*
|
||||
* Checks if an address which has a conflict is already known,
|
||||
* otherwise remembers it to prevent loops.
|
||||
* Checks if an address which has a conflict is already known. If it is
|
||||
* a known conflict, remember the time
|
||||
*
|
||||
* Returns: TRUE if it was a known conflict, FALSE otherwise
|
||||
*/
|
||||
|
||||
gboolean
|
||||
rtp_source_find_add_conflicting_address (RTPSource * src,
|
||||
GstNetAddress * address, GstClockTime time)
|
||||
rtp_source_find_conflicting_address (RTPSource * src, GstNetAddress * address,
|
||||
GstClockTime time)
|
||||
{
|
||||
GList *item;
|
||||
RTPConflictingAddress *new_conflict;
|
||||
|
||||
for (item = g_list_first (src->conflicting_addresses);
|
||||
item; item = g_list_next (item)) {
|
||||
|
@ -1615,6 +1614,24 @@ rtp_source_find_add_conflicting_address (RTPSource * src,
|
|||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* rtp_source_add_conflicting_address:
|
||||
* @src: The source the packet came in
|
||||
* @address: address to remember
|
||||
* @time: The time when the packet that is in conflict arrived
|
||||
*
|
||||
* Adds a new conflict address
|
||||
*/
|
||||
|
||||
void
|
||||
rtp_source_add_conflicting_address (RTPSource * src,
|
||||
GstNetAddress * address, GstClockTime time)
|
||||
{
|
||||
RTPConflictingAddress *new_conflict;
|
||||
|
||||
new_conflict = g_new0 (RTPConflictingAddress, 1);
|
||||
|
||||
memcpy (&new_conflict->address, address, sizeof (GstNetAddress));
|
||||
|
@ -1622,8 +1639,6 @@ rtp_source_find_add_conflicting_address (RTPSource * src,
|
|||
|
||||
src->conflicting_addresses = g_list_prepend (src->conflicting_addresses,
|
||||
new_conflict);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -236,7 +236,11 @@ gboolean rtp_source_get_last_rb (RTPSource *src, guint8 *fraction
|
|||
|
||||
void rtp_source_reset (RTPSource * src);
|
||||
|
||||
gboolean rtp_source_find_add_conflicting_address (RTPSource * src,
|
||||
gboolean rtp_source_find_conflicting_address (RTPSource * src,
|
||||
GstNetAddress *address,
|
||||
GstClockTime time);
|
||||
|
||||
void rtp_source_add_conflicting_address (RTPSource * src,
|
||||
GstNetAddress *address,
|
||||
GstClockTime time);
|
||||
|
||||
|
|
Loading…
Reference in a new issue