diff --git a/images/wkdev_sdk/Containerfile b/images/wkdev_sdk/Containerfile index 7c0503c..b4555c7 100644 --- a/images/wkdev_sdk/Containerfile +++ b/images/wkdev_sdk/Containerfile @@ -76,6 +76,9 @@ RUN sed -i 's/^Types: deb$/Types: deb deb-src/' /etc/apt/sources.list.d/ubuntu.s rm -rf WebKit && \ ${APT_AUTOREMOVE} +# GStreamer 1.26.x requires at least Meson 1.4. Install the latest version. +RUN pip install meson==1.7.0 --break-system-packages + # Add Rust environment. ENV RUSTUP_HOME="/opt/rust" \ CARGO_HOME="/opt/rust" \ @@ -89,7 +92,7 @@ RUN rustup default stable && \ # Copy jhbuild helper files and do the initial build & install COPY /jhbuild/jhbuildrc /etc/xdg/jhbuildrc COPY /jhbuild/webkit-sdk-deps.modules /jhbuild/webkit-sdk-deps.modules -COPY /jhbuild/patches/ /jhbuild/patches/ + WORKDIR /jhbuild RUN git clone https://gitlab.gnome.org/GNOME/jhbuild.git && \ cd jhbuild && \ diff --git a/images/wkdev_sdk/jhbuild/patches/0001-webrtcbin-create-and-associate-transceivers-earlier-.patch b/images/wkdev_sdk/jhbuild/patches/0001-webrtcbin-create-and-associate-transceivers-earlier-.patch deleted file mode 100644 index ed452ab..0000000 --- a/images/wkdev_sdk/jhbuild/patches/0001-webrtcbin-create-and-associate-transceivers-earlier-.patch +++ /dev/null @@ -1,887 +0,0 @@ -From e194b6bb173a95dcfb84c328fff426e60e6ab8f9 Mon Sep 17 00:00:00 2001 -From: Carlos Bentzen -Date: Wed, 10 Jul 2024 10:34:19 +0200 -Subject: [PATCH 1/8] webrtcbin: create and associate transceivers earlier in - negotation - -According to https://w3c.github.io/webrtc-pc/#set-the-session-description -(steps in 4.6.10.), we should be creating and associating transceivers when -setting session descriptions. - -Before this commit, webrtcbin deviated from the spec: -1. Transceivers from sink pads where created when the sink pad was - requested, but not associated after setting local description, only - when signaling is STABLE. -2. Transceivers from remote offers were not created after applying the - the remote description, only when the answer is created, and were then - only associated once signaling is STABLE. - -This commit makes webrtcbin follow the spec more closely with regards to -timing of transceivers creation and association. - -A unit test is added, checking that the transceivers are created and -associated after every session description is set. - -Part-of: ---- - .../gst-plugins-bad/ext/webrtc/gstwebrtcbin.c | 477 +++++++++++------- - .../gst-plugins-bad/ext/webrtc/webrtcsdp.c | 11 + - .../gst-plugins-bad/ext/webrtc/webrtcsdp.h | 2 + - .../tests/check/elements/webrtcbin.c | 120 ++++- - 4 files changed, 388 insertions(+), 222 deletions(-) - -diff --git a/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c b/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c -index dce4820a6d..225d246576 100644 ---- a/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c -+++ b/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c -@@ -748,6 +748,13 @@ transceiver_match_for_mid (GstWebRTCRTPTransceiver * trans, const gchar * mid) - return g_strcmp0 (trans->mid, mid) == 0; - } - -+static gboolean -+transceiver_match_for_pending_mid (GstWebRTCRTPTransceiver * trans, -+ const gchar * mid) -+{ -+ return g_strcmp0 (WEBRTC_TRANSCEIVER (trans)->pending_mid, mid) == 0; -+} -+ - static gboolean - transceiver_match_for_mline (GstWebRTCRTPTransceiver * trans, guint * mline) - { -@@ -786,6 +793,20 @@ _find_transceiver_for_mid (GstWebRTCBin * webrtc, const char *mid) - return trans; - } - -+static GstWebRTCRTPTransceiver * -+_find_transceiver_for_pending_mid (GstWebRTCBin * webrtc, const char *mid) -+{ -+ GstWebRTCRTPTransceiver *trans; -+ -+ trans = _find_transceiver (webrtc, mid, -+ (FindTransceiverFunc) transceiver_match_for_pending_mid); -+ -+ GST_TRACE_OBJECT (webrtc, "Found transceiver %" GST_PTR_FORMAT " for " -+ "pending mid %s", trans, mid); -+ -+ return trans; -+} -+ - typedef gboolean (*FindTransportFunc) (TransportStream * p1, - gconstpointer data); - -@@ -4553,146 +4574,51 @@ _create_answer_task (GstWebRTCBin * webrtc, const GstStructure * options, - - _remove_optional_offer_fields (offer_caps); - -- if (last_answer && i < gst_sdp_message_medias_len (last_answer) -- && (rtp_trans = _find_transceiver_for_mid (webrtc, mid))) { -+ rtp_trans = _find_transceiver_for_mid (webrtc, mid); -+ if (!rtp_trans) { -+ g_set_error (error, GST_WEBRTC_ERROR, GST_WEBRTC_ERROR_INVALID_STATE, -+ "Transceiver for media with mid %s not found", mid); -+ gst_caps_unref (offer_caps); -+ goto rejected; -+ } -+ GstCaps *current_caps = -+ _find_codec_preferences (webrtc, rtp_trans, i, error); -+ if (*error) { -+ gst_caps_unref (offer_caps); -+ goto rejected; -+ } -+ -+ if (last_answer && i < gst_sdp_message_medias_len (last_answer)) { - const GstSDPMedia *last_media = - gst_sdp_message_get_media (last_answer, i); - const gchar *last_mid = - gst_sdp_media_get_attribute_val (last_media, "mid"); -- GstCaps *current_caps; -- - /* FIXME: assumes no shenanigans with recycling transceivers */ - g_assert (g_strcmp0 (mid, last_mid) == 0); -- -- current_caps = _find_codec_preferences (webrtc, rtp_trans, i, error); -- if (*error) { -- gst_caps_unref (offer_caps); -- goto rejected; -- } - if (!current_caps) - current_caps = _rtp_caps_from_media (last_media); -- -- if (current_caps) { -- answer_caps = gst_caps_intersect (offer_caps, current_caps); -- if (gst_caps_is_empty (answer_caps)) { -- GST_WARNING_OBJECT (webrtc, "Caps from offer for m-line %d (%" -- GST_PTR_FORMAT ") don't intersect with caps from codec" -- " preferences and transceiver %" GST_PTR_FORMAT, i, offer_caps, -- current_caps); -- gst_caps_unref (current_caps); -- gst_caps_unref (answer_caps); -- gst_caps_unref (offer_caps); -- goto rejected; -- } -- gst_caps_unref (current_caps); -- } -- -- /* XXX: In theory we're meant to use the sendrecv formats for the -- * inactive direction however we don't know what that may be and would -- * require asking outside what it expects to possibly send later */ -- -- GST_LOG_OBJECT (webrtc, "Found existing previously negotiated " -- "transceiver %" GST_PTR_FORMAT " from mid %s for mline %u " -- "using caps %" GST_PTR_FORMAT, rtp_trans, mid, i, answer_caps); -- } else { -- for (j = 0; j < webrtc->priv->transceivers->len; j++) { -- GstCaps *trans_caps; -- -- rtp_trans = g_ptr_array_index (webrtc->priv->transceivers, j); -- -- if (g_list_find (seen_transceivers, rtp_trans)) { -- /* Don't double allocate a transceiver to multiple mlines */ -- rtp_trans = NULL; -- continue; -- } -- -- trans_caps = _find_codec_preferences (webrtc, rtp_trans, j, error); -- if (*error) { -- gst_caps_unref (offer_caps); -- goto rejected; -- } -- -- GST_LOG_OBJECT (webrtc, "trying to compare %" GST_PTR_FORMAT -- " and %" GST_PTR_FORMAT, offer_caps, trans_caps); -- -- /* FIXME: technically this is a little overreaching as some fields we -- * we can deal with not having and/or we may have unrecognized fields -- * that we cannot actually support */ -- if (trans_caps) { -- answer_caps = gst_caps_intersect (offer_caps, trans_caps); -- gst_caps_unref (trans_caps); -- if (answer_caps) { -- if (!gst_caps_is_empty (answer_caps)) { -- GST_LOG_OBJECT (webrtc, -- "found compatible transceiver %" GST_PTR_FORMAT -- " for offer media %u", rtp_trans, i); -- break; -- } -- gst_caps_unref (answer_caps); -- answer_caps = NULL; -- } -- } -- rtp_trans = NULL; -- } -- } -- -- if (rtp_trans) { -- answer_dir = rtp_trans->direction; -- g_assert (answer_caps != NULL); -- } else { -- /* if no transceiver, then we only receive that stream and respond with -- * the intersection with the transceivers codec preferences caps */ -- answer_dir = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY; -- GST_WARNING_OBJECT (webrtc, "did not find compatible transceiver for " -- "offer caps %" GST_PTR_FORMAT ", will only receive", offer_caps); - } - -- if (!rtp_trans) { -- GstCaps *trans_caps; -- GstWebRTCKind kind = GST_WEBRTC_KIND_UNKNOWN; -- -- if (g_strcmp0 (gst_sdp_media_get_media (offer_media), "audio") == 0) -- kind = GST_WEBRTC_KIND_AUDIO; -- else if (g_strcmp0 (gst_sdp_media_get_media (offer_media), -- "video") == 0) -- kind = GST_WEBRTC_KIND_VIDEO; -- else -- GST_LOG_OBJECT (webrtc, "Unknown media kind %s", -- GST_STR_NULL (gst_sdp_media_get_media (offer_media))); -- -- trans = _create_webrtc_transceiver (webrtc, answer_dir, i, kind, NULL); -- rtp_trans = GST_WEBRTC_RTP_TRANSCEIVER (trans); -- -- PC_UNLOCK (webrtc); -- g_signal_emit (webrtc, -- gst_webrtc_bin_signals[ON_NEW_TRANSCEIVER_SIGNAL], 0, rtp_trans); -- PC_LOCK (webrtc); -- -- GST_LOG_OBJECT (webrtc, "Created new transceiver %" GST_PTR_FORMAT -- " for mline %u with media kind %d", trans, i, kind); -- -- trans_caps = _find_codec_preferences (webrtc, rtp_trans, i, error); -- if (*error) { -+ if (current_caps) { -+ answer_caps = gst_caps_intersect (offer_caps, current_caps); -+ if (gst_caps_is_empty (answer_caps)) { -+ GST_WARNING_OBJECT (webrtc, "Caps from offer for m-line %d (%" -+ GST_PTR_FORMAT ") don't intersect with caps from codec" -+ " preferences and transceiver %" GST_PTR_FORMAT, i, offer_caps, -+ current_caps); -+ gst_caps_unref (current_caps); -+ gst_caps_unref (answer_caps); - 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); -- -- /* FIXME: technically this is a little overreaching as some fields we -- * we can deal with not having and/or we may have unrecognized fields -- * that we cannot actually support */ -- if (trans_caps) { -- answer_caps = gst_caps_intersect (offer_caps, trans_caps); -- gst_clear_caps (&trans_caps); -- } else { -- answer_caps = gst_caps_ref (offer_caps); -- } -+ gst_caps_unref (current_caps); - } else { -- trans = WEBRTC_TRANSCEIVER (rtp_trans); -+ answer_caps = gst_caps_ref (offer_caps); - } - -+ answer_dir = rtp_trans->direction; -+ trans = WEBRTC_TRANSCEIVER (rtp_trans); -+ - seen_transceivers = g_list_prepend (seen_transceivers, rtp_trans); - - if (gst_caps_is_empty (answer_caps)) { -@@ -5739,6 +5665,7 @@ _update_transceiver_from_sdp_media (GstWebRTCBin * webrtc, - if (g_strcmp0 (attr->key, "mid") == 0) { - g_free (rtp_trans->mid); - rtp_trans->mid = g_strdup (attr->value); -+ g_object_notify (G_OBJECT (rtp_trans), "mid"); - } - } - -@@ -6185,7 +6112,6 @@ _update_transceivers_from_sdp (GstWebRTCBin * webrtc, SDPSource source, - for (i = 0; i < gst_sdp_message_medias_len (sdp->sdp); i++) { - const GstSDPMedia *media = gst_sdp_message_get_media (sdp->sdp, i); - TransportStream *stream; -- GstWebRTCRTPTransceiver *trans; - guint transport_idx; - - /* skip rejected media */ -@@ -6197,8 +6123,6 @@ _update_transceivers_from_sdp (GstWebRTCBin * webrtc, SDPSource source, - else - transport_idx = i; - -- trans = _find_transceiver_for_sdp_media (webrtc, sdp->sdp, i); -- - stream = _get_or_create_transport_stream (webrtc, transport_idx, - _message_media_is_datachannel (sdp->sdp, transport_idx)); - if (!bundled) { -@@ -6209,60 +6133,28 @@ _update_transceivers_from_sdp (GstWebRTCBin * webrtc, SDPSource source, - ensure_rtx_hdr_ext (stream); - } - -- if (trans) -- webrtc_transceiver_set_transport ((WebRTCTransceiver *) trans, stream); -- -- if (source == SDP_LOCAL && sdp->type == GST_WEBRTC_SDP_TYPE_OFFER && !trans) { -- g_set_error (error, GST_WEBRTC_ERROR, GST_WEBRTC_ERROR_SDP_SYNTAX_ERROR, -- "State mismatch. Could not find local transceiver by mline %u", i); -- goto done; -- } else { -- if (g_strcmp0 (gst_sdp_media_get_media (media), "audio") == 0 || -- g_strcmp0 (gst_sdp_media_get_media (media), "video") == 0) { -- GstWebRTCKind kind = GST_WEBRTC_KIND_UNKNOWN; -- -- /* No existing transceiver, find an unused one */ -- if (!trans) { -- if (g_strcmp0 (gst_sdp_media_get_media (media), "audio") == 0) -- kind = GST_WEBRTC_KIND_AUDIO; -- else if (g_strcmp0 (gst_sdp_media_get_media (media), "video") == 0) -- kind = GST_WEBRTC_KIND_VIDEO; -- else -- GST_LOG_OBJECT (webrtc, "Unknown media kind %s", -- GST_STR_NULL (gst_sdp_media_get_media (media))); -- -- trans = _find_transceiver (webrtc, GINT_TO_POINTER (kind), -- (FindTransceiverFunc) _find_compatible_unassociated_transceiver); -- } -- -- /* Still no transceiver? Create one */ -- /* XXX: default to the advertised direction in the sdp for new -- * transceivers. The spec doesn't actually say what happens here, only -- * that calls to setDirection will change the value. Nothing about -- * a default value when the transceiver is created internally */ -- if (!trans) { -- WebRTCTransceiver *t = _create_webrtc_transceiver (webrtc, -- _get_direction_from_media (media), i, kind, NULL); -- webrtc_transceiver_set_transport (t, stream); -- trans = GST_WEBRTC_RTP_TRANSCEIVER (t); -- PC_UNLOCK (webrtc); -- g_signal_emit (webrtc, -- gst_webrtc_bin_signals[ON_NEW_TRANSCEIVER_SIGNAL], 0, trans); -- PC_LOCK (webrtc); -- } -+ if (g_strcmp0 (gst_sdp_media_get_media (media), "audio") == 0 || -+ g_strcmp0 (gst_sdp_media_get_media (media), "video") == 0) { -+ GstWebRTCRTPTransceiver *trans; - -- _update_transceiver_from_sdp_media (webrtc, sdp->sdp, i, stream, -- trans, bundled, bundle_idx, error); -- if (error && *error) -- goto done; -- } else if (_message_media_is_datachannel (sdp->sdp, i)) { -- _update_data_channel_from_sdp_media (webrtc, sdp->sdp, i, stream, -- error); -- if (error && *error) -- goto done; -- } else { -- GST_ERROR_OBJECT (webrtc, "Unknown media type in SDP at index %u", i); -+ trans = _find_transceiver_for_sdp_media (webrtc, sdp->sdp, i); -+ if (!trans) { -+ g_set_error (error, GST_WEBRTC_ERROR, GST_WEBRTC_ERROR_INVALID_STATE, -+ "Transceiver for mline %d not found", i); -+ goto done; - } -+ webrtc_transceiver_set_transport (WEBRTC_TRANSCEIVER (trans), stream); -+ -+ _update_transceiver_from_sdp_media (webrtc, sdp->sdp, i, stream, -+ trans, bundled, bundle_idx, error); -+ if (error && *error) -+ goto done; -+ } else if (_message_media_is_datachannel (sdp->sdp, i)) { -+ _update_data_channel_from_sdp_media (webrtc, sdp->sdp, i, stream, error); -+ if (error && *error) -+ goto done; -+ } else { -+ GST_ERROR_OBJECT (webrtc, "Unknown media type in SDP at index %u", i); - } - } - -@@ -6412,6 +6304,210 @@ get_last_generated_description (GstWebRTCBin * webrtc, SDPSource source, - return NULL; - } - -+/* https://w3c.github.io/webrtc-pc/#set-description (steps in 4.6.10.) */ -+static gboolean -+_create_and_associate_transceivers_from_sdp (GstWebRTCBin * webrtc, -+ struct set_description *sd, GError ** error) -+{ -+ gboolean ret = FALSE; -+ GStrv bundled = NULL; -+ guint bundle_idx = 0; -+ int i; -+ -+ if (sd->sdp->type == GST_WEBRTC_SDP_TYPE_ROLLBACK) { -+ /* FIXME: -+ * If the mid value of an RTCRtpTransceiver was set to a non-null value -+ * by the RTCSessionDescription that is being rolled back, set the mid -+ * value of that transceiver to null, as described by [JSEP] -+ * (section 4.1.7.2.). -+ * If an RTCRtpTransceiver was created by applying the -+ * RTCSessionDescription that is being rolled back, and a track has not -+ * been attached to it via addTrack, remove that transceiver from -+ * connection's set of transceivers, as described by [JSEP] -+ * (section 4.1.7.2.). -+ * Restore the value of connection's [[ sctpTransport]] internal slot -+ * to its value at the last stable signaling state. -+ */ -+ return ret; -+ } -+ -+ /* FIXME: With some peers, it's possible we could have -+ * multiple bundles to deal with, although I've never seen one yet */ -+ if (webrtc->bundle_policy != GST_WEBRTC_BUNDLE_POLICY_NONE) -+ if (!_parse_bundle (sd->sdp->sdp, &bundled, error)) -+ goto out; -+ -+ if (bundled) { -+ if (!_get_bundle_index (sd->sdp->sdp, bundled, &bundle_idx)) { -+ g_set_error (error, GST_WEBRTC_ERROR, GST_WEBRTC_ERROR_SDP_SYNTAX_ERROR, -+ "Bundle tag is %s but no media found matching", bundled[0]); -+ goto out; -+ } -+ } -+ -+ for (i = 0; i < gst_sdp_message_medias_len (sd->sdp->sdp); i++) { -+ GstWebRTCRTPTransceiver *trans; -+ WebRTCTransceiver *wtrans; -+ const GstSDPMedia *media; -+ const gchar *mid; -+ guint transport_idx; -+ TransportStream *stream; -+ -+ if (_message_media_is_datachannel (sd->sdp->sdp, i)) -+ continue; -+ -+ media = gst_sdp_message_get_media (sd->sdp->sdp, i); -+ mid = gst_sdp_media_get_attribute_val (media, "mid"); -+ -+ /* XXX: not strictly required but a lot of functionality requires a mid */ -+ if (!mid) { -+ g_set_error (error, GST_WEBRTC_ERROR, GST_WEBRTC_ERROR_SDP_SYNTAX_ERROR, -+ "Missing mid attribute in media"); -+ goto out; -+ } -+ -+ if (bundled) -+ transport_idx = bundle_idx; -+ else -+ transport_idx = i; -+ -+ trans = _find_transceiver_for_mid (webrtc, mid); -+ -+ if (sd->source == SDP_LOCAL) { -+ /* If the media description was not yet associated with an RTCRtpTransceiver object then run the following steps: */ -+ if (!trans) { -+ /* Let transceiver be the RTCRtpTransceiver used to create the media description. */ -+ trans = _find_transceiver_for_pending_mid (webrtc, mid); -+ if (!trans) { -+ g_set_error (error, GST_WEBRTC_ERROR, -+ GST_WEBRTC_ERROR_INVALID_STATE, -+ "Transceiver used to created media with mid %s not found", mid); -+ goto out; -+ } -+ wtrans = WEBRTC_TRANSCEIVER (trans); -+ if (wtrans->mline_locked && trans->mline != i) { -+ g_set_error (error, GST_WEBRTC_ERROR, -+ GST_WEBRTC_ERROR_INTERNAL_FAILURE, -+ "Transceiver <%s> with mid %s has mline %d from session description " -+ "but transceiver has locked mline %u", -+ GST_OBJECT_NAME (trans), GST_STR_NULL (trans->mid), i, -+ trans->mline); -+ } -+ trans->mline = i; -+ /* Set transceiver.[[Mid]] to transceiver.[[JsepMid]] */ -+ g_free (trans->mid); -+ trans->mid = g_strdup (mid); -+ g_object_notify (G_OBJECT (trans), "mid"); -+ /* If transceiver.[[Stopped]] is true, abort these sub steps */ -+ if (trans->stopped) -+ continue; -+ /* If the media description is indicated as using an existing media transport according to [RFC8843], let -+ * transport be the RTCDtlsTransport object representing the RTP/RTCP component of that transport. -+ * Otherwise, let transport be a newly created RTCDtlsTransport object with a new underlying RTCIceTransport. -+ */ -+ stream = _get_or_create_transport_stream (webrtc, transport_idx, FALSE); -+ webrtc_transceiver_set_transport (wtrans, stream); -+ } -+ } else { -+ if (!trans) { -+ /* RFC9429: If the "m=" section is "sendrecv" or "recvonly", and there are RtpTransceivers of the same type -+ * that were added to the PeerConnection by addTrack and are not associated with any "m=" section -+ * and are not stopped, find the first (according to the canonical order described in Section 5.2.1) -+ * such RtpTransceiver. */ -+ GstWebRTCRTPTransceiverDirection direction = -+ _get_direction_from_media (media); -+ if (direction == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV -+ || direction == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY) { -+ int j; -+ for (j = 0; j < webrtc->priv->transceivers->len; ++j) { -+ trans = g_ptr_array_index (webrtc->priv->transceivers, j); -+ if (trans->mid || trans->stopped) { -+ trans = NULL; -+ continue; -+ } -+ -+ /* FIXME: Here we shouldn't in theory need to match caps, as the spec says only about -+ * "RtpTransceivers of the same type". However, transceivers created by requesting sink -+ * pads (aka addTrack) may still have unknown type at this point. We may be missing updating -+ * the transceiver type early enough during caps negotation. -+ */ -+ GstCaps *trans_caps = -+ _find_codec_preferences (webrtc, trans, i, error); -+ if (error && *error) -+ goto out; -+ -+ if (trans_caps) { -+ GstCaps *offer_caps = _rtp_caps_from_media (media); -+ GstCaps *caps = gst_caps_intersect (offer_caps, trans_caps); -+ gst_caps_unref (offer_caps); -+ gst_caps_unref (trans_caps); -+ if (caps) { -+ if (!gst_caps_is_empty (caps)) { -+ GST_LOG_OBJECT (webrtc, -+ "found compatible transceiver %" GST_PTR_FORMAT -+ " for offer media %u", trans, i); -+ gst_caps_unref (caps); -+ break; -+ } -+ gst_caps_unref (caps); -+ caps = NULL; -+ } -+ } -+ trans = NULL; -+ } -+ } -+ } -+ -+ /* If no RtpTransceiver was found in the previous step, create one with a "recvonly" direction. */ -+ if (!trans) { -+ wtrans = _create_webrtc_transceiver (webrtc, -+ GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY, i, -+ _get_kind_from_media (media), NULL); -+ trans = GST_WEBRTC_RTP_TRANSCEIVER (wtrans); -+ -+ PC_UNLOCK (webrtc); -+ g_signal_emit (webrtc, -+ gst_webrtc_bin_signals[ON_NEW_TRANSCEIVER_SIGNAL], 0, trans); -+ PC_LOCK (webrtc); -+ } -+ -+ /* Associate the found or created RtpTransceiver with the "m=" section by setting the value of -+ * the RtpTransceiver's mid property to the MID of the "m=" section, and establish a mapping -+ * between the transceiver and the index of the "m=" section. */ -+ wtrans = WEBRTC_TRANSCEIVER (trans); -+ if (wtrans->mline_locked && trans->mline != i) { -+ g_set_error (error, GST_WEBRTC_ERROR, -+ GST_WEBRTC_ERROR_INTERNAL_FAILURE, -+ "Transceiver <%s> with mid %s has mline %d from session description " -+ "but transceiver has locked mline %u", -+ GST_OBJECT_NAME (trans), GST_STR_NULL (trans->mid), i, -+ trans->mline); -+ } -+ trans->mline = i; -+ g_free (trans->mid); -+ trans->mid = g_strdup (mid); -+ g_object_notify (G_OBJECT (trans), "mid"); -+ -+ /* If description is of type "answer" or "pranswer", then run the following steps: */ -+ if (sd->sdp->type == GST_WEBRTC_SDP_TYPE_ANSWER -+ || sd->sdp->type == GST_WEBRTC_SDP_TYPE_PRANSWER) { -+ /* Set transceiver.[[CurrentDirection]] to direction. */ -+ trans->current_direction = _get_direction_from_media (media); -+ } -+ /* Let transport be the RTCDtlsTransport object representing the RTP/RTCP component of the media transport -+ * used by transceiver's associated media description, according to [RFC8843]. */ -+ if (!wtrans->stream) { -+ stream = _get_or_create_transport_stream (webrtc, transport_idx, FALSE); -+ webrtc_transceiver_set_transport (wtrans, stream); -+ } -+ } -+ } -+ -+ ret = TRUE; -+out: -+ g_strfreev (bundled); -+ return ret; -+} - - /* http://w3c.github.io/webrtc-pc/#set-description */ - static GstStructure * -@@ -6574,21 +6670,8 @@ _set_description_task (GstWebRTCBin * webrtc, struct set_description *sd) - } - } - -- if (sd->sdp->type == GST_WEBRTC_SDP_TYPE_ROLLBACK) { -- /* FIXME: -- * If the mid value of an RTCRtpTransceiver was set to a non-null value -- * by the RTCSessionDescription that is being rolled back, set the mid -- * value of that transceiver to null, as described by [JSEP] -- * (section 4.1.7.2.). -- * If an RTCRtpTransceiver was created by applying the -- * RTCSessionDescription that is being rolled back, and a track has not -- * been attached to it via addTrack, remove that transceiver from -- * connection's set of transceivers, as described by [JSEP] -- * (section 4.1.7.2.). -- * Restore the value of connection's [[ sctpTransport]] internal slot -- * to its value at the last stable signaling state. -- */ -- } -+ if (!_create_and_associate_transceivers_from_sdp (webrtc, sd, &error)) -+ goto out; - - if (webrtc->signaling_state != new_signaling_state) { - webrtc->signaling_state = new_signaling_state; -@@ -6648,6 +6731,12 @@ _set_description_task (GstWebRTCBin * webrtc, struct set_description *sd) - continue; - } - -+ if (!pad->trans->mid) { -+ GST_DEBUG_OBJECT (pad, "transceiver not associated. Skipping"); -+ tmp = tmp->next; -+ continue; -+ } -+ - media = gst_sdp_message_get_media (sd->sdp->sdp, pad->trans->mline); - /* skip rejected media */ - if (gst_sdp_media_get_port (media) == 0) { -diff --git a/subprojects/gst-plugins-bad/ext/webrtc/webrtcsdp.c b/subprojects/gst-plugins-bad/ext/webrtc/webrtcsdp.c -index 67c8143d99..0ece0c6250 100644 ---- a/subprojects/gst-plugins-bad/ext/webrtc/webrtcsdp.c -+++ b/subprojects/gst-plugins-bad/ext/webrtc/webrtcsdp.c -@@ -399,6 +399,17 @@ _get_direction_from_media (const GstSDPMedia * media) - return new_dir; - } - -+GstWebRTCKind -+_get_kind_from_media (const GstSDPMedia * media) -+{ -+ GstWebRTCKind kind = GST_WEBRTC_KIND_UNKNOWN; -+ if (!g_strcmp0 (gst_sdp_media_get_media (media), "audio")) -+ kind = GST_WEBRTC_KIND_AUDIO; -+ else if (!g_strcmp0 (gst_sdp_media_get_media (media), "video")) -+ kind = GST_WEBRTC_KIND_VIDEO; -+ return kind; -+} -+ - #define DIR(val) GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_ ## val - GstWebRTCRTPTransceiverDirection - _intersect_answer_directions (GstWebRTCRTPTransceiverDirection offer, -diff --git a/subprojects/gst-plugins-bad/ext/webrtc/webrtcsdp.h b/subprojects/gst-plugins-bad/ext/webrtc/webrtcsdp.h -index 80d21203c2..abeb5dba33 100644 ---- a/subprojects/gst-plugins-bad/ext/webrtc/webrtcsdp.h -+++ b/subprojects/gst-plugins-bad/ext/webrtc/webrtcsdp.h -@@ -46,6 +46,8 @@ gboolean validate_sdp (Gst - G_GNUC_INTERNAL - GstWebRTCRTPTransceiverDirection _get_direction_from_media (const GstSDPMedia * media); - G_GNUC_INTERNAL -+GstWebRTCKind _get_kind_from_media (const GstSDPMedia * media); -+G_GNUC_INTERNAL - GstWebRTCRTPTransceiverDirection _intersect_answer_directions (GstWebRTCRTPTransceiverDirection offer, - GstWebRTCRTPTransceiverDirection answer); - G_GNUC_INTERNAL -diff --git a/subprojects/gst-plugins-bad/tests/check/elements/webrtcbin.c b/subprojects/gst-plugins-bad/tests/check/elements/webrtcbin.c -index 7fa337e9ba..adf5014e02 100644 ---- a/subprojects/gst-plugins-bad/tests/check/elements/webrtcbin.c -+++ b/subprojects/gst-plugins-bad/tests/check/elements/webrtcbin.c -@@ -50,9 +50,11 @@ typedef enum - STATE_NEW = 1, - STATE_NEGOTIATION_NEEDED, - STATE_OFFER_CREATED, -- STATE_OFFER_SET, -+ STATE_LOCAL_OFFER_SET, -+ STATE_REMOTE_OFFER_SET, - STATE_ANSWER_CREATED, -- STATE_ANSWER_SET, -+ STATE_LOCAL_ANSWER_SET, -+ STATE_REMOTE_ANSWER_SET, - STATE_EOS, - STATE_ERROR, - STATE_CUSTOM, -@@ -100,7 +102,6 @@ struct test_webrtc - GstPromise * promise, - gpointer user_data); - GstWebRTCSessionDescription *offer_desc; -- guint offer_set_count; - gpointer offer_data; - GDestroyNotify offer_notify; - void (*on_offer_set) (struct test_webrtc * t, -@@ -114,7 +115,6 @@ struct test_webrtc - GstPromise * promise, - gpointer user_data); - GstWebRTCSessionDescription *answer_desc; -- guint answer_set_count; - gpointer answer_data; - GDestroyNotify answer_notify; - void (*on_answer_set) (struct test_webrtc * t, -@@ -178,19 +178,31 @@ test_webrtc_state_find_unlocked (struct test_webrtc *t, TestState state, - return FALSE; - } - #endif -+ - static void --_on_answer_set (GstPromise * promise, gpointer user_data) -+_on_local_answer_set (GstPromise * promise, gpointer user_data) - { - struct test_webrtc *t = user_data; - GstElement *answerer = TEST_GET_ANSWERER (t); - - g_mutex_lock (&t->lock); -- if (++t->answer_set_count >= 2) { -- if (t->on_answer_set) -- t->on_answer_set (t, answerer, promise, t->answer_set_data); -- test_webrtc_signal_state_unlocked (t, STATE_ANSWER_SET); -- g_cond_broadcast (&t->cond); -- } -+ if (t->on_answer_set) -+ t->on_answer_set (t, answerer, promise, t->answer_set_data); -+ test_webrtc_signal_state_unlocked (t, STATE_LOCAL_ANSWER_SET); -+ gst_promise_unref (promise); -+ g_mutex_unlock (&t->lock); -+} -+ -+static void -+_on_remote_answer_set (GstPromise * promise, gpointer user_data) -+{ -+ struct test_webrtc *t = user_data; -+ GstElement *offeror = TEST_GET_OFFEROR (t); -+ -+ g_mutex_lock (&t->lock); -+ if (t->on_answer_set) -+ t->on_answer_set (t, offeror, promise, t->answer_set_data); -+ test_webrtc_signal_state_unlocked (t, STATE_REMOTE_ANSWER_SET); - gst_promise_unref (promise); - g_mutex_unlock (&t->lock); - } -@@ -231,10 +243,10 @@ _on_answer_received (GstPromise * promise, gpointer user_data) - 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_local_answer_set, t, NULL); - g_signal_emit_by_name (answerer, "set-local-description", t->answer_desc, - promise); -- promise = gst_promise_new_with_change_func (_on_answer_set, t, NULL); -+ promise = gst_promise_new_with_change_func (_on_remote_answer_set, t, NULL); - g_signal_emit_by_name (offeror, "set-remote-description", t->answer_desc, - promise); - } -@@ -251,18 +263,29 @@ error: - } - - static void --_on_offer_set (GstPromise * promise, gpointer user_data) -+_on_local_offer_set (GstPromise * promise, gpointer user_data) - { - struct test_webrtc *t = user_data; - GstElement *offeror = TEST_GET_OFFEROR (t); - - g_mutex_lock (&t->lock); -- if (++t->offer_set_count >= 2) { -- if (t->on_offer_set) -- t->on_offer_set (t, offeror, promise, t->offer_set_data); -- test_webrtc_signal_state_unlocked (t, STATE_OFFER_SET); -- g_cond_broadcast (&t->cond); -- } -+ if (t->on_offer_set) -+ t->on_offer_set (t, offeror, promise, t->offer_set_data); -+ test_webrtc_signal_state_unlocked (t, STATE_LOCAL_OFFER_SET); -+ gst_promise_unref (promise); -+ g_mutex_unlock (&t->lock); -+} -+ -+static void -+_on_remote_offer_set (GstPromise * promise, gpointer user_data) -+{ -+ struct test_webrtc *t = user_data; -+ GstElement *answerer = TEST_GET_ANSWERER (t); -+ -+ g_mutex_lock (&t->lock); -+ if (t->on_offer_set) -+ t->on_offer_set (t, answerer, promise, t->offer_set_data); -+ test_webrtc_signal_state_unlocked (t, STATE_REMOTE_OFFER_SET); - gst_promise_unref (promise); - g_mutex_unlock (&t->lock); - } -@@ -309,10 +332,10 @@ _on_offer_received (GstPromise * promise, gpointer user_data) - g_mutex_unlock (&t->lock); - - if (t->offer_desc) { -- promise = gst_promise_new_with_change_func (_on_offer_set, t, NULL); -+ promise = gst_promise_new_with_change_func (_on_local_offer_set, t, NULL); - g_signal_emit_by_name (offeror, "set-local-description", t->offer_desc, - promise); -- promise = gst_promise_new_with_change_func (_on_offer_set, t, NULL); -+ promise = gst_promise_new_with_change_func (_on_remote_offer_set, t, NULL); - g_signal_emit_by_name (answerer, "set-remote-description", t->offer_desc, - promise); - -@@ -689,11 +712,9 @@ test_webrtc_reset_negotiation (struct test_webrtc *t) - if (t->offer_desc) - gst_webrtc_session_description_free (t->offer_desc); - t->offer_desc = NULL; -- t->offer_set_count = 0; - if (t->answer_desc) - gst_webrtc_session_description_free (t->answer_desc); - t->answer_desc = NULL; -- t->answer_set_count = 0; - - test_webrtc_signal_state (t, STATE_NEGOTIATION_NEEDED); - } -@@ -832,7 +853,7 @@ static TestState - test_webrtc_wait_for_answer_error_eos (struct test_webrtc *t) - { - TestState states = 0; -- states |= (1 << STATE_ANSWER_SET); -+ states |= (1 << STATE_REMOTE_ANSWER_SET); - states |= (1 << STATE_EOS); - states |= (1 << STATE_ERROR); - return test_webrtc_wait_for_state_mask (t, states); -@@ -961,7 +982,7 @@ test_validate_sdp_full (struct test_webrtc *t, struct validate_sdp *offer, - - if (wait_mask == 0) { - fail_unless_equals_int (test_webrtc_wait_for_answer_error_eos (t), -- STATE_ANSWER_SET); -+ STATE_REMOTE_ANSWER_SET); - } else { - test_webrtc_wait_for_state_mask (t, wait_mask); - } -@@ -1107,6 +1128,7 @@ on_sdp_media_setup (struct test_webrtc *t, GstElement * element, - } - } - -+ - static void - add_fake_audio_src_harness (GstHarness * h, gint pt, guint ssrc) - { -@@ -1419,6 +1441,47 @@ GST_START_TEST (test_payload_types) - - GST_END_TEST; - -+static void -+_check_transceiver_mids (struct test_webrtc *t, GstElement * element, -+ GstPromise * promise, gpointer user_data) -+{ -+ const GArray *expected_mids = user_data; -+ GArray *transceivers; -+ int i; -+ -+ g_signal_emit_by_name (element, "get-transceivers", &transceivers); -+ fail_unless (transceivers != NULL); -+ fail_unless_equals_uint64 (transceivers->len, expected_mids->len); -+ for (i = 0; i < transceivers->len; ++i) { -+ GstWebRTCRTPTransceiver *trans = -+ g_array_index (transceivers, GstWebRTCRTPTransceiver *, i); -+ gchar *mid = g_array_index (expected_mids, char *, i); -+ fail_unless_equals_string (trans->mid, mid); -+ } -+ g_array_unref (transceivers); -+} -+ -+GST_START_TEST (test_transceivers_mid) -+{ -+ struct test_webrtc *t = create_audio_video_test (); -+ const gchar *EXPECTED_MIDS_DATA[] = { "audio0", "video1" }; -+ GArray *expected_mids = g_array_new (FALSE, FALSE, sizeof (gchar *)); -+ g_array_append_vals (expected_mids, EXPECTED_MIDS_DATA, -+ sizeof (EXPECTED_MIDS_DATA) / sizeof (gchar *)); -+ -+ t->on_offer_set = _check_transceiver_mids; -+ t->offer_set_data = expected_mids; -+ -+ t->on_answer_set = _check_transceiver_mids; -+ t->answer_set_data = expected_mids; -+ -+ test_validate_sdp (t, NULL, NULL); -+ test_webrtc_free (t); -+ g_array_free (expected_mids, TRUE); -+} -+ -+GST_END_TEST; -+ - GST_START_TEST (test_no_nice_elements_request_pad) - { - struct test_webrtc *t = test_webrtc_new (); -@@ -1814,7 +1877,7 @@ GST_START_TEST (test_stats_with_stream) - gst_caps_unref (caps); - - test_webrtc_wait_for_answer_error_eos (t); -- test_webrtc_signal_state (t, STATE_ANSWER_SET); -+ test_webrtc_signal_state (t, STATE_REMOTE_ANSWER_SET); - - p = gst_promise_new_with_change_func (_on_stats, t, NULL); - g_signal_emit_by_name (t->webrtc1, "get-stats", NULL, p); -@@ -5955,7 +6018,7 @@ GST_START_TEST (test_sdp_session_setup_attribute) - fail_if (gst_element_set_state (t->webrtc2, GST_STATE_READY) == - GST_STATE_CHANGE_FAILURE); - test_webrtc_create_offer (t); -- test_webrtc_wait_for_state_mask (t, 1 << STATE_ANSWER_SET); -+ test_webrtc_wait_for_state_mask (t, 1 << STATE_REMOTE_ANSWER_SET); - - test_webrtc_wait_for_ice_gathering_complete (t); - -@@ -5993,6 +6056,7 @@ webrtcbin_suite (void) - tcase_add_test (tc, test_media_direction); - tcase_add_test (tc, test_add_transceiver); - tcase_add_test (tc, test_get_transceivers); -+ tcase_add_test (tc, test_transceivers_mid); - tcase_add_test (tc, test_add_recvonly_transceiver); - tcase_add_test (tc, test_recvonly_sendonly); - tcase_add_test (tc, test_payload_types); --- -2.47.0 - diff --git a/images/wkdev_sdk/jhbuild/patches/0002-webrtcbin-reverse-direction-from-remote-media.patch b/images/wkdev_sdk/jhbuild/patches/0002-webrtcbin-reverse-direction-from-remote-media.patch deleted file mode 100644 index cd00e5a..0000000 --- a/images/wkdev_sdk/jhbuild/patches/0002-webrtcbin-reverse-direction-from-remote-media.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 2e69c18ecb12a66ce92f7e3c591343916856c1b1 Mon Sep 17 00:00:00 2001 -From: Carlos Bentzen -Date: Fri, 2 Aug 2024 11:19:56 +0200 -Subject: [PATCH 2/8] webrtcbin: reverse direction from remote media - -This had been overlooked from the spec. We need to reverse -the remote media direction when setting the transceiver direction. - -Part-of: ---- - .../gst-plugins-bad/ext/webrtc/gstwebrtcbin.c | 29 +++++++++++++++++-- - 1 file changed, 26 insertions(+), 3 deletions(-) - -diff --git a/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c b/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c -index 225d246576..bc5ebb1909 100644 ---- a/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c -+++ b/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c -@@ -6304,6 +6304,22 @@ get_last_generated_description (GstWebRTCBin * webrtc, SDPSource source, - return NULL; - } - -+static GstWebRTCRTPTransceiverDirection -+_reverse_direction (GstWebRTCRTPTransceiverDirection direction) -+{ -+ switch (direction) { -+ case GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_NONE: -+ case GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_INACTIVE: -+ case GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV: -+ return direction; -+ case GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY: -+ return GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY; -+ case GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY: -+ return GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY; -+ } -+ return GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_NONE; -+} -+ - /* https://w3c.github.io/webrtc-pc/#set-description (steps in 4.6.10.) */ - static gboolean - _create_and_associate_transceivers_from_sdp (GstWebRTCBin * webrtc, -@@ -6352,12 +6368,14 @@ _create_and_associate_transceivers_from_sdp (GstWebRTCBin * webrtc, - const gchar *mid; - guint transport_idx; - TransportStream *stream; -+ GstWebRTCRTPTransceiverDirection direction; - - if (_message_media_is_datachannel (sd->sdp->sdp, i)) - continue; - - media = gst_sdp_message_get_media (sd->sdp->sdp, i); - mid = gst_sdp_media_get_attribute_val (media, "mid"); -+ direction = _get_direction_from_media (media); - - /* XXX: not strictly required but a lot of functionality requires a mid */ - if (!mid) { -@@ -6414,8 +6432,6 @@ _create_and_associate_transceivers_from_sdp (GstWebRTCBin * webrtc, - * that were added to the PeerConnection by addTrack and are not associated with any "m=" section - * and are not stopped, find the first (according to the canonical order described in Section 5.2.1) - * such RtpTransceiver. */ -- GstWebRTCRTPTransceiverDirection direction = -- _get_direction_from_media (media); - if (direction == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV - || direction == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY) { - int j; -@@ -6488,11 +6504,18 @@ _create_and_associate_transceivers_from_sdp (GstWebRTCBin * webrtc, - trans->mid = g_strdup (mid); - g_object_notify (G_OBJECT (trans), "mid"); - -+ /* Let direction be an RTCRtpTransceiverDirection value representing the direction from the media -+ description, but with the send and receive directions reversed to represent this peer's point of view. */ -+ direction = _reverse_direction (direction); -+ /* If the media description is rejected, set direction to "inactive". */ -+ if (gst_sdp_media_get_port (media) == 0) -+ direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_INACTIVE; -+ - /* If description is of type "answer" or "pranswer", then run the following steps: */ - if (sd->sdp->type == GST_WEBRTC_SDP_TYPE_ANSWER - || sd->sdp->type == GST_WEBRTC_SDP_TYPE_PRANSWER) { - /* Set transceiver.[[CurrentDirection]] to direction. */ -- trans->current_direction = _get_direction_from_media (media); -+ trans->current_direction = direction; - } - /* Let transport be the RTCDtlsTransport object representing the RTP/RTCP component of the media transport - * used by transceiver's associated media description, according to [RFC8843]. */ --- -2.47.0 - diff --git a/images/wkdev_sdk/jhbuild/patches/0003-webrtcbin-connect-output-stream-on-recv-transceivers.patch b/images/wkdev_sdk/jhbuild/patches/0003-webrtcbin-connect-output-stream-on-recv-transceivers.patch deleted file mode 100644 index c7c5a9a..0000000 --- a/images/wkdev_sdk/jhbuild/patches/0003-webrtcbin-connect-output-stream-on-recv-transceivers.patch +++ /dev/null @@ -1,120 +0,0 @@ -From 5bd0033bc9683610a74f668e67672fc524628fb2 Mon Sep 17 00:00:00 2001 -From: Carlos Bentzen -Date: Fri, 2 Aug 2024 11:21:13 +0200 -Subject: [PATCH 3/8] webrtcbin: connect output stream on recv transceivers - -With MR 7156, transceivers and transports are created earlier, -but for sendrecv media we could get `not-linked` errors due to -transportreceivebin not being connected to rtpbin yet when incoming -data arrives. - -This condition wasn't being tested in elements_webrtcbin, but could be -reproduced in the webrtcbidirectional example. This commit now also -adds a test for this, so that this doesn't regress anymore. - -Part-of: ---- - .../gst-plugins-bad/ext/webrtc/gstwebrtcbin.c | 6 ++ - .../tests/check/elements/webrtcbin.c | 62 +++++++++++++++++++ - 2 files changed, 68 insertions(+) - -diff --git a/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c b/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c -index bc5ebb1909..02652c0362 100644 ---- a/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c -+++ b/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c -@@ -6524,6 +6524,12 @@ _create_and_associate_transceivers_from_sdp (GstWebRTCBin * webrtc, - webrtc_transceiver_set_transport (wtrans, stream); - } - } -+ -+ wtrans = WEBRTC_TRANSCEIVER (trans); -+ if (wtrans->stream -+ && (direction == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV -+ || direction == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY)) -+ _connect_output_stream (webrtc, wtrans->stream, transport_idx); - } - - ret = TRUE; -diff --git a/subprojects/gst-plugins-bad/tests/check/elements/webrtcbin.c b/subprojects/gst-plugins-bad/tests/check/elements/webrtcbin.c -index adf5014e02..2272943a27 100644 ---- a/subprojects/gst-plugins-bad/tests/check/elements/webrtcbin.c -+++ b/subprojects/gst-plugins-bad/tests/check/elements/webrtcbin.c -@@ -4651,6 +4651,67 @@ a=group:BUNDLE \r\n\ - test_webrtc_free (t); - } - -+GST_START_TEST (test_audio_sendrecv) -+{ -+ struct test_webrtc *t = test_webrtc_new (); -+ GstHarness *h1, *h2; -+ -+ t->on_negotiation_needed = NULL; -+ t->on_ice_candidate = NULL; -+ t->on_pad_added = _pad_added_fakesink; -+ -+ h1 = gst_harness_new_with_element (t->webrtc1, "sink_0", NULL); -+ add_audio_test_src_harness (h1, 0xDEADBEEF); -+ t->harnesses = g_list_prepend (t->harnesses, h1); -+ -+ h2 = gst_harness_new_with_element (t->webrtc2, "sink_0", NULL); -+ add_audio_test_src_harness (h2, 0xBEEFDEAD); -+ t->harnesses = g_list_prepend (t->harnesses, h2); -+ -+ VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads, -+ NULL, NULL); -+ guint media_format_count[] = { 1 }; -+ VAL_SDP_INIT (media_formats, on_sdp_media_count_formats, -+ media_format_count, &no_duplicate_payloads); -+ VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1), -+ &media_formats); -+ const gchar *expected_offer_setup[] = { "actpass", }; -+ VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup, &count); -+ const gchar *expected_answer_setup[] = { "active", }; -+ VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup, -+ &count); -+ const gchar *expected_offer_direction[] = { "sendrecv", }; -+ VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction, -+ &offer_setup); -+ const gchar *expected_answer_direction[] = { "sendrecv", }; -+ VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction, -+ &answer_setup); -+ GstWebRTCKind expected_kind = GST_WEBRTC_KIND_AUDIO; -+ -+ g_signal_connect (t->webrtc1, "on-new-transceiver", -+ G_CALLBACK (on_new_transceiver_expected_kind), -+ GUINT_TO_POINTER (expected_kind)); -+ g_signal_connect (t->webrtc2, "on-new-transceiver", -+ G_CALLBACK (on_new_transceiver_expected_kind), -+ GUINT_TO_POINTER (expected_kind)); -+ -+ test_validate_sdp (t, &offer, &answer); -+ -+ fail_if (gst_element_set_state (t->webrtc1, -+ GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE); -+ fail_if (gst_element_set_state (t->webrtc2, -+ GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE); -+ -+ /* Exchange a few buffers between webrtcbin1 and webrtcbin2 to check -+ that they can handle incoming data and we get no errors on the bus. */ -+ for (int i = 0; i < 5; i++) { -+ gst_harness_push_from_src (h1); -+ gst_harness_push_from_src (h2); -+ } -+ -+ test_webrtc_free (t); -+} -+ - GST_END_TEST; - - static void -@@ -6051,6 +6112,7 @@ webrtcbin_suite (void) - tcase_add_test (tc, test_session_stats); - tcase_add_test (tc, test_stats_with_stream); - tcase_add_test (tc, test_audio); -+ tcase_add_test (tc, test_audio_sendrecv); - tcase_add_test (tc, test_ice_port_restriction); - tcase_add_test (tc, test_audio_video); - tcase_add_test (tc, test_media_direction); --- -2.47.0 - diff --git a/images/wkdev_sdk/jhbuild/patches/0004-webrtc-Fixes-for-matching-pads-to-unassociated-trans.patch b/images/wkdev_sdk/jhbuild/patches/0004-webrtc-Fixes-for-matching-pads-to-unassociated-trans.patch deleted file mode 100644 index 118d506..0000000 --- a/images/wkdev_sdk/jhbuild/patches/0004-webrtc-Fixes-for-matching-pads-to-unassociated-trans.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 11d381a3d77848e62189df20ba4e7fe8c9dadd45 Mon Sep 17 00:00:00 2001 -From: Jan Schmidt -Date: Wed, 24 Jul 2024 20:59:51 +1000 -Subject: [PATCH 4/8] webrtc: Fixes for matching pads to unassociated - transceivers - -Fix an inverted condition when checking if sink pad caps match -the codec-preference of an unassociated transceiver, and -fix a condition check for transceiver media kind to -avoid matching sinkpad requests where caps aren't provided -against unassociated transceivers where the caps might -not match later. - -Part-of: ---- - subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c b/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c -index 02652c0362..6fa560b554 100644 ---- a/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c -+++ b/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c -@@ -8379,9 +8379,9 @@ gst_webrtc_bin_request_new_pad (GstElement * element, GstPadTemplate * templ, - GstWebRTCBinPad *pad2; - gboolean has_matching_caps; - -- /* Ignore transceivers with a non-matching kind */ -+ /* Ignore transceivers with a non-matching kind or where we don't know the kind we want */ - if (tmptrans->kind != GST_WEBRTC_KIND_UNKNOWN && -- kind != GST_WEBRTC_KIND_UNKNOWN && tmptrans->kind != kind) -+ (kind == GST_WEBRTC_KIND_UNKNOWN || tmptrans->kind != kind)) - continue; - - /* Ignore stopped transmitters */ -@@ -8403,7 +8403,7 @@ gst_webrtc_bin_request_new_pad (GstElement * element, GstPadTemplate * templ, - - GST_OBJECT_LOCK (tmptrans); - has_matching_caps = (caps && tmptrans->codec_preferences && -- !gst_caps_can_intersect (caps, tmptrans->codec_preferences)); -+ gst_caps_can_intersect (caps, tmptrans->codec_preferences)); - GST_OBJECT_UNLOCK (tmptrans); - /* Ignore transceivers with non-matching caps */ - if (!has_matching_caps) --- -2.47.0 - diff --git a/images/wkdev_sdk/jhbuild/patches/0005-webrtcbin-Fix-renegotiation-checks.patch b/images/wkdev_sdk/jhbuild/patches/0005-webrtcbin-Fix-renegotiation-checks.patch deleted file mode 100644 index d044f8d..0000000 --- a/images/wkdev_sdk/jhbuild/patches/0005-webrtcbin-Fix-renegotiation-checks.patch +++ /dev/null @@ -1,275 +0,0 @@ -From 8be67d014ff50275ad0dd0a70f81bb93b24033c6 Mon Sep 17 00:00:00 2001 -From: Jan Schmidt -Date: Thu, 1 Aug 2024 13:42:52 +1000 -Subject: [PATCH 5/8] webrtcbin: Fix renegotiation checks - -When checking for renegotiation against a local offer, -reverse the remote direction in the corresponding answer -to fix falsely not triggering on-negotiation needed when -switching (for example) from local sendrecv -> recvonly -against a peer that answered 'recvonly'. - -In the other direction, when the local was the answerer, -renegotiation might trigger when it didn't need to - -whenever the local transceiver direction differs from -the intersected direction we chose. Instead what we want -is to check if the intersected direction we would now -choose differs from what was previously chosen. - -This makes the behaviour in both cases match the -behaviour described in -https://www.w3.org/TR/webrtc/#dfn-check-if-negotiation-is-needed - -Part-of: ---- - .../gst-plugins-bad/ext/webrtc/gstwebrtcbin.c | 70 ++++++----- - .../tests/check/elements/webrtcbin.c | 113 ++++++++++++++++++ - 2 files changed, 151 insertions(+), 32 deletions(-) - -diff --git a/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c b/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c -index 6fa560b554..6fb42da6f4 100644 ---- a/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c -+++ b/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c -@@ -1772,6 +1772,22 @@ done: - return res; - } - -+static GstWebRTCRTPTransceiverDirection -+_reverse_direction (GstWebRTCRTPTransceiverDirection direction) -+{ -+ switch (direction) { -+ case GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_NONE: -+ case GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_INACTIVE: -+ case GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV: -+ return direction; -+ case GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY: -+ return GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY; -+ case GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY: -+ return GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY; -+ } -+ return GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_NONE; -+} -+ - /* http://w3c.github.io/webrtc-pc/#dfn-check-if-negotiation-is-needed */ - static gboolean - _check_if_negotiation_is_needed (GstWebRTCBin * webrtc) -@@ -1861,33 +1877,39 @@ _check_if_negotiation_is_needed (GstWebRTCBin * webrtc) - /* If connection's currentLocalDescription if of type "offer", and - * the direction of the associated m= section in neither the offer - * nor answer matches t's direction, return "true". */ -- -- if (local_dir != trans->direction && remote_dir != trans->direction) { -- GST_LOG_OBJECT (webrtc, "transceiver direction (%s) doesn't match " -- "description (local %s remote %s)", -+ if (local_dir != trans->direction -+ && _reverse_direction (remote_dir) != trans->direction) { -+ GST_LOG_OBJECT (webrtc, -+ "transceiver direction (%s) doesn't match " -+ "description (local %s remote %s (reversed %s))", - gst_webrtc_rtp_transceiver_direction_to_string (trans->direction), - gst_webrtc_rtp_transceiver_direction_to_string (local_dir), -- gst_webrtc_rtp_transceiver_direction_to_string (remote_dir)); -+ gst_webrtc_rtp_transceiver_direction_to_string (remote_dir), -+ gst_webrtc_rtp_transceiver_direction_to_string (_reverse_direction -+ (remote_dir)) -+ ); - return TRUE; - } - } else if (webrtc->current_local_description->type == - GST_WEBRTC_SDP_TYPE_ANSWER) { -- GstWebRTCRTPTransceiverDirection intersect_dir; -- - /* If connection's currentLocalDescription if of type "answer", and -- * the direction of the associated m= section in the answer does not -- * match t's direction intersected with the offered direction (as -- * described in [JSEP] (section 5.3.1.)), return "true". */ -+ * the direction of the associated m= section in the answer we sent -+ * (local_dir) does not match t's direction intersected with the -+ * offer direction (as described in [JSEP] (section 5.3.1.)), -+ * return "true" because we want to propose a different -+ * direction now. */ - - /* remote is the offer, local is the answer */ -- intersect_dir = _intersect_answer_directions (remote_dir, local_dir); -- -- if (intersect_dir != trans->direction) { -- GST_LOG_OBJECT (webrtc, "transceiver direction (%s) doesn't match " -- "description intersected direction %s (local %s remote %s)", -+ GstWebRTCRTPTransceiverDirection now_intersect_dir = -+ _intersect_answer_directions (remote_dir, trans->direction); -+ if (now_intersect_dir != local_dir) { -+ GST_LOG_OBJECT (webrtc, -+ "transceiver direction (%s) doesn't match for the " -+ "new description intersected direction %s (prev local %s remote %s)", - gst_webrtc_rtp_transceiver_direction_to_string (trans->direction), - gst_webrtc_rtp_transceiver_direction_to_string (local_dir), -- gst_webrtc_rtp_transceiver_direction_to_string (intersect_dir), -+ gst_webrtc_rtp_transceiver_direction_to_string -+ (now_intersect_dir), - gst_webrtc_rtp_transceiver_direction_to_string (remote_dir)); - return TRUE; - } -@@ -6304,22 +6326,6 @@ get_last_generated_description (GstWebRTCBin * webrtc, SDPSource source, - return NULL; - } - --static GstWebRTCRTPTransceiverDirection --_reverse_direction (GstWebRTCRTPTransceiverDirection direction) --{ -- switch (direction) { -- case GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_NONE: -- case GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_INACTIVE: -- case GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV: -- return direction; -- case GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY: -- return GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY; -- case GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY: -- return GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY; -- } -- return GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_NONE; --} -- - /* https://w3c.github.io/webrtc-pc/#set-description (steps in 4.6.10.) */ - static gboolean - _create_and_associate_transceivers_from_sdp (GstWebRTCBin * webrtc, -diff --git a/subprojects/gst-plugins-bad/tests/check/elements/webrtcbin.c b/subprojects/gst-plugins-bad/tests/check/elements/webrtcbin.c -index 2272943a27..e34f350ebd 100644 ---- a/subprojects/gst-plugins-bad/tests/check/elements/webrtcbin.c -+++ b/subprojects/gst-plugins-bad/tests/check/elements/webrtcbin.c -@@ -719,6 +719,14 @@ test_webrtc_reset_negotiation (struct test_webrtc *t) - test_webrtc_signal_state (t, STATE_NEGOTIATION_NEEDED); - } - -+static void -+test_webrtc_clear_states (struct test_webrtc *t) -+{ -+ GST_DEBUG ("clearing states"); -+ g_array_free (t->states, TRUE); -+ t->states = g_array_new (FALSE, TRUE, sizeof (TestState)); -+} -+ - static void - test_webrtc_free (struct test_webrtc *t) - { -@@ -3789,6 +3797,110 @@ GST_START_TEST (test_renego_transceiver_set_direction) - - GST_END_TEST; - -+GST_START_TEST (test_renego_triggering) -+{ -+ -+ struct test_webrtc *t = create_audio_test (); -+ -+ VAL_SDP_INIT (no_duplicate_payloads, on_sdp_media_no_duplicate_payloads, -+ NULL, NULL); -+ -+ guint media_format_count[] = { 1 }; -+ VAL_SDP_INIT (media_formats, on_sdp_media_count_formats, -+ media_format_count, &no_duplicate_payloads); -+ VAL_SDP_INIT (count, _count_num_sdp_media, GUINT_TO_POINTER (1), -+ &media_formats); -+ -+ const gchar *expected_offer_setup[] = { "actpass" }; -+ VAL_SDP_INIT (offer_setup, on_sdp_media_setup, expected_offer_setup, &count); -+ const gchar *expected_answer_setup[] = { "active" }; -+ VAL_SDP_INIT (answer_setup, on_sdp_media_setup, expected_answer_setup, -+ &count); -+ const gchar *expected_offer_direction[] = { "sendrecv" }; -+ VAL_SDP_INIT (offer, on_sdp_media_direction, expected_offer_direction, -+ &offer_setup); -+ const gchar *expected_answer_direction[] = { "recvonly" }; -+ VAL_SDP_INIT (answer, on_sdp_media_direction, expected_answer_direction, -+ &answer_setup); -+ GstCaps *caps; -+ GArray *transceivers; -+ -+ /* Ensure sendrecv stream on webrtc1 */ -+ g_signal_emit_by_name (t->webrtc1, "get-transceivers", &transceivers); -+ fail_unless (transceivers != NULL); -+ fail_unless_equals_int (transceivers->len, 1); -+ -+ GstWebRTCRTPTransceiver *trans_local = -+ g_array_index (transceivers, GstWebRTCRTPTransceiver *, 0); -+ g_object_set (trans_local, "direction", -+ GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV, NULL); -+ -+ /* setup recvonly peer */ -+ caps = gst_caps_from_string (OPUS_RTP_CAPS (96)); -+ gst_caps_set_simple (caps, "ssrc", G_TYPE_UINT, 0xDEADBEEF, NULL); -+ -+ GstWebRTCRTPTransceiver *trans_remote = NULL; -+ GstWebRTCRTPTransceiverDirection direction = -+ GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY; -+ g_signal_emit_by_name (t->webrtc2, "add-transceiver", direction, caps, -+ &trans_remote); -+ gst_caps_unref (caps); -+ fail_unless (trans_remote != NULL); -+ gst_object_unref (trans_remote); -+ -+ test_validate_sdp (t, &offer, &answer); -+ -+ GST_LOG -+ ("Finished validating sendrecv <-> recvonly nego. Triggering renego with recvonly <-> recvonly peers"); -+ -+ /* Now change the sender to recvonly and expect to renegotiate to inactive */ -+ test_webrtc_reset_negotiation (t); -+ test_webrtc_clear_states (t); -+ -+ GST_LOG ("Setting local transceiver to RECVONLY"); -+ g_object_set (trans_local, "direction", -+ GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY, NULL); -+ -+ GST_LOG ("Waiting for on-negotiation-needed"); -+ test_webrtc_wait_for_state_mask (t, 1 << STATE_NEGOTIATION_NEEDED); -+ -+ const gchar *new_expected_offer_direction[] = { "recvonly" }; -+ VAL_SDP_INIT (new_offer, on_sdp_media_direction, new_expected_offer_direction, -+ NULL); -+ const gchar *new_expected_answer_direction[] = { "inactive" }; -+ VAL_SDP_INIT (new_answer, on_sdp_media_direction, -+ new_expected_answer_direction, NULL); -+ -+ test_validate_sdp (t, &new_offer, &new_answer); -+ -+ g_array_unref (transceivers); -+ -+ /* At this point webrtc2 is the answerer. Check that it also triggers nego -+ * if we change the direction to sendonly */ -+ test_webrtc_reset_negotiation (t); -+ test_webrtc_clear_states (t); -+ -+ GST_LOG ("Setting remote transceiver to SENDONLY"); -+ g_signal_emit_by_name (t->webrtc2, "get-transceivers", &transceivers); -+ fail_unless (transceivers != NULL); -+ fail_unless_equals_int (transceivers->len, 1); -+ -+ trans_remote = g_array_index (transceivers, GstWebRTCRTPTransceiver *, 0); -+ -+ g_object_set (trans_remote, "direction", -+ GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY, NULL); -+ -+ g_array_unref (transceivers); -+ -+ GST_LOG ("Waiting for on-negotiation-needed"); -+ test_webrtc_wait_for_state_mask (t, 1 << STATE_NEGOTIATION_NEEDED); -+ -+ test_webrtc_free (t); -+} -+ -+GST_END_TEST; -+ -+ - static void - offer_remove_last_media (struct test_webrtc *t, GstElement * element, - GstPromise * promise, gpointer user_data) -@@ -6131,6 +6243,7 @@ webrtcbin_suite (void) - 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_renego_transceiver_set_direction); -+ tcase_add_test (tc, test_renego_triggering); - tcase_add_test (tc, test_renego_lose_media_fails); - tcase_add_test (tc, - test_bundle_codec_preferences_rtx_no_duplicate_payloads); --- -2.47.0 - diff --git a/images/wkdev_sdk/jhbuild/patches/0006-webrtc-add-all-SSRC-attributes-getting-CAPS-for-a-PT.patch b/images/wkdev_sdk/jhbuild/patches/0006-webrtc-add-all-SSRC-attributes-getting-CAPS-for-a-PT.patch deleted file mode 100644 index 90cd128..0000000 --- a/images/wkdev_sdk/jhbuild/patches/0006-webrtc-add-all-SSRC-attributes-getting-CAPS-for-a-PT.patch +++ /dev/null @@ -1,144 +0,0 @@ -From 41fa9831893c9ee434840b4d1bf1150ab124f762 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fran=C3=A7ois=20Laignel?= -Date: Thu, 7 Mar 2024 17:36:33 +0100 -Subject: [PATCH 6/8] webrtc: add all SSRC attributes getting CAPS for a PT - -The transport stream only returned the CAPS for the first matching PT entry -from the `ptmap`. Other SSRC with the same PT where not included. For a stream -which bundled multiple audio streams for instance, only the first SSRC was -knowed to the SSRC demux and downstream elements. - -This commit adds all the `ssrc-` attributes from the matching PT entries. - -The RTP jitter buffer can now find the CNAME corresponding its SSRC even if it -was not the first to be registered for a particular PT. - -The RTP PT demux removes `ssrc-*` attributes cooresponding to other SSRCs -before pushing SSRC specific CAPS to downstream elements. - -Part-of: ---- - .../gst-plugins-bad/ext/webrtc/gstwebrtcbin.c | 5 ++-- - .../ext/webrtc/transportstream.c | 30 ++++++++++++++++--- - .../gst/rtpmanager/gstrtpptdemux.c | 28 +++++++++++++++++ - 3 files changed, 57 insertions(+), 6 deletions(-) - -diff --git a/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c b/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c -index 6fb42da6f4..8ac9850a62 100644 ---- a/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c -+++ b/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c -@@ -5080,6 +5080,8 @@ _set_internal_rtpbin_element_props_from_stream (GstWebRTCBin * webrtc, - - GST_LOG_OBJECT (stream, "setting rtx mapping: %s -> %u", apt, rtx_pt[i]); - gst_structure_set (pt_map, apt, G_TYPE_UINT, rtx_pt[i], NULL); -+ -+ gst_caps_unref (rtx_caps); - } - - GST_DEBUG_OBJECT (stream, "setting payload map on %" GST_PTR_FORMAT " : %" -@@ -7586,8 +7588,7 @@ on_rtpbin_request_pt_map (GstElement * rtpbin, guint session_id, guint pt, - if (!stream) - goto unknown_session; - -- if ((ret = transport_stream_get_caps_for_pt (stream, pt))) -- gst_caps_ref (ret); -+ ret = transport_stream_get_caps_for_pt (stream, pt); - - GST_DEBUG_OBJECT (webrtc, "Found caps %" GST_PTR_FORMAT " for pt %d in " - "session %d", ret, pt, session_id); -diff --git a/subprojects/gst-plugins-bad/ext/webrtc/transportstream.c b/subprojects/gst-plugins-bad/ext/webrtc/transportstream.c -index f1811a025c..7462384df0 100644 ---- a/subprojects/gst-plugins-bad/ext/webrtc/transportstream.c -+++ b/subprojects/gst-plugins-bad/ext/webrtc/transportstream.c -@@ -47,15 +47,37 @@ enum - GstCaps * - transport_stream_get_caps_for_pt (TransportStream * stream, guint pt) - { -- guint i, len; -+ GstCaps *ret = NULL; -+ GstStructure *ret_s, *item_s; -+ guint i, len, si, slen; -+ const gchar *field_name; - - len = stream->ptmap->len; - for (i = 0; i < len; i++) { - PtMapItem *item = &g_array_index (stream->ptmap, PtMapItem, i); -- if (item->pt == pt) -- return item->caps; -+ if (item->pt == pt) { -+ if (item->caps) { -+ if (ret == NULL) { -+ ret = gst_caps_copy (item->caps); -+ ret_s = gst_caps_get_structure (ret, 0); -+ } else { -+ /* Append the "ssrc-*" fields for current PT entry to ret */ -+ item_s = gst_caps_get_structure (item->caps, 0); -+ slen = gst_structure_n_fields (item_s); -+ for (si = 0; si < slen; ++si) { -+ field_name = gst_structure_nth_field_name (item_s, si); -+ if (!g_str_has_prefix (field_name, "ssrc-")) -+ continue; -+ -+ gst_structure_set (ret_s, field_name, G_TYPE_STRING, -+ gst_structure_get_string (item_s, field_name), NULL); -+ } -+ } -+ } -+ } - } -- return NULL; -+ -+ return ret; - } - - int -diff --git a/subprojects/gst-plugins-good/gst/rtpmanager/gstrtpptdemux.c b/subprojects/gst-plugins-good/gst/rtpmanager/gstrtpptdemux.c -index 0454d97134..7be4cc8945 100644 ---- a/subprojects/gst-plugins-good/gst/rtpmanager/gstrtpptdemux.c -+++ b/subprojects/gst-plugins-good/gst/rtpmanager/gstrtpptdemux.c -@@ -312,6 +312,29 @@ gst_rtp_pt_demux_finalize (GObject * object) - G_OBJECT_CLASS (parent_class)->finalize (object); - } - -+/* Removes "ssrc-*" attributes matching other SSRCs. */ -+static gboolean -+_filter_ssrc (GQuark field_id, GValue * value, gpointer ssrc) -+{ -+ const gchar *field_name = g_quark_to_string (field_id); -+ -+ if (!g_str_has_prefix (field_name, "ssrc-")) -+ return TRUE; -+ -+ gchar *endptr; -+ guint32 field_ssrc = g_ascii_strtoll (field_name + 5, &endptr, 10); -+ -+ if (!endptr || *endptr != '-') -+ return TRUE; -+ -+ /* Found a valid "ssrc-*" */ -+ if (field_ssrc != *(guint32 *) ssrc) -+ /* Not the expected SSRC => remove this field */ -+ return FALSE; -+ -+ return TRUE; -+} -+ - static GstCaps * - gst_rtp_pt_demux_get_caps (GstRtpPtDemux * rtpdemux, guint pt) - { -@@ -349,7 +372,12 @@ gst_rtp_pt_demux_get_caps (GstRtpPtDemux * rtpdemux, guint pt) - } - - if (caps != NULL) { -+ GstStructure *s; -+ - caps = gst_caps_make_writable (caps); -+ s = gst_caps_get_structure (caps, 0); -+ gst_structure_filter_and_map_in_place (s, _filter_ssrc, &ssrc); -+ - gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL); - if (have_ssrc) - gst_caps_set_simple (caps, "ssrc", G_TYPE_UINT, ssrc, NULL); --- -2.47.0 - diff --git a/images/wkdev_sdk/jhbuild/patches/0007-rtpfunnel-also-fallback-to-pad-default-handling-for-.patch b/images/wkdev_sdk/jhbuild/patches/0007-rtpfunnel-also-fallback-to-pad-default-handling-for-.patch deleted file mode 100644 index 0a69883..0000000 --- a/images/wkdev_sdk/jhbuild/patches/0007-rtpfunnel-also-fallback-to-pad-default-handling-for-.patch +++ /dev/null @@ -1,192 +0,0 @@ -From c94115afb25784e5552df9a40d05fa038e72f3e4 Mon Sep 17 00:00:00 2001 -From: Matthew Waters -Date: Fri, 23 Aug 2024 20:01:32 +1000 -Subject: [PATCH 7/8] rtpfunnel: also fallback to pad default handling for - unknown ssrcs - -If two (or more) rtpfunnel elements are cascaded, then only one will -realistically have information on the particular ssrc that is in use for a -particular input stream. As such, any key unit requests may never reach the -corresponding encoder. - -This has been discovered by combining simulcast and BUNDLE with webrtcbin. -simulcast uses one rtpfunnel, and BUNDLE uses another rtpfunnel. - -Part-of: ---- - .../docs/gst_plugins_cache.json | 12 +++++++ - .../gst/rtpmanager/gstrtpfunnel.c | 34 +++++++++++++++++-- - .../tests/check/elements/rtpfunnel.c | 18 +++++++--- - 3 files changed, 58 insertions(+), 6 deletions(-) - -diff --git a/subprojects/gst-plugins-good/docs/gst_plugins_cache.json b/subprojects/gst-plugins-good/docs/gst_plugins_cache.json -index 4629e86836..d05e5c054b 100644 ---- a/subprojects/gst-plugins-good/docs/gst_plugins_cache.json -+++ b/subprojects/gst-plugins-good/docs/gst_plugins_cache.json -@@ -18376,6 +18376,18 @@ - "readable": true, - "type": "gint", - "writable": true -+ }, -+ "forward-unknown-ssrc": { -+ "blurb": "Whether to forward events or queries that reference unknown SSRCs", -+ "conditionally-available": false, -+ "construct": false, -+ "construct-only": false, -+ "controllable": false, -+ "default": "false", -+ "mutable": "null", -+ "readable": true, -+ "type": "gboolean", -+ "writable": true - } - }, - "rank": "none" -diff --git a/subprojects/gst-plugins-good/gst/rtpmanager/gstrtpfunnel.c b/subprojects/gst-plugins-good/gst/rtpmanager/gstrtpfunnel.c -index 8de1ae8918..ee819676ec 100644 ---- a/subprojects/gst-plugins-good/gst/rtpmanager/gstrtpfunnel.c -+++ b/subprojects/gst-plugins-good/gst/rtpmanager/gstrtpfunnel.c -@@ -109,9 +109,11 @@ enum - { - PROP_0, - PROP_COMMON_TS_OFFSET, -+ PROP_FORWARD_UNKNOWN_SSRC, - }; - - #define DEFAULT_COMMON_TS_OFFSET -1 -+#define DEFAULT_FORWARD_UNKNOWN_SSRC FALSE - - struct _GstRtpFunnelClass - { -@@ -136,6 +138,7 @@ struct _GstRtpFunnel - - /* properties */ - gint common_ts_offset; -+ gboolean forward_unknown_ssrcs; - }; - - #define RTP_CAPS "application/x-rtp" -@@ -536,9 +539,10 @@ gst_rtp_funnel_src_event (GstPad * pad, GstObject * parent, GstEvent * event) - GstPad *fpad; - guint ssrc; - if (s && gst_structure_get_uint (s, "ssrc", &ssrc)) { -- handled = TRUE; -+ gboolean forward_unknown = FALSE; - - GST_OBJECT_LOCK (funnel); -+ forward_unknown = funnel->forward_unknown_ssrcs; - fpad = g_hash_table_lookup (funnel->ssrc_to_pad, GUINT_TO_POINTER (ssrc)); - if (fpad) - gst_object_ref (fpad); -@@ -549,8 +553,10 @@ gst_rtp_funnel_src_event (GstPad * pad, GstObject * parent, GstEvent * event) - event, fpad); - ret = gst_pad_push_event (fpad, event); - gst_object_unref (fpad); -- } else { -+ handled = TRUE; -+ } else if (!forward_unknown) { - gst_event_unref (event); -+ handled = TRUE; - } - } - } -@@ -607,6 +613,11 @@ gst_rtp_funnel_set_property (GObject * object, guint prop_id, - case PROP_COMMON_TS_OFFSET: - funnel->common_ts_offset = g_value_get_int (value); - break; -+ case PROP_FORWARD_UNKNOWN_SSRC: -+ GST_OBJECT_LOCK (funnel); -+ funnel->forward_unknown_ssrcs = g_value_get_boolean (value); -+ GST_OBJECT_UNLOCK (funnel); -+ break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; -@@ -623,6 +634,11 @@ gst_rtp_funnel_get_property (GObject * object, guint prop_id, GValue * value, - case PROP_COMMON_TS_OFFSET: - g_value_set_int (value, funnel->common_ts_offset); - break; -+ case PROP_FORWARD_UNKNOWN_SSRC: -+ GST_OBJECT_LOCK (funnel); -+ g_value_set_boolean (value, funnel->forward_unknown_ssrcs); -+ GST_OBJECT_UNLOCK (funnel); -+ break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; -@@ -717,6 +733,19 @@ gst_rtp_funnel_class_init (GstRtpFunnelClass * klass) - -1, G_MAXINT32, DEFAULT_COMMON_TS_OFFSET, - G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - -+ /** -+ * rtpfunnel:forward-unknown-ssrc: -+ * -+ * Whether to forward events or queries that reference unknown SSRCs. -+ * -+ * Since: 1.26 -+ */ -+ g_object_class_install_property (gobject_class, PROP_FORWARD_UNKNOWN_SSRC, -+ g_param_spec_boolean ("forward-unknown-ssrc", "Forward Unknown SSRC", -+ "Whether to forward events or queries that reference unknown SSRCs", -+ DEFAULT_FORWARD_UNKNOWN_SSRC, -+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -+ - GST_DEBUG_CATEGORY_INIT (gst_rtp_funnel_debug, - "gstrtpfunnel", 0, "funnel element"); - } -@@ -734,4 +763,5 @@ gst_rtp_funnel_init (GstRtpFunnel * funnel) - funnel->srccaps = gst_caps_new_empty_simple (RTP_CAPS); - funnel->ssrc_to_pad = g_hash_table_new (NULL, NULL); - funnel->current_pad = NULL; -+ funnel->forward_unknown_ssrcs = DEFAULT_FORWARD_UNKNOWN_SSRC; - } -diff --git a/subprojects/gst-plugins-good/tests/check/elements/rtpfunnel.c b/subprojects/gst-plugins-good/tests/check/elements/rtpfunnel.c -index a7da56ad00..e755ea8500 100644 ---- a/subprojects/gst-plugins-good/tests/check/elements/rtpfunnel.c -+++ b/subprojects/gst-plugins-good/tests/check/elements/rtpfunnel.c -@@ -55,7 +55,7 @@ GST_START_TEST (rtpfunnel_ssrc_demuxing) - fail_unless_equals_int (2, gst_harness_upstream_events_received (h0)); - fail_unless_equals_int (2, gst_harness_upstream_events_received (h1)); - -- /* unknown ssrc, we drop it */ -+ /* unknown ssrc, we drop it by default */ - gst_harness_push_upstream_event (h, - gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, - gst_structure_new ("GstForceKeyUnit", -@@ -63,12 +63,22 @@ GST_START_TEST (rtpfunnel_ssrc_demuxing) - fail_unless_equals_int (2, gst_harness_upstream_events_received (h0)); - fail_unless_equals_int (2, gst_harness_upstream_events_received (h1)); - -- /* no ssrc, we send to all */ -+ /* unknown ssrc, we forward if property says to */ -+ g_object_set (h->element, "forward-unknown-ssrc", TRUE, NULL); - gst_harness_push_upstream_event (h, - gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, -- gst_structure_new_empty ("GstForceKeyUnit"))); -+ gst_structure_new ("GstForceKeyUnit", -+ "ssrc", G_TYPE_UINT, 666, NULL))); - fail_unless_equals_int (3, gst_harness_upstream_events_received (h0)); - fail_unless_equals_int (3, gst_harness_upstream_events_received (h1)); -+ g_object_set (h->element, "forward-unknown-ssrc", FALSE, NULL); -+ -+ /* no ssrc, we send to all */ -+ gst_harness_push_upstream_event (h, -+ gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, -+ gst_structure_new_empty ("GstForceKeyUnit"))); -+ fail_unless_equals_int (4, gst_harness_upstream_events_received (h0)); -+ fail_unless_equals_int (4, gst_harness_upstream_events_received (h1)); - - /* remove pad 0, and send an event referencing the now dead ssrc */ - gst_harness_teardown (h0); -@@ -76,7 +86,7 @@ GST_START_TEST (rtpfunnel_ssrc_demuxing) - gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, - gst_structure_new ("GstForceKeyUnit", - "ssrc", G_TYPE_UINT, 123, NULL))); -- fail_unless_equals_int (3, gst_harness_upstream_events_received (h1)); -+ fail_unless_equals_int (4, gst_harness_upstream_events_received (h1)); - - gst_harness_teardown (h); - gst_harness_teardown (h1); --- -2.47.0 - diff --git a/images/wkdev_sdk/jhbuild/patches/0008-webrtcbin-enable-forward-unknown-ssrc-on-rtpfunnel.patch b/images/wkdev_sdk/jhbuild/patches/0008-webrtcbin-enable-forward-unknown-ssrc-on-rtpfunnel.patch deleted file mode 100644 index c48a6ee..0000000 --- a/images/wkdev_sdk/jhbuild/patches/0008-webrtcbin-enable-forward-unknown-ssrc-on-rtpfunnel.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 90484041b738b81efeea7df13a00af82b7153f52 Mon Sep 17 00:00:00 2001 -From: Matthew Waters -Date: Mon, 26 Aug 2024 14:46:59 +1000 -Subject: [PATCH 8/8] webrtcbin: enable forward-unknown-ssrc on rtpfunnel - -See also: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7405 - -Part-of: ---- - subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c b/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c -index 8ac9850a62..c911ee5c47 100644 ---- a/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c -+++ b/subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c -@@ -6066,6 +6066,10 @@ _connect_rtpfunnel (GstWebRTCBin * webrtc, guint session_id, GError ** error) - goto done; - - webrtc->rtpfunnel = gst_element_factory_make ("rtpfunnel", NULL); -+ if (g_object_class_find_property (G_OBJECT_GET_CLASS (webrtc->rtpfunnel), -+ "forward-unknown-ssrc") != NULL) { -+ g_object_set (webrtc->rtpfunnel, "forward-unknown-ssrc", TRUE, NULL); -+ } - gst_bin_add (GST_BIN (webrtc), webrtc->rtpfunnel); - gst_element_sync_state_with_parent (webrtc->rtpfunnel); - --- -2.47.0 - diff --git a/images/wkdev_sdk/jhbuild/patches/0009-oggdemux-Fix-racy-decode-error.patch b/images/wkdev_sdk/jhbuild/patches/0009-oggdemux-Fix-racy-decode-error.patch deleted file mode 100644 index 2a4b713..0000000 --- a/images/wkdev_sdk/jhbuild/patches/0009-oggdemux-Fix-racy-decode-error.patch +++ /dev/null @@ -1,128 +0,0 @@ -From dfb287339abe6ede03ec8abac2a12dd665ad4707 Mon Sep 17 00:00:00 2001 -From: Philippe Normand -Date: Thu, 11 Apr 2019 11:24:34 +0100 -Subject: [PATCH] oggdemux: Fix racy decode error - -Sometimes the seek to the end of file to determine the duration would trigger a -reset of the source pads, that would confuse the decoder downstream and trigger -an error. So the proposed fix is to not reset pads when the segment event being -processed is the consequence of a seek performed to determine the duration. - -Fixes #4212 - -Part-of: ---- - .../testsuites/validate.testslist | 8 ----- - .../testsuites/validate_known_issues.py | 33 ------------------- - .../gst-plugins-base/ext/ogg/gstoggdemux.c | 2 +- - 3 files changed, 1 insertion(+), 42 deletions(-) - -diff --git a/subprojects/gst-integration-testsuites/testsuites/validate.testslist b/subprojects/gst-integration-testsuites/testsuites/validate.testslist -index 7f826b76ca..929de93cce 100644 ---- a/subprojects/gst-integration-testsuites/testsuites/validate.testslist -+++ b/subprojects/gst-integration-testsuites/testsuites/validate.testslist -@@ -755,7 +755,6 @@ validate.pushfile.media_check.qtdemux-test-frag-basic_zero_dur_no_mehd_mp4 - ~validate.rtsp2.playback.fast_forward.cm5000_hevc_1080i_colorbars_ts - ~validate.rtsp2.playback.fast_forward.mp3_h264_0_mp4 - ~validate.rtsp2.playback.fast_forward.mp3_h264_1_mp4 --~validate.rtsp2.playback.fast_forward.opus_1_ogg - ~validate.rtsp2.playback.fast_forward.raw_h264_0_mp4 - ~validate.rtsp2.playback.fast_forward.raw_h264_1_mp4 - ~validate.rtsp2.playback.fast_forward.rawaudioS32LE_prores_mov -@@ -765,8 +764,6 @@ validate.pushfile.media_check.qtdemux-test-frag-basic_zero_dur_no_mehd_mp4 - ~validate.rtsp2.playback.fast_forward.samples_multimedia_cx_testsuite_iv31_avi - ~validate.rtsp2.playback.fast_forward.test5_mkv - ~validate.rtsp2.playback.fast_forward.tron_en_ge_aac_h264_ts --~validate.rtsp2.playback.fast_forward.vorbis_theora_0_ogg --~validate.rtsp2.playback.fast_forward.vorbis_theora_1_ogg - ~validate.rtsp2.playback.fast_forward.vorbis_vp8_0_webm - ~validate.rtsp2.playback.fast_forward.vorbis_vp8_1_webm - ~validate.rtsp2.playback.play_15s.1080p_xavc_audio_conforming_accuracy_mxf -@@ -810,7 +807,6 @@ validate.pushfile.media_check.qtdemux-test-frag-basic_zero_dur_no_mehd_mp4 - ~validate.rtsp2.playback.reverse_playback.mp3_h264_0_mp4 - ~validate.rtsp2.playback.reverse_playback.mp3_h264_1_mp4 - ~validate.rtsp2.playback.reverse_playback.numerated_frames_blue_ogv --~validate.rtsp2.playback.reverse_playback.opus_1_ogg - ~validate.rtsp2.playback.reverse_playback.raw_h264_0_mp4 - ~validate.rtsp2.playback.reverse_playback.raw_h264_1_mp4 - ~validate.rtsp2.playback.reverse_playback.raw_video_avi -@@ -818,8 +814,6 @@ validate.pushfile.media_check.qtdemux-test-frag-basic_zero_dur_no_mehd_mp4 - ~validate.rtsp2.playback.reverse_playback.rawaudioS32LE_prores_mov - ~validate.rtsp2.playback.reverse_playback.samples_multimedia_cx_flac_Yesterday_flac - ~validate.rtsp2.playback.reverse_playback.samples_multimedia_cx_testsuite_iv31_avi --~validate.rtsp2.playback.reverse_playback.vorbis_theora_0_ogg --~validate.rtsp2.playback.reverse_playback.vorbis_theora_1_ogg - ~validate.rtsp2.playback.seek_backward.GH1_00094_1920x1280_MTS - ~validate.rtsp2.playback.seek_backward.bowlerhatdancer_sleepytom_SGP_mjpeg_avi - ~validate.rtsp2.playback.seek_backward.cm5000_hevc_1080i_colorbars_ts -@@ -895,10 +889,8 @@ validate.pushfile.media_check.qtdemux-test-frag-basic_zero_dur_no_mehd_mp4 - ~validate.rtsp2.playback.seek_with_stop.cm5000_hevc_1080i_colorbars_ts - ~validate.rtsp2.playback.seek_with_stop.mp3_h264_0_mp4 - ~validate.rtsp2.playback.seek_with_stop.mp3_h264_1_mp4 --~validate.rtsp2.playback.seek_with_stop.numerated_frames_blue_ogv - ~validate.rtsp2.playback.seek_with_stop.op1a-mpeg2-wave_hd_mxf - ~validate.rtsp2.playback.seek_with_stop.op2b-mpeg2-wave_hd_mxf --~validate.rtsp2.playback.seek_with_stop.opus_1_ogg - ~validate.rtsp2.playback.seek_with_stop.raw_h264_0_mp4 - ~validate.rtsp2.playback.seek_with_stop.raw_h264_1_mp4 - ~validate.rtsp2.playback.seek_with_stop.raw_video_avi -diff --git a/subprojects/gst-integration-testsuites/testsuites/validate_known_issues.py b/subprojects/gst-integration-testsuites/testsuites/validate_known_issues.py -index fa634f21ca..a89489e3e1 100644 ---- a/subprojects/gst-integration-testsuites/testsuites/validate_known_issues.py -+++ b/subprojects/gst-integration-testsuites/testsuites/validate_known_issues.py -@@ -49,39 +49,6 @@ KNOWN_ISSUES = { - }, - ] - }, -- "https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/issues/311": { -- "tests": [ -- "validate.http.*.ogg$", -- "validate.http.*.ogv$", -- "validate.rtsp.*.ogg$", -- "validate.rtsp.*.ogv$", -- ], -- "issues": [ -- { -- "detected-on": "playbin", -- "summary": "We got an ERROR message on the bus", -- "details": ".*No valid frames decoded before end of stream.*", -- "level": "critical", -- "sometimes": True, -- }, -- { -- "level": "critical", -- "summary": "We got an ERROR message on the bus", -- "details": ".*Got error: Could not decode stream.*", -- "sometimes": True, -- }, -- { -- "level": "critical", -- "summary": "The program stopped before some actions were executed", -- "sometimes": True, -- }, -- { -- "summary": "The program stopped before some actions were executed", -- "issue-id": "scenario::not-ended", -- "sometimes": True, -- }, -- ] -- }, - "https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/563": { - "tests": [ - "validate.rtsp.playback.seek_backward.bowlerhatdancer_sleepytom_SGP_mjpeg_avi", -diff --git a/subprojects/gst-plugins-base/ext/ogg/gstoggdemux.c b/subprojects/gst-plugins-base/ext/ogg/gstoggdemux.c -index 4e6b370aa6..d97e6975dd 100644 ---- a/subprojects/gst-plugins-base/ext/ogg/gstoggdemux.c -+++ b/subprojects/gst-plugins-base/ext/ogg/gstoggdemux.c -@@ -2487,7 +2487,7 @@ gst_ogg_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) - ogg sync object as we already reset the chain */ - GST_DEBUG_OBJECT (ogg, "No chain, just resetting ogg sync"); - ogg_sync_reset (&ogg->sync); -- } else { -+ } else if (ogg->push_state != PUSH_DURATION) { - /* reset pad push mode seeking state */ - for (i = 0; i < chain->streams->len; i++) { - GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i); --- -2.48.1 - diff --git a/images/wkdev_sdk/jhbuild/webkit-sdk-deps.modules b/images/wkdev_sdk/jhbuild/webkit-sdk-deps.modules index e2a4a84..ed86bea 100644 --- a/images/wkdev_sdk/jhbuild/webkit-sdk-deps.modules +++ b/images/wkdev_sdk/jhbuild/webkit-sdk-deps.modules @@ -109,16 +109,7 @@ - - - - - - - - - + tag="1.26.0"/>