mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 18:05:37 +00:00
webrtc: propagate more errors through the promise
Return errors on promises when things fail where available. Things like parsing errors, invalid states, missing fields, unsupported transitions, etc. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1565>
This commit is contained in:
parent
d4fa35efb9
commit
e2d88f0569
5 changed files with 281 additions and 71 deletions
|
@ -2561,7 +2561,8 @@ _add_data_channel_offer (GstWebRTCBin * webrtc, GstSDPMessage * msg,
|
||||||
|
|
||||||
/* TODO: use the options argument */
|
/* TODO: use the options argument */
|
||||||
static GstSDPMessage *
|
static GstSDPMessage *
|
||||||
_create_offer_task (GstWebRTCBin * webrtc, const GstStructure * options)
|
_create_offer_task (GstWebRTCBin * webrtc, const GstStructure * options,
|
||||||
|
GError ** error)
|
||||||
{
|
{
|
||||||
GstSDPMessage *ret;
|
GstSDPMessage *ret;
|
||||||
GString *bundled_mids = NULL;
|
GString *bundled_mids = NULL;
|
||||||
|
@ -2604,8 +2605,8 @@ _create_offer_task (GstWebRTCBin * webrtc, const GstStructure * options)
|
||||||
guint bundle_media_index;
|
guint bundle_media_index;
|
||||||
|
|
||||||
reserved_pts = gather_reserved_pts (webrtc);
|
reserved_pts = gather_reserved_pts (webrtc);
|
||||||
if (last_offer && _parse_bundle (last_offer, &last_bundle) && last_bundle
|
if (last_offer && _parse_bundle (last_offer, &last_bundle, NULL)
|
||||||
&& last_bundle && last_bundle[0]
|
&& last_bundle && last_bundle && last_bundle[0]
|
||||||
&& _get_bundle_index (last_offer, last_bundle, &bundle_media_index)) {
|
&& _get_bundle_index (last_offer, last_bundle, &bundle_media_index)) {
|
||||||
bundle_ufrag =
|
bundle_ufrag =
|
||||||
g_strdup (_media_get_ice_ufrag (last_offer, bundle_media_index));
|
g_strdup (_media_get_ice_ufrag (last_offer, bundle_media_index));
|
||||||
|
@ -2881,7 +2882,8 @@ _get_rtx_target_pt_and_ssrc_from_caps (GstCaps * answer_caps, gint * target_pt,
|
||||||
|
|
||||||
/* TODO: use the options argument */
|
/* TODO: use the options argument */
|
||||||
static GstSDPMessage *
|
static GstSDPMessage *
|
||||||
_create_answer_task (GstWebRTCBin * webrtc, const GstStructure * options)
|
_create_answer_task (GstWebRTCBin * webrtc, const GstStructure * options,
|
||||||
|
GError ** error)
|
||||||
{
|
{
|
||||||
GstSDPMessage *ret = NULL;
|
GstSDPMessage *ret = NULL;
|
||||||
const GstWebRTCSessionDescription *pending_remote =
|
const GstWebRTCSessionDescription *pending_remote =
|
||||||
|
@ -2896,12 +2898,13 @@ _create_answer_task (GstWebRTCBin * webrtc, const GstStructure * options)
|
||||||
GstSDPMessage *last_answer = _get_latest_self_generated_sdp (webrtc);
|
GstSDPMessage *last_answer = _get_latest_self_generated_sdp (webrtc);
|
||||||
|
|
||||||
if (!webrtc->pending_remote_description) {
|
if (!webrtc->pending_remote_description) {
|
||||||
GST_ERROR_OBJECT (webrtc,
|
g_set_error_literal (error, GST_WEBRTC_BIN_ERROR,
|
||||||
|
GST_WEBRTC_BIN_ERROR_INVALID_STATE,
|
||||||
"Asked to create an answer without a remote description");
|
"Asked to create an answer without a remote description");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_parse_bundle (pending_remote->sdp, &bundled))
|
if (!_parse_bundle (pending_remote->sdp, &bundled, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (bundled) {
|
if (bundled) {
|
||||||
|
@ -2909,8 +2912,8 @@ _create_answer_task (GstWebRTCBin * webrtc, const GstStructure * options)
|
||||||
guint bundle_media_index;
|
guint bundle_media_index;
|
||||||
|
|
||||||
if (!_get_bundle_index (pending_remote->sdp, bundled, &bundle_idx)) {
|
if (!_get_bundle_index (pending_remote->sdp, bundled, &bundle_idx)) {
|
||||||
GST_ERROR_OBJECT (webrtc, "Bundle tag is %s but no media found matching",
|
g_set_error (error, GST_WEBRTC_BIN_ERROR, GST_WEBRTC_BIN_ERROR_BAD_SDP,
|
||||||
bundled[0]);
|
"Bundle tag is %s but no media found matching", bundled[0]);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2918,7 +2921,7 @@ _create_answer_task (GstWebRTCBin * webrtc, const GstStructure * options)
|
||||||
bundled_mids = g_string_new ("BUNDLE");
|
bundled_mids = g_string_new ("BUNDLE");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (last_answer && _parse_bundle (last_answer, &last_bundle)
|
if (last_answer && _parse_bundle (last_answer, &last_bundle, NULL)
|
||||||
&& last_bundle && last_bundle[0]
|
&& last_bundle && last_bundle[0]
|
||||||
&& _get_bundle_index (last_answer, last_bundle, &bundle_media_index)) {
|
&& _get_bundle_index (last_answer, last_bundle, &bundle_media_index)) {
|
||||||
bundle_ufrag =
|
bundle_ufrag =
|
||||||
|
@ -3305,14 +3308,15 @@ _create_sdp_task (GstWebRTCBin * webrtc, struct create_sdp *data)
|
||||||
GstWebRTCSessionDescription *desc = NULL;
|
GstWebRTCSessionDescription *desc = NULL;
|
||||||
GstSDPMessage *sdp = NULL;
|
GstSDPMessage *sdp = NULL;
|
||||||
GstStructure *s = NULL;
|
GstStructure *s = NULL;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
GST_INFO_OBJECT (webrtc, "creating %s sdp with options %" GST_PTR_FORMAT,
|
GST_INFO_OBJECT (webrtc, "creating %s sdp with options %" GST_PTR_FORMAT,
|
||||||
gst_webrtc_sdp_type_to_string (data->type), data->options);
|
gst_webrtc_sdp_type_to_string (data->type), data->options);
|
||||||
|
|
||||||
if (data->type == GST_WEBRTC_SDP_TYPE_OFFER)
|
if (data->type == GST_WEBRTC_SDP_TYPE_OFFER)
|
||||||
sdp = _create_offer_task (webrtc, data->options);
|
sdp = _create_offer_task (webrtc, data->options, &error);
|
||||||
else if (data->type == GST_WEBRTC_SDP_TYPE_ANSWER)
|
else if (data->type == GST_WEBRTC_SDP_TYPE_ANSWER)
|
||||||
sdp = _create_answer_task (webrtc, data->options);
|
sdp = _create_answer_task (webrtc, data->options, &error);
|
||||||
else {
|
else {
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -3323,6 +3327,13 @@ _create_sdp_task (GstWebRTCBin * webrtc, struct create_sdp *data)
|
||||||
s = gst_structure_new ("application/x-gst-promise",
|
s = gst_structure_new ("application/x-gst-promise",
|
||||||
gst_webrtc_sdp_type_to_string (data->type),
|
gst_webrtc_sdp_type_to_string (data->type),
|
||||||
GST_TYPE_WEBRTC_SESSION_DESCRIPTION, desc, NULL);
|
GST_TYPE_WEBRTC_SESSION_DESCRIPTION, desc, NULL);
|
||||||
|
} else {
|
||||||
|
g_warn_if_fail (error != NULL);
|
||||||
|
GST_WARNING_OBJECT (webrtc, "returning error: %s",
|
||||||
|
error ? error->message : "Unknown");
|
||||||
|
s = gst_structure_new ("application/x-gstwebrtcbin-error",
|
||||||
|
"error", G_TYPE_ERROR, error, NULL);
|
||||||
|
g_clear_error (&error);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -3775,7 +3786,7 @@ static void
|
||||||
_update_transceiver_from_sdp_media (GstWebRTCBin * webrtc,
|
_update_transceiver_from_sdp_media (GstWebRTCBin * webrtc,
|
||||||
const GstSDPMessage * sdp, guint media_idx,
|
const GstSDPMessage * sdp, guint media_idx,
|
||||||
TransportStream * stream, GstWebRTCRTPTransceiver * rtp_trans,
|
TransportStream * stream, GstWebRTCRTPTransceiver * rtp_trans,
|
||||||
GStrv bundled, guint bundle_idx)
|
GStrv bundled, guint bundle_idx, GError ** error)
|
||||||
{
|
{
|
||||||
WebRTCTransceiver *trans = WEBRTC_TRANSCEIVER (rtp_trans);
|
WebRTCTransceiver *trans = WEBRTC_TRANSCEIVER (rtp_trans);
|
||||||
GstWebRTCRTPTransceiverDirection prev_dir = rtp_trans->current_direction;
|
GstWebRTCRTPTransceiverDirection prev_dir = rtp_trans->current_direction;
|
||||||
|
@ -3812,20 +3823,28 @@ _update_transceiver_from_sdp_media (GstWebRTCBin * webrtc,
|
||||||
local_setup = _get_dtls_setup_from_media (local_media);
|
local_setup = _get_dtls_setup_from_media (local_media);
|
||||||
remote_setup = _get_dtls_setup_from_media (remote_media);
|
remote_setup = _get_dtls_setup_from_media (remote_media);
|
||||||
new_setup = _get_final_setup (local_setup, remote_setup);
|
new_setup = _get_final_setup (local_setup, remote_setup);
|
||||||
if (new_setup == GST_WEBRTC_DTLS_SETUP_NONE)
|
if (new_setup == GST_WEBRTC_DTLS_SETUP_NONE) {
|
||||||
|
g_set_error (error, GST_WEBRTC_BIN_ERROR, GST_WEBRTC_BIN_ERROR_BAD_SDP,
|
||||||
|
"Cannot intersect direction attributes for media %u", media_idx);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
local_dir = _get_direction_from_media (local_media);
|
local_dir = _get_direction_from_media (local_media);
|
||||||
remote_dir = _get_direction_from_media (remote_media);
|
remote_dir = _get_direction_from_media (remote_media);
|
||||||
new_dir = _get_final_direction (local_dir, remote_dir);
|
new_dir = _get_final_direction (local_dir, remote_dir);
|
||||||
|
if (new_dir == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_NONE) {
|
||||||
if (new_dir == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_NONE)
|
g_set_error (error, GST_WEBRTC_BIN_ERROR, GST_WEBRTC_BIN_ERROR_BAD_SDP,
|
||||||
|
"Cannot intersect dtls setup attributes for media %u", media_idx);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (prev_dir != GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_NONE
|
if (prev_dir != GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_NONE
|
||||||
&& new_dir != GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_INACTIVE
|
&& new_dir != GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_INACTIVE
|
||||||
&& prev_dir != new_dir) {
|
&& prev_dir != new_dir) {
|
||||||
GST_FIXME_OBJECT (webrtc, "implement transceiver direction changes");
|
g_set_error (error, GST_WEBRTC_BIN_ERROR,
|
||||||
|
GST_WEBRTC_BIN_ERROR_NOT_IMPLEMENTED,
|
||||||
|
"transceiver direction changes are not implemented. Media %u",
|
||||||
|
media_idx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4023,7 +4042,8 @@ _generate_data_channel_id (GstWebRTCBin * webrtc)
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_update_data_channel_from_sdp_media (GstWebRTCBin * webrtc,
|
_update_data_channel_from_sdp_media (GstWebRTCBin * webrtc,
|
||||||
const GstSDPMessage * sdp, guint media_idx, TransportStream * stream)
|
const GstSDPMessage * sdp, guint media_idx, TransportStream * stream,
|
||||||
|
GError ** error)
|
||||||
{
|
{
|
||||||
const GstSDPMedia *local_media, *remote_media;
|
const GstSDPMedia *local_media, *remote_media;
|
||||||
GstWebRTCDTLSSetup local_setup, remote_setup, new_setup;
|
GstWebRTCDTLSSetup local_setup, remote_setup, new_setup;
|
||||||
|
@ -4042,8 +4062,11 @@ _update_data_channel_from_sdp_media (GstWebRTCBin * webrtc,
|
||||||
local_setup = _get_dtls_setup_from_media (local_media);
|
local_setup = _get_dtls_setup_from_media (local_media);
|
||||||
remote_setup = _get_dtls_setup_from_media (remote_media);
|
remote_setup = _get_dtls_setup_from_media (remote_media);
|
||||||
new_setup = _get_final_setup (local_setup, remote_setup);
|
new_setup = _get_final_setup (local_setup, remote_setup);
|
||||||
if (new_setup == GST_WEBRTC_DTLS_SETUP_NONE)
|
if (new_setup == GST_WEBRTC_DTLS_SETUP_NONE) {
|
||||||
|
g_set_error (error, GST_WEBRTC_BIN_ERROR, GST_WEBRTC_BIN_ERROR_BAD_SDP,
|
||||||
|
"Cannot intersect dtls setup for media %u", media_idx);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* data channel is always rtcp-muxed to avoid generating ICE candidates
|
/* data channel is always rtcp-muxed to avoid generating ICE candidates
|
||||||
* for RTCP */
|
* for RTCP */
|
||||||
|
@ -4052,8 +4075,12 @@ _update_data_channel_from_sdp_media (GstWebRTCBin * webrtc,
|
||||||
|
|
||||||
local_port = _get_sctp_port_from_media (local_media);
|
local_port = _get_sctp_port_from_media (local_media);
|
||||||
remote_port = _get_sctp_port_from_media (local_media);
|
remote_port = _get_sctp_port_from_media (local_media);
|
||||||
if (local_port == -1 || remote_port == -1)
|
if (local_port == -1 || remote_port == -1) {
|
||||||
|
g_set_error (error, GST_WEBRTC_BIN_ERROR, GST_WEBRTC_BIN_ERROR_BAD_SDP,
|
||||||
|
"Could not find sctp port for media %u (local %i, remote %i)",
|
||||||
|
media_idx, local_port, remote_port);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (0 == (local_max_size =
|
if (0 == (local_max_size =
|
||||||
_get_sctp_max_message_size_from_media (local_media)))
|
_get_sctp_max_message_size_from_media (local_media)))
|
||||||
|
@ -4166,7 +4193,7 @@ done:
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
_update_transceivers_from_sdp (GstWebRTCBin * webrtc, SDPSource source,
|
_update_transceivers_from_sdp (GstWebRTCBin * webrtc, SDPSource source,
|
||||||
GstWebRTCSessionDescription * sdp)
|
GstWebRTCSessionDescription * sdp, GError ** error)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
|
@ -4177,14 +4204,14 @@ _update_transceivers_from_sdp (GstWebRTCBin * webrtc, SDPSource source,
|
||||||
/* FIXME: With some peers, it's possible we could have
|
/* FIXME: With some peers, it's possible we could have
|
||||||
* multiple bundles to deal with, although I've never seen one yet */
|
* multiple bundles to deal with, although I've never seen one yet */
|
||||||
if (webrtc->bundle_policy != GST_WEBRTC_BUNDLE_POLICY_NONE)
|
if (webrtc->bundle_policy != GST_WEBRTC_BUNDLE_POLICY_NONE)
|
||||||
if (!_parse_bundle (sdp->sdp, &bundled))
|
if (!_parse_bundle (sdp->sdp, &bundled, error))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (bundled) {
|
if (bundled) {
|
||||||
|
|
||||||
if (!_get_bundle_index (sdp->sdp, bundled, &bundle_idx)) {
|
if (!_get_bundle_index (sdp->sdp, bundled, &bundle_idx)) {
|
||||||
GST_ERROR_OBJECT (webrtc, "Bundle tag is %s but no media found matching",
|
g_set_error (error, GST_WEBRTC_BIN_ERROR, GST_WEBRTC_BIN_ERROR_BAD_SDP,
|
||||||
bundled[0]);
|
"Bundle tag is %s but no media found matching", bundled[0]);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4235,7 +4262,8 @@ _update_transceivers_from_sdp (GstWebRTCBin * webrtc, SDPSource source,
|
||||||
webrtc_transceiver_set_transport ((WebRTCTransceiver *) trans, stream);
|
webrtc_transceiver_set_transport ((WebRTCTransceiver *) trans, stream);
|
||||||
|
|
||||||
if (source == SDP_LOCAL && sdp->type == GST_WEBRTC_SDP_TYPE_OFFER && !trans) {
|
if (source == SDP_LOCAL && sdp->type == GST_WEBRTC_SDP_TYPE_OFFER && !trans) {
|
||||||
GST_ERROR ("State mismatch. Could not find local transceiver by mline.");
|
g_set_error (error, GST_WEBRTC_BIN_ERROR, GST_WEBRTC_BIN_ERROR_BAD_SDP,
|
||||||
|
"State mismatch. Could not find local transceiver by mline %u", i);
|
||||||
goto done;
|
goto done;
|
||||||
} else {
|
} else {
|
||||||
if (g_strcmp0 (gst_sdp_media_get_media (media), "audio") == 0 ||
|
if (g_strcmp0 (gst_sdp_media_get_media (media), "audio") == 0 ||
|
||||||
|
@ -4258,9 +4286,10 @@ _update_transceivers_from_sdp (GstWebRTCBin * webrtc, SDPSource source,
|
||||||
}
|
}
|
||||||
|
|
||||||
_update_transceiver_from_sdp_media (webrtc, sdp->sdp, i, stream,
|
_update_transceiver_from_sdp_media (webrtc, sdp->sdp, i, stream,
|
||||||
trans, bundled, bundle_idx);
|
trans, bundled, bundle_idx, error);
|
||||||
} else if (_message_media_is_datachannel (sdp->sdp, i)) {
|
} else if (_message_media_is_datachannel (sdp->sdp, i)) {
|
||||||
_update_data_channel_from_sdp_media (webrtc, sdp->sdp, i, stream);
|
_update_data_channel_from_sdp_media (webrtc, sdp->sdp, i, stream,
|
||||||
|
error);
|
||||||
} else {
|
} else {
|
||||||
GST_ERROR_OBJECT (webrtc, "Unknown media type in SDP at index %u", i);
|
GST_ERROR_OBJECT (webrtc, "Unknown media type in SDP at index %u", i);
|
||||||
}
|
}
|
||||||
|
@ -4284,6 +4313,20 @@ done:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
check_transceivers_not_removed (GstWebRTCBin * webrtc,
|
||||||
|
GstWebRTCSessionDescription * previous, GstWebRTCSessionDescription * new)
|
||||||
|
{
|
||||||
|
if (!previous)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (gst_sdp_message_medias_len (previous->sdp) >
|
||||||
|
gst_sdp_message_medias_len (new->sdp))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
struct set_description
|
struct set_description
|
||||||
{
|
{
|
||||||
GstPromise *promise;
|
GstPromise *promise;
|
||||||
|
@ -4291,6 +4334,30 @@ struct set_description
|
||||||
GstWebRTCSessionDescription *sdp;
|
GstWebRTCSessionDescription *sdp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static GstWebRTCSessionDescription *
|
||||||
|
get_previous_description (GstWebRTCBin * webrtc, SDPSource source,
|
||||||
|
GstWebRTCSDPType type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case GST_WEBRTC_SDP_TYPE_OFFER:
|
||||||
|
case GST_WEBRTC_SDP_TYPE_PRANSWER:
|
||||||
|
case GST_WEBRTC_SDP_TYPE_ANSWER:
|
||||||
|
if (source == SDP_LOCAL) {
|
||||||
|
return webrtc->current_local_description;
|
||||||
|
} else {
|
||||||
|
return webrtc->current_remote_description;
|
||||||
|
}
|
||||||
|
case GST_WEBRTC_SDP_TYPE_ROLLBACK:
|
||||||
|
return NULL;
|
||||||
|
default:
|
||||||
|
/* other values mean memory corruption/uninitialized! */
|
||||||
|
g_assert_not_reached ();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* http://w3c.github.io/webrtc-pc/#set-description */
|
/* http://w3c.github.io/webrtc-pc/#set-description */
|
||||||
static void
|
static void
|
||||||
_set_description_task (GstWebRTCBin * webrtc, struct set_description *sd)
|
_set_description_task (GstWebRTCBin * webrtc, struct set_description *sd)
|
||||||
|
@ -4316,29 +4383,31 @@ _set_description_task (GstWebRTCBin * webrtc, struct set_description *sd)
|
||||||
g_free (type_str);
|
g_free (type_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!validate_sdp (webrtc->signaling_state, sd->source, sd->sdp, &error)) {
|
if (!validate_sdp (webrtc->signaling_state, sd->source, sd->sdp, &error))
|
||||||
GST_ERROR_OBJECT (webrtc, "%s", error->message);
|
|
||||||
g_clear_error (&error);
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
|
|
||||||
if (webrtc->priv->is_closed) {
|
|
||||||
GST_WARNING_OBJECT (webrtc, "we are closed");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (webrtc->bundle_policy != GST_WEBRTC_BUNDLE_POLICY_NONE)
|
if (webrtc->bundle_policy != GST_WEBRTC_BUNDLE_POLICY_NONE)
|
||||||
if (!_parse_bundle (sd->sdp->sdp, &bundled))
|
if (!_parse_bundle (sd->sdp->sdp, &bundled, &error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (bundled) {
|
if (bundled) {
|
||||||
if (!_get_bundle_index (sd->sdp->sdp, bundled, &bundle_idx)) {
|
if (!_get_bundle_index (sd->sdp->sdp, bundled, &bundle_idx)) {
|
||||||
GST_ERROR_OBJECT (webrtc, "Bundle tag is %s but no media found matching",
|
g_set_error (&error, GST_WEBRTC_BIN_ERROR, GST_WEBRTC_BIN_ERROR_BAD_SDP,
|
||||||
bundled[0]);
|
"Bundle tag is %s but no matching media found", bundled[0]);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!check_transceivers_not_removed (webrtc,
|
||||||
|
get_previous_description (webrtc, sd->source, sd->sdp->type),
|
||||||
|
sd->sdp)) {
|
||||||
|
g_set_error_literal (&error, GST_WEBRTC_BIN_ERROR,
|
||||||
|
GST_WEBRTC_BIN_ERROR_BAD_SDP,
|
||||||
|
"m=lines removed from the SDP. Processing a completely new connection "
|
||||||
|
"is not currently supported.");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
switch (sd->sdp->type) {
|
switch (sd->sdp->type) {
|
||||||
case GST_WEBRTC_SDP_TYPE_OFFER:{
|
case GST_WEBRTC_SDP_TYPE_OFFER:{
|
||||||
if (sd->source == SDP_LOCAL) {
|
if (sd->source == SDP_LOCAL) {
|
||||||
|
@ -4484,7 +4553,8 @@ _set_description_task (GstWebRTCBin * webrtc, struct set_description *sd)
|
||||||
GList *tmp;
|
GList *tmp;
|
||||||
|
|
||||||
/* media modifications */
|
/* media modifications */
|
||||||
_update_transceivers_from_sdp (webrtc, sd->source, sd->sdp);
|
if (!_update_transceivers_from_sdp (webrtc, sd->source, sd->sdp, &error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
for (tmp = webrtc->priv->pending_sink_transceivers; tmp;) {
|
for (tmp = webrtc->priv->pending_sink_transceivers; tmp;) {
|
||||||
GstWebRTCBinPad *pad = GST_WEBRTC_BIN_PAD (tmp->data);
|
GstWebRTCBinPad *pad = GST_WEBRTC_BIN_PAD (tmp->data);
|
||||||
|
@ -4664,7 +4734,15 @@ out:
|
||||||
g_strfreev (bundled);
|
g_strfreev (bundled);
|
||||||
|
|
||||||
PC_UNLOCK (webrtc);
|
PC_UNLOCK (webrtc);
|
||||||
|
if (error) {
|
||||||
|
GST_WARNING_OBJECT (webrtc, "returning error: %s", error->message);
|
||||||
|
gst_promise_reply (sd->promise,
|
||||||
|
gst_structure_new ("application/x-getwebrtcbin-error", "error",
|
||||||
|
G_TYPE_ERROR, error, NULL));
|
||||||
|
g_clear_error (&error);
|
||||||
|
} else {
|
||||||
gst_promise_reply (sd->promise, NULL);
|
gst_promise_reply (sd->promise, NULL);
|
||||||
|
}
|
||||||
PC_LOCK (webrtc);
|
PC_LOCK (webrtc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ typedef enum
|
||||||
GST_WEBRTC_BIN_ERROR_SCTP_FAILURE,
|
GST_WEBRTC_BIN_ERROR_SCTP_FAILURE,
|
||||||
GST_WEBRTC_BIN_ERROR_DATA_CHANNEL_FAILURE,
|
GST_WEBRTC_BIN_ERROR_DATA_CHANNEL_FAILURE,
|
||||||
GST_WEBRTC_BIN_ERROR_CLOSED,
|
GST_WEBRTC_BIN_ERROR_CLOSED,
|
||||||
|
GST_WEBRTC_BIN_ERROR_NOT_IMPLEMENTED,
|
||||||
} GstWebRTCError;
|
} GstWebRTCError;
|
||||||
|
|
||||||
GstPadTemplate * _find_pad_template (GstElement * element,
|
GstPadTemplate * _find_pad_template (GstElement * element,
|
||||||
|
|
|
@ -872,7 +872,7 @@ _get_ice_credentials_from_sdp_media (const GstSDPMessage * sdp, guint media_idx,
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
_parse_bundle (GstSDPMessage * sdp, GStrv * bundled)
|
_parse_bundle (GstSDPMessage * sdp, GStrv * bundled, GError ** error)
|
||||||
{
|
{
|
||||||
const gchar *group;
|
const gchar *group;
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
|
@ -883,8 +883,9 @@ _parse_bundle (GstSDPMessage * sdp, GStrv * bundled)
|
||||||
*bundled = g_strsplit (group + strlen ("BUNDLE "), " ", 0);
|
*bundled = g_strsplit (group + strlen ("BUNDLE "), " ", 0);
|
||||||
|
|
||||||
if (!(*bundled)[0]) {
|
if (!(*bundled)[0]) {
|
||||||
GST_ERROR ("Invalid format for BUNDLE group, expected at least "
|
g_set_error (error, GST_WEBRTC_BIN_ERROR, GST_WEBRTC_BIN_ERROR_BAD_SDP,
|
||||||
"one mid (%s)", group);
|
"Invalid format for BUNDLE group, expected at least one mid (%s)",
|
||||||
|
group);
|
||||||
g_strfreev (*bundled);
|
g_strfreev (*bundled);
|
||||||
*bundled = NULL;
|
*bundled = NULL;
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
@ -101,7 +101,8 @@ gboolean _get_bundle_index (Gst
|
||||||
guint * idx);
|
guint * idx);
|
||||||
G_GNUC_INTERNAL
|
G_GNUC_INTERNAL
|
||||||
gboolean _parse_bundle (GstSDPMessage * sdp,
|
gboolean _parse_bundle (GstSDPMessage * sdp,
|
||||||
GStrv * bundled);
|
GStrv * bundled,
|
||||||
|
GError ** error);
|
||||||
|
|
||||||
G_GNUC_INTERNAL
|
G_GNUC_INTERNAL
|
||||||
const gchar * _media_get_ice_pwd (const GstSDPMessage * msg,
|
const gchar * _media_get_ice_pwd (const GstSDPMessage * msg,
|
||||||
|
|
|
@ -177,14 +177,19 @@ _on_answer_received (GstPromise * promise, gpointer user_data)
|
||||||
GstElement *answerer = TEST_GET_ANSWERER (t);
|
GstElement *answerer = TEST_GET_ANSWERER (t);
|
||||||
const GstStructure *reply;
|
const GstStructure *reply;
|
||||||
GstWebRTCSessionDescription *answer = NULL;
|
GstWebRTCSessionDescription *answer = NULL;
|
||||||
gchar *desc;
|
GError *error = NULL;
|
||||||
|
|
||||||
reply = gst_promise_get_reply (promise);
|
reply = gst_promise_get_reply (promise);
|
||||||
gst_structure_get (reply, "answer",
|
if (gst_structure_get (reply, "answer",
|
||||||
GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &answer, NULL);
|
GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &answer, NULL)) {
|
||||||
desc = gst_sdp_message_as_text (answer->sdp);
|
gchar *desc = gst_sdp_message_as_text (answer->sdp);
|
||||||
GST_INFO ("Created Answer: %s", desc);
|
GST_INFO ("Created Answer: %s", desc);
|
||||||
g_free (desc);
|
g_free (desc);
|
||||||
|
} else if (gst_structure_get (reply, "error", G_TYPE_ERROR, &error, NULL)) {
|
||||||
|
GST_INFO ("Creating answer resulted in error: %s", error->message);
|
||||||
|
} else {
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
g_mutex_lock (&t->lock);
|
g_mutex_lock (&t->lock);
|
||||||
|
|
||||||
|
@ -196,15 +201,28 @@ _on_answer_received (GstPromise * promise, gpointer user_data)
|
||||||
}
|
}
|
||||||
gst_promise_unref (promise);
|
gst_promise_unref (promise);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (t->answer_desc) {
|
||||||
promise = gst_promise_new_with_change_func (_on_answer_set, t, NULL);
|
promise = gst_promise_new_with_change_func (_on_answer_set, t, NULL);
|
||||||
g_signal_emit_by_name (answerer, "set-local-description", t->answer_desc,
|
g_signal_emit_by_name (answerer, "set-local-description", t->answer_desc,
|
||||||
promise);
|
promise);
|
||||||
promise = gst_promise_new_with_change_func (_on_answer_set, t, NULL);
|
promise = gst_promise_new_with_change_func (_on_answer_set, t, NULL);
|
||||||
g_signal_emit_by_name (offeror, "set-remote-description", t->answer_desc,
|
g_signal_emit_by_name (offeror, "set-remote-description", t->answer_desc,
|
||||||
promise);
|
promise);
|
||||||
|
}
|
||||||
|
|
||||||
test_webrtc_signal_state_unlocked (t, STATE_ANSWER_CREATED);
|
test_webrtc_signal_state_unlocked (t, STATE_ANSWER_CREATED);
|
||||||
g_mutex_unlock (&t->lock);
|
g_mutex_unlock (&t->lock);
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
g_clear_error (&error);
|
||||||
|
if (t->state < STATE_ERROR)
|
||||||
|
test_webrtc_signal_state_unlocked (t, STATE_ERROR);
|
||||||
|
g_mutex_unlock (&t->lock);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -232,14 +250,19 @@ _on_offer_received (GstPromise * promise, gpointer user_data)
|
||||||
GstElement *answerer = TEST_GET_ANSWERER (t);
|
GstElement *answerer = TEST_GET_ANSWERER (t);
|
||||||
const GstStructure *reply;
|
const GstStructure *reply;
|
||||||
GstWebRTCSessionDescription *offer = NULL;
|
GstWebRTCSessionDescription *offer = NULL;
|
||||||
gchar *desc;
|
GError *error = NULL;
|
||||||
|
|
||||||
reply = gst_promise_get_reply (promise);
|
reply = gst_promise_get_reply (promise);
|
||||||
gst_structure_get (reply, "offer",
|
if (gst_structure_get (reply, "offer",
|
||||||
GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &offer, NULL);
|
GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &offer, NULL)) {
|
||||||
desc = gst_sdp_message_as_text (offer->sdp);
|
gchar *desc = gst_sdp_message_as_text (offer->sdp);
|
||||||
GST_INFO ("Created offer: %s", desc);
|
GST_INFO ("Created offer: %s", desc);
|
||||||
g_free (desc);
|
g_free (desc);
|
||||||
|
} else if (gst_structure_get (reply, "error", G_TYPE_ERROR, &error, NULL)) {
|
||||||
|
GST_INFO ("Creating offer resulted in error: %s", error->message);
|
||||||
|
} else {
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
g_mutex_lock (&t->lock);
|
g_mutex_lock (&t->lock);
|
||||||
|
|
||||||
|
@ -251,6 +274,10 @@ _on_offer_received (GstPromise * promise, gpointer user_data)
|
||||||
}
|
}
|
||||||
gst_promise_unref (promise);
|
gst_promise_unref (promise);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (t->offer_desc) {
|
||||||
promise = gst_promise_new_with_change_func (_on_offer_set, t, NULL);
|
promise = gst_promise_new_with_change_func (_on_offer_set, t, NULL);
|
||||||
g_signal_emit_by_name (offeror, "set-local-description", t->offer_desc,
|
g_signal_emit_by_name (offeror, "set-local-description", t->offer_desc,
|
||||||
promise);
|
promise);
|
||||||
|
@ -260,9 +287,18 @@ _on_offer_received (GstPromise * promise, gpointer user_data)
|
||||||
|
|
||||||
promise = gst_promise_new_with_change_func (_on_answer_received, t, NULL);
|
promise = gst_promise_new_with_change_func (_on_answer_received, t, NULL);
|
||||||
g_signal_emit_by_name (answerer, "create-answer", NULL, promise);
|
g_signal_emit_by_name (answerer, "create-answer", NULL, promise);
|
||||||
|
}
|
||||||
|
|
||||||
test_webrtc_signal_state_unlocked (t, STATE_OFFER_CREATED);
|
test_webrtc_signal_state_unlocked (t, STATE_OFFER_CREATED);
|
||||||
g_mutex_unlock (&t->lock);
|
g_mutex_unlock (&t->lock);
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
g_clear_error (&error);
|
||||||
|
if (t->state < STATE_ERROR)
|
||||||
|
test_webrtc_signal_state_unlocked (t, STATE_ERROR);
|
||||||
|
g_mutex_unlock (&t->lock);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -2053,7 +2089,7 @@ _check_bundle_tag (struct test_webrtc *t, GstElement * element,
|
||||||
GStrv expected = user_data;
|
GStrv expected = user_data;
|
||||||
guint i;
|
guint i;
|
||||||
|
|
||||||
fail_unless (_parse_bundle (sd->sdp, &bundled));
|
fail_unless (_parse_bundle (sd->sdp, &bundled, NULL));
|
||||||
|
|
||||||
if (!bundled) {
|
if (!bundled) {
|
||||||
fail_unless_equals_int (g_strv_length (expected), 0);
|
fail_unless_equals_int (g_strv_length (expected), 0);
|
||||||
|
@ -2745,6 +2781,98 @@ GST_START_TEST (test_renego_transceiver_set_direction)
|
||||||
|
|
||||||
GST_END_TEST;
|
GST_END_TEST;
|
||||||
|
|
||||||
|
static void
|
||||||
|
offer_remove_last_media (struct test_webrtc *t, GstElement * element,
|
||||||
|
GstPromise * promise, gpointer user_data)
|
||||||
|
{
|
||||||
|
guint i, n;
|
||||||
|
GstSDPMessage *new, *old;
|
||||||
|
const GstSDPOrigin *origin;
|
||||||
|
const GstSDPConnection *conn;
|
||||||
|
|
||||||
|
old = t->offer_desc->sdp;
|
||||||
|
fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_new (&new));
|
||||||
|
|
||||||
|
origin = gst_sdp_message_get_origin (old);
|
||||||
|
conn = gst_sdp_message_get_connection (old);
|
||||||
|
fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_set_version (new,
|
||||||
|
gst_sdp_message_get_version (old)));
|
||||||
|
fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_set_origin (new,
|
||||||
|
origin->username, origin->sess_id, origin->sess_version,
|
||||||
|
origin->nettype, origin->addrtype, origin->addr));
|
||||||
|
fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_set_session_name (new,
|
||||||
|
gst_sdp_message_get_session_name (old)));
|
||||||
|
fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_set_information (new,
|
||||||
|
gst_sdp_message_get_information (old)));
|
||||||
|
fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_set_uri (new,
|
||||||
|
gst_sdp_message_get_uri (old)));
|
||||||
|
fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_set_connection (new,
|
||||||
|
conn->nettype, conn->addrtype, conn->address, conn->ttl,
|
||||||
|
conn->addr_number));
|
||||||
|
|
||||||
|
n = gst_sdp_message_attributes_len (old);
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
const GstSDPAttribute *a = gst_sdp_message_get_attribute (old, i);
|
||||||
|
fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_add_attribute (new,
|
||||||
|
a->key, a->value));
|
||||||
|
}
|
||||||
|
|
||||||
|
n = gst_sdp_message_medias_len (old);
|
||||||
|
fail_unless (n > 0);
|
||||||
|
for (i = 0; i < n - 1; i++) {
|
||||||
|
const GstSDPMedia *m = gst_sdp_message_get_media (old, i);
|
||||||
|
GstSDPMedia *new_m;
|
||||||
|
|
||||||
|
fail_unless_equals_int (GST_SDP_OK, gst_sdp_media_copy (m, &new_m));
|
||||||
|
fail_unless_equals_int (GST_SDP_OK, gst_sdp_message_add_media (new, new_m));
|
||||||
|
gst_sdp_media_init (new_m);
|
||||||
|
gst_sdp_media_free (new_m);
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_webrtc_session_description_free (t->offer_desc);
|
||||||
|
t->offer_desc = gst_webrtc_session_description_new (GST_WEBRTC_SDP_TYPE_OFFER,
|
||||||
|
new);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
offer_set_produced_error (struct test_webrtc *t, GstElement * element,
|
||||||
|
GstPromise * promise, gpointer user_data)
|
||||||
|
{
|
||||||
|
const GstStructure *reply;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
reply = gst_promise_get_reply (promise);
|
||||||
|
fail_unless (gst_structure_get (reply, "error", G_TYPE_ERROR, &error, NULL));
|
||||||
|
GST_INFO ("error produced: %s", error->message);
|
||||||
|
g_clear_error (&error);
|
||||||
|
|
||||||
|
test_webrtc_signal_state_unlocked (t, STATE_CUSTOM);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_START_TEST (test_renego_lose_media_fails)
|
||||||
|
{
|
||||||
|
struct test_webrtc *t = create_audio_video_test ();
|
||||||
|
VAL_SDP_INIT (offer, _count_num_sdp_media, GUINT_TO_POINTER (2), NULL);
|
||||||
|
VAL_SDP_INIT (answer, _count_num_sdp_media, GUINT_TO_POINTER (2), NULL);
|
||||||
|
|
||||||
|
/* check that removing an m=line will produce an error */
|
||||||
|
|
||||||
|
test_validate_sdp (t, &offer, &answer);
|
||||||
|
|
||||||
|
test_webrtc_reset_negotiation (t);
|
||||||
|
|
||||||
|
t->on_offer_created = offer_remove_last_media;
|
||||||
|
t->on_offer_set = offer_set_produced_error;
|
||||||
|
t->on_answer_created = NULL;
|
||||||
|
|
||||||
|
test_webrtc_create_offer (t, t->webrtc1);
|
||||||
|
test_webrtc_wait_for_state_mask (t, 1 << STATE_CUSTOM);
|
||||||
|
|
||||||
|
test_webrtc_free (t);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
static Suite *
|
static Suite *
|
||||||
webrtcbin_suite (void)
|
webrtcbin_suite (void)
|
||||||
{
|
{
|
||||||
|
@ -2785,6 +2913,7 @@ webrtcbin_suite (void)
|
||||||
tcase_add_test (tc, test_bundle_renego_add_stream);
|
tcase_add_test (tc, test_bundle_renego_add_stream);
|
||||||
tcase_add_test (tc, test_bundle_max_compat_max_bundle_renego_add_stream);
|
tcase_add_test (tc, test_bundle_max_compat_max_bundle_renego_add_stream);
|
||||||
tcase_add_test (tc, test_renego_transceiver_set_direction);
|
tcase_add_test (tc, test_renego_transceiver_set_direction);
|
||||||
|
tcase_add_test (tc, test_renego_lose_media_fails);
|
||||||
if (sctpenc && sctpdec) {
|
if (sctpenc && sctpdec) {
|
||||||
tcase_add_test (tc, test_data_channel_create);
|
tcase_add_test (tc, test_data_channel_create);
|
||||||
tcase_add_test (tc, test_data_channel_remote_notify);
|
tcase_add_test (tc, test_data_channel_remote_notify);
|
||||||
|
|
Loading…
Reference in a new issue