mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-02 12:32:29 +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_SOURCES,
|
||||||
PROP_NUM_ACTIVE_SOURCES,
|
PROP_NUM_ACTIVE_SOURCES,
|
||||||
PROP_SOURCES,
|
PROP_SOURCES,
|
||||||
|
PROP_FAVOR_NEW,
|
||||||
PROP_LAST
|
PROP_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -307,6 +308,12 @@ rtp_session_class_init (RTPSessionClass * klass)
|
||||||
"An array of all known sources in the session",
|
"An array of all known sources in the session",
|
||||||
G_TYPE_VALUE_ARRAY, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
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 =
|
klass->get_source_by_ssrc =
|
||||||
GST_DEBUG_FUNCPTR (rtp_session_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:
|
case PROP_SDES:
|
||||||
rtp_session_set_sdes_struct (sess, g_value_get_boxed (value));
|
rtp_session_set_sdes_struct (sess, g_value_get_boxed (value));
|
||||||
break;
|
break;
|
||||||
|
case PROP_FAVOR_NEW:
|
||||||
|
sess->favor_new = g_value_get_boolean (value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -473,6 +483,9 @@ rtp_session_get_property (GObject * object, guint prop_id,
|
||||||
case PROP_SOURCES:
|
case PROP_SOURCES:
|
||||||
g_value_take_boxed (value, rtp_session_create_sources (sess));
|
g_value_take_boxed (value, rtp_session_create_sources (sess));
|
||||||
break;
|
break;
|
||||||
|
case PROP_FAVOR_NEW:
|
||||||
|
g_value_set_boolean (value, sess->favor_new);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -978,33 +991,70 @@ check_collision (RTPSession * sess, RTPSource * source,
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (sess->source != source) {
|
if (sess->source != source) {
|
||||||
|
GstNetAddress *from;
|
||||||
|
gboolean have_from;
|
||||||
|
|
||||||
/* This is not our local source, but lets check if two remote
|
/* This is not our local source, but lets check if two remote
|
||||||
* source collide
|
* source collide
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (rtp) {
|
if (rtp) {
|
||||||
if (source->have_rtp_from) {
|
from = &source->rtp_from;
|
||||||
if (gst_netaddress_equal (&source->rtp_from, &arrival->address))
|
have_from = source->have_rtp_from;
|
||||||
/* Address is the same */
|
} else {
|
||||||
return FALSE;
|
from = &source->rtcp_from;
|
||||||
} else {
|
have_from = source->have_rtcp_from;
|
||||||
/* We don't already have a from address for RTP, just set it */
|
}
|
||||||
rtp_source_set_rtp_from (source, &arrival->address);
|
|
||||||
|
if (have_from) {
|
||||||
|
if (gst_netaddress_equal (from, &arrival->address)) {
|
||||||
|
/* Address is the same */
|
||||||
return FALSE;
|
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 {
|
} else {
|
||||||
if (source->have_rtcp_from) {
|
/* We don't already have a from address for RTP, just set it */
|
||||||
if (gst_netaddress_equal (&source->rtcp_from, &arrival->address))
|
if (rtp)
|
||||||
/* Address is the same */
|
rtp_source_set_rtp_from (source, &arrival->address);
|
||||||
return FALSE;
|
else
|
||||||
} else {
|
|
||||||
/* We don't already have a from address for RTCP, just set it */
|
|
||||||
rtp_source_set_rtcp_from (source, &arrival->address);
|
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
|
/* FIXME: Log 3rd party collision somehow
|
||||||
* Maybe should be done in upper layer, only the SDES can tell us
|
* Maybe should be done in upper layer, only the SDES can tell us
|
||||||
|
@ -1013,7 +1063,7 @@ check_collision (RTPSession * sess, RTPSource * source,
|
||||||
} else {
|
} else {
|
||||||
/* This is sending with our ssrc, is it an address we already know */
|
/* 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)) {
|
arrival->current_time)) {
|
||||||
/* Its a known conflict, its probably a loop, not a collision
|
/* Its a known conflict, its probably a loop, not a collision
|
||||||
* lets just drop the incoming packet
|
* lets just drop the incoming packet
|
||||||
|
@ -1022,6 +1072,9 @@ check_collision (RTPSession * sess, RTPSource * source,
|
||||||
} else {
|
} else {
|
||||||
/* Its a new collision, lets change our SSRC */
|
/* 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));
|
GST_DEBUG ("Collision for SSRC %x", rtp_source_get_ssrc (source));
|
||||||
on_ssrc_collision (sess, source);
|
on_ssrc_collision (sess, source);
|
||||||
|
|
||||||
|
|
|
@ -191,6 +191,7 @@ struct _RTPSession {
|
||||||
RTPSessionStats stats;
|
RTPSessionStats stats;
|
||||||
|
|
||||||
gboolean change_ssrc;
|
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
|
* @src: The source the packet came in
|
||||||
* @address: address to check for
|
* @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,
|
* Checks if an address which has a conflict is already known. If it is
|
||||||
* otherwise remembers it to prevent loops.
|
* a known conflict, remember the time
|
||||||
*
|
*
|
||||||
* Returns: TRUE if it was a known conflict, FALSE otherwise
|
* Returns: TRUE if it was a known conflict, FALSE otherwise
|
||||||
*/
|
*/
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
rtp_source_find_add_conflicting_address (RTPSource * src,
|
rtp_source_find_conflicting_address (RTPSource * src, GstNetAddress * address,
|
||||||
GstNetAddress * address, GstClockTime time)
|
GstClockTime time)
|
||||||
{
|
{
|
||||||
GList *item;
|
GList *item;
|
||||||
RTPConflictingAddress *new_conflict;
|
|
||||||
|
|
||||||
for (item = g_list_first (src->conflicting_addresses);
|
for (item = g_list_first (src->conflicting_addresses);
|
||||||
item; item = g_list_next (item)) {
|
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);
|
new_conflict = g_new0 (RTPConflictingAddress, 1);
|
||||||
|
|
||||||
memcpy (&new_conflict->address, address, sizeof (GstNetAddress));
|
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,
|
src->conflicting_addresses = g_list_prepend (src->conflicting_addresses,
|
||||||
new_conflict);
|
new_conflict);
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -236,7 +236,11 @@ gboolean rtp_source_get_last_rb (RTPSource *src, guint8 *fraction
|
||||||
|
|
||||||
void rtp_source_reset (RTPSource * src);
|
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,
|
GstNetAddress *address,
|
||||||
GstClockTime time);
|
GstClockTime time);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue