webrtcbin: Refactor codec preference retrieval

Now intersect against pads on both sides if they are available.
If the intersection fails, we now just reject the creation of the offer
or answer as it means that the codec_preferences are too restrictive or
that the caps on both sides the webrtcbin are not compatible.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2183>
This commit is contained in:
Olivier Crête 2021-05-05 19:00:11 -04:00
parent 48f4498801
commit f6345b4b03
2 changed files with 103 additions and 45 deletions

View file

@ -1573,34 +1573,78 @@ _update_need_negotiation (GstWebRTCBin * webrtc)
NULL, NULL);
}
static GstCaps *
_query_pad_caps (GstWebRTCBin * webrtc, GstWebRTCRTPTransceiver * rtp_trans,
GstWebRTCBinPad * pad, GstCaps * filter, GError ** error)
{
GstCaps *caps;
caps = gst_pad_peer_query_caps (GST_PAD (pad), filter);
GST_LOG_OBJECT (webrtc, "Using peer query caps: %" GST_PTR_FORMAT, caps);
if (gst_caps_is_empty (caps)) {
g_set_error (error, GST_WEBRTC_BIN_ERROR,
GST_WEBRTC_BIN_ERROR_CAPS_NEGOTIATION_FAILED,
"Caps negotiation on pad %s failed", GST_PAD_NAME (pad));
gst_clear_caps (&caps);
} else if (!gst_caps_is_fixed (caps) || gst_caps_is_equal (caps, filter)
|| gst_caps_is_empty (caps) || gst_caps_is_any (caps)) {
gst_clear_caps (&caps);
}
gst_caps_unref (filter);
return caps;
}
static GstCaps *
_find_codec_preferences (GstWebRTCBin * webrtc,
GstWebRTCRTPTransceiver * rtp_trans, GstPadDirection direction,
guint media_idx)
GstWebRTCRTPTransceiver * rtp_trans, guint media_idx, GError ** error)
{
WebRTCTransceiver *trans = (WebRTCTransceiver *) rtp_trans;
GstCaps *ret = NULL;
GstCaps *codec_preferences = NULL;
GstWebRTCBinPad *pad = NULL;
GstPadDirection direction;
g_assert (rtp_trans);
g_assert (error && *error == NULL);
GST_LOG_OBJECT (webrtc, "retrieving codec preferences from %" GST_PTR_FORMAT,
trans);
if (rtp_trans) {
GST_OBJECT_LOCK (rtp_trans);
if (rtp_trans->codec_preferences) {
GST_LOG_OBJECT (webrtc, "Using codec preferences: %" GST_PTR_FORMAT,
rtp_trans->codec_preferences);
codec_preferences = gst_caps_ref (rtp_trans->codec_preferences);
}
GST_OBJECT_UNLOCK (rtp_trans);
pad = _find_pad_for_transceiver (webrtc, direction, rtp_trans);
GST_OBJECT_LOCK (rtp_trans);
if (rtp_trans->codec_preferences) {
GST_LOG_OBJECT (webrtc, "Using codec preferences: %" GST_PTR_FORMAT,
rtp_trans->codec_preferences);
codec_preferences = gst_caps_ref (rtp_trans->codec_preferences);
}
GST_OBJECT_UNLOCK (rtp_trans);
if (rtp_trans->direction == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY)
direction = GST_PAD_SRC;
else
direction = GST_PAD_SINK;
pad = _find_pad_for_transceiver (webrtc, direction, rtp_trans);
/* try to find a pad */
if (!pad)
pad = _find_pad_for_mline (webrtc, direction, media_idx);
/* For the case where we have set our transceiver to sendrecv, but the
* sink pad has not been requested yet.
*/
if (!pad &&
rtp_trans->direction == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV) {
pad = _find_pad_for_transceiver (webrtc, GST_PAD_SRC, rtp_trans);
/* try to find a pad */
if (!pad)
pad = _find_pad_for_mline (webrtc, GST_PAD_SRC, media_idx);
}
if (pad) {
GstCaps *caps = NULL;
@ -1621,15 +1665,25 @@ _find_codec_preferences (GstWebRTCBin * webrtc,
else if (rtp_trans->kind == GST_WEBRTC_KIND_VIDEO)
gst_caps_set_simple (filter, "media", G_TYPE_STRING, "video", NULL);
caps = gst_pad_peer_query_caps (GST_PAD (pad), filter);
GST_LOG_OBJECT (webrtc, "Using peer query caps: %" GST_PTR_FORMAT, caps);
caps = _query_pad_caps (webrtc, rtp_trans, pad, filter, error);
}
gst_object_unref (pad);
if (!gst_caps_is_fixed (caps) || gst_caps_is_equal (caps, filter)
|| gst_caps_is_empty (caps) || gst_caps_is_any (caps)) {
gst_caps_unref (caps);
caps = NULL;
if (*error)
goto out;
if (caps &&
rtp_trans->direction == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV) {
GstWebRTCBinPad *srcpad =
_find_pad_for_transceiver (webrtc, GST_PAD_SRC, rtp_trans);
if (srcpad) {
caps = _query_pad_caps (webrtc, rtp_trans, srcpad, caps, error);
gst_object_unref (srcpad);
if (*error)
goto out;
}
gst_caps_unref (filter);
}
if (caps && codec_preferences) {
@ -1637,11 +1691,14 @@ _find_codec_preferences (GstWebRTCBin * webrtc,
intersection = gst_caps_intersect_full (codec_preferences, caps,
GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (caps);
gst_clear_caps (&caps);
if (gst_caps_is_empty (intersection)) {
caps = NULL;
gst_caps_unref (intersection);
g_set_error (error, GST_WEBRTC_BIN_ERROR,
GST_WEBRTC_BIN_ERROR_CAPS_NEGOTIATION_FAILED,
"Caps negotiation on pad %s failed againt codec preferences",
GST_PAD_NAME (pad));
gst_clear_caps (&intersection);
} else {
caps = intersection;
}
@ -1653,15 +1710,17 @@ _find_codec_preferences (GstWebRTCBin * webrtc,
ret = caps;
}
}
gst_object_unref (pad);
} else {
if (!ret) {
if (codec_preferences)
ret = gst_caps_ref (codec_preferences);
else if (trans && trans->last_configured_caps)
else if (trans->last_configured_caps)
ret = gst_caps_ref (trans->last_configured_caps);
}
out:
if (codec_preferences)
gst_caps_unref (codec_preferences);
@ -2579,7 +2638,8 @@ static gboolean
sdp_media_from_transceiver (GstWebRTCBin * webrtc, GstSDPMedia * media,
GstWebRTCRTPTransceiver * trans, GstWebRTCSDPType type, guint media_idx,
GString * bundled_mids, guint bundle_idx, gchar * bundle_ufrag,
gchar * bundle_pwd, GArray * reserved_pts, GHashTable * all_mids)
gchar * bundle_pwd, GArray * reserved_pts, GHashTable * all_mids,
GError ** error)
{
/* TODO:
* rtp header extensions
@ -2655,7 +2715,7 @@ sdp_media_from_transceiver (GstWebRTCBin * webrtc, GstSDPMedia * media,
g_free (direction);
if (type == GST_WEBRTC_SDP_TYPE_OFFER) {
caps = _find_codec_preferences (webrtc, trans, GST_PAD_SINK, media_idx);
caps = _find_codec_preferences (webrtc, trans, media_idx, error);
caps =
_add_supported_attributes_to_caps (webrtc, WEBRTC_TRANSCEIVER (trans),
caps);
@ -3171,7 +3231,7 @@ _create_offer_task (GstWebRTCBin * webrtc, const GstStructure * options,
if (sdp_media_from_transceiver (webrtc, &media, trans,
GST_WEBRTC_SDP_TYPE_OFFER, media_idx, bundled_mids, 0, bundle_ufrag,
bundle_pwd, reserved_pts, all_mids)) {
bundle_pwd, reserved_pts, all_mids, error)) {
gst_sdp_message_add_media (ret, &media);
media_idx++;
} else {
@ -3182,6 +3242,8 @@ _create_offer_task (GstWebRTCBin * webrtc, const GstStructure * options,
g_array_free (reserved_pts, TRUE);
reserved_pts = NULL;
}
if (*error)
goto cancel_offer;
}
if (webrtc->bundle_policy != GST_WEBRTC_BUNDLE_POLICY_NONE) {
@ -3567,20 +3629,12 @@ _create_answer_task (GstWebRTCBin * webrtc, const GstStructure * options,
/* FIXME: assumes no shenanigans with recycling transceivers */
g_assert (g_strcmp0 (mid, last_mid) == 0);
if (!answer_caps
&& (rtp_trans->direction ==
GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV
|| rtp_trans->direction ==
GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY))
answer_caps =
_find_codec_preferences (webrtc, rtp_trans, GST_PAD_SINK, i);
if (!answer_caps
&& (rtp_trans->direction ==
GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV
|| rtp_trans->direction ==
GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY))
answer_caps =
_find_codec_preferences (webrtc, rtp_trans, GST_PAD_SRC, i);
if (!answer_caps)
answer_caps = _find_codec_preferences (webrtc, rtp_trans, i, error);
if (*error) {
gst_caps_unref (offer_caps);
goto rejected;
}
if (!answer_caps)
answer_caps = _rtp_caps_from_media (last_media);
@ -3603,8 +3657,11 @@ _create_answer_task (GstWebRTCBin * webrtc, const GstStructure * options,
continue;
}
trans_caps =
_find_codec_preferences (webrtc, rtp_trans, GST_PAD_SINK, j);
trans_caps = _find_codec_preferences (webrtc, rtp_trans, j, error);
if (*error) {
gst_caps_unref (offer_caps);
goto rejected;
}
GST_TRACE_OBJECT (webrtc, "trying to compare %" GST_PTR_FORMAT
" and %" GST_PTR_FORMAT, offer_caps, trans_caps);

View file

@ -41,7 +41,8 @@ typedef enum
GST_WEBRTC_BIN_ERROR_DATA_CHANNEL_FAILURE,
GST_WEBRTC_BIN_ERROR_CLOSED,
GST_WEBRTC_BIN_ERROR_NOT_IMPLEMENTED,
GST_WEBRTC_BIN_ERROR_IMPOSSIBLE_MLINE_RESTRICTION
GST_WEBRTC_BIN_ERROR_IMPOSSIBLE_MLINE_RESTRICTION,
GST_WEBRTC_BIN_ERROR_CAPS_NEGOTIATION_FAILED
} GstWebRTCError;
GstPadTemplate * _find_pad_template (GstElement * element,