⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 276197 in webkit


Ignore:
Timestamp:
Apr 17, 2021, 4:23:09 AM (5 years ago)
Author:
Philippe Normand
Message:

[GStreamer][MediaStream] fast/mediastream/play-newly-added-audio-track.html is failing since added in r260380
https://bugs.webkit.org/show_bug.cgi?id=210840

Reviewed by Xabier Rodriguez-Calvar.

Source/WebCore:

The test was failing mainly because our mediastreamsrc GStreamer element wasn't creating the
corresponding AudioTrackPrivateMediaStream object. The media player should propagate its
volume/mute/is-playing states to the source element. And also until now our mediastreamsrc
element was handling at most one audio track and at most one audio track, but it turns out
multiple audio tracks can be added actually. So I refactored the element internals
accordingly. The InternalSource is now directly observing the corresponding
RealtimeMediaSource, which simplified some code. Observing is also now suspended/resumed
depending on the element state.

We don't implement a GStreamer AudioMediaStreamTrackRenderer class yet, because actual
rendering is still performed from the WebProcess, so early returns were added in
AudioTrackPrivateMediaStream to handle this case.

  • platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:

(WebCore::MediaPlayerPrivateGStreamer::updateTracks):
(WebCore::MediaPlayerPrivateGStreamer::configureMediaStreamAudioTracks):
(WebCore::MediaPlayerPrivateGStreamer::setVolume):
(WebCore::MediaPlayerPrivateGStreamer::setMuted):
(WebCore::MediaPlayerPrivateGStreamer::updateStates):
(WebCore::MediaPlayerPrivateGStreamer::didEnd):

  • platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h:
  • platform/mediastream/AudioTrackPrivateMediaStream.cpp:

(WebCore::AudioTrackPrivateMediaStream::createRenderer):
(WebCore::AudioTrackPrivateMediaStream::setLogger):
(WebCore::AudioTrackPrivateMediaStream::clear):
(WebCore::AudioTrackPrivateMediaStream::setVolume):
(WebCore::AudioTrackPrivateMediaStream::setAudioOutputDevice):
(WebCore::AudioTrackPrivateMediaStream::volume const):
(WebCore::AudioTrackPrivateMediaStream::audioSamplesAvailable):
(WebCore::AudioTrackPrivateMediaStream::startRenderer):
(WebCore::AudioTrackPrivateMediaStream::stopRenderer):
(WebCore::AudioTrackPrivateMediaStream::createNewRenderer):

  • platform/mediastream/gstreamer/GStreamerMediaStreamSource.cpp:

(mediaStreamTrackPrivateGetTags):
(WebKitMediaStreamObserver::didRemoveTrack):
(webkitMediaStreamSrcConstructed):
(webkitMediaStreamSrcDispose):
(webkitMediaStreamSrcChangeState):
(webkitMediaStreamSrcPostStreamCollection):
(webkitMediaStreamSrcAddPad):
(ProbeData::ProbeData):
(webkitMediaStreamSrcPadProbeCb):
(webkitMediaStreamSrcAddTrack):
(webkitMediaStreamSrcSetStream):
(webkitMediaStreamSrcTrackEnded):
(InternalSource::trackEnded):
(webkitMediaStreamSrcConfigureAudioTracks):

  • platform/mediastream/gstreamer/GStreamerMediaStreamSource.h:

LayoutTests:

Remove flakyness from test and unflag it on GTK.

  • fast/mediastream/play-newly-added-audio-track.html: addTrack might have asynchronous

effects, so it's better to rely on the trackadded event when testing its result.

  • platform/gtk/TestExpectations:
Location:
trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r276194 r276197  
     12021-04-17  Philippe Normand  <pnormand@igalia.com>
     2
     3        [GStreamer][MediaStream] fast/mediastream/play-newly-added-audio-track.html is failing since added in r260380
     4        https://bugs.webkit.org/show_bug.cgi?id=210840
     5
     6        Reviewed by Xabier Rodriguez-Calvar.
     7
     8        Remove flakyness from test and unflag it on GTK.
     9
     10        * fast/mediastream/play-newly-added-audio-track.html: addTrack might have asynchronous
     11        effects, so it's better to rely on the trackadded event when testing its result.
     12        * platform/gtk/TestExpectations:
     13
    1142021-04-16  Diego Pino Garcia  <dpino@igalia.com>
    215
  • trunk/LayoutTests/fast/mediastream/play-newly-added-audio-track.html

    r260380 r276197  
    1212    await video.play();
    1313
     14    video.srcObject.ontrackadded = () => {
     15        if (window.internals)
     16            assert_true(internals.shouldAudioTrackPlay(video.audioTracks[0]));
     17    };
     18
    1419    let stream2 = await navigator.mediaDevices.getUserMedia({ audio : true });
    1520    video.srcObject.addTrack(stream2.getAudioTracks()[0]);
    16 
    17     if (window.internals)
    18         assert_true(internals.shouldAudioTrackPlay(video.audioTracks[0]));
     21    await new Promise(resolve => setTimeout(resolve, 50));
    1922}, "Add an audio track while playing video");
    2023
     
    2528    await video.play();
    2629
     30    video.srcObject.ontrackadded = () => {
     31        if (window.internals)
     32            assert_true(internals.shouldAudioTrackPlay(video.audioTracks[1]));
     33    };
     34
    2735    video.srcObject.addTrack(stream.getAudioTracks()[0]);
    2836    await new Promise(resolve => setTimeout(resolve, 50));
    29     if (window.internals)
    30         assert_true(internals.shouldAudioTrackPlay(video.audioTracks[1]));
    3137}, "Add an audio track while playing audio");
    3238        </script>
  • trunk/LayoutTests/platform/gtk/TestExpectations

    r276134 r276197  
    162162# GStreamer - GTK-Only. Most GStreamer issues probably will go in the glib expectations
    163163webkit.org/b/210528 media/video-supports-fullscreen.html [ Pass ]
    164 webkit.org/b/210840 fast/mediastream/play-newly-added-audio-track.html [ Failure ]
    165164
    166165# Layout
  • trunk/Source/WebCore/ChangeLog

    r276193 r276197  
     12021-04-17  Philippe Normand  <pnormand@igalia.com>
     2
     3        [GStreamer][MediaStream] fast/mediastream/play-newly-added-audio-track.html is failing since added in r260380
     4        https://bugs.webkit.org/show_bug.cgi?id=210840
     5
     6        Reviewed by Xabier Rodriguez-Calvar.
     7
     8        The test was failing mainly because our mediastreamsrc GStreamer element wasn't creating the
     9        corresponding AudioTrackPrivateMediaStream object. The media player should propagate its
     10        volume/mute/is-playing states to the source element. And also until now our mediastreamsrc
     11        element was handling at most one audio track and at most one audio track, but it turns out
     12        multiple audio tracks can be added actually. So I refactored the element internals
     13        accordingly. The InternalSource is now directly observing the corresponding
     14        RealtimeMediaSource, which simplified some code. Observing is also now suspended/resumed
     15        depending on the element state.
     16
     17        We don't implement a GStreamer AudioMediaStreamTrackRenderer class yet, because actual
     18        rendering is still performed from the WebProcess, so early returns were added in
     19        AudioTrackPrivateMediaStream to handle this case.
     20
     21        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
     22        (WebCore::MediaPlayerPrivateGStreamer::updateTracks):
     23        (WebCore::MediaPlayerPrivateGStreamer::configureMediaStreamAudioTracks):
     24        (WebCore::MediaPlayerPrivateGStreamer::setVolume):
     25        (WebCore::MediaPlayerPrivateGStreamer::setMuted):
     26        (WebCore::MediaPlayerPrivateGStreamer::updateStates):
     27        (WebCore::MediaPlayerPrivateGStreamer::didEnd):
     28        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h:
     29        * platform/mediastream/AudioTrackPrivateMediaStream.cpp:
     30        (WebCore::AudioTrackPrivateMediaStream::createRenderer):
     31        (WebCore::AudioTrackPrivateMediaStream::setLogger):
     32        (WebCore::AudioTrackPrivateMediaStream::clear):
     33        (WebCore::AudioTrackPrivateMediaStream::setVolume):
     34        (WebCore::AudioTrackPrivateMediaStream::setAudioOutputDevice):
     35        (WebCore::AudioTrackPrivateMediaStream::volume const):
     36        (WebCore::AudioTrackPrivateMediaStream::audioSamplesAvailable):
     37        (WebCore::AudioTrackPrivateMediaStream::startRenderer):
     38        (WebCore::AudioTrackPrivateMediaStream::stopRenderer):
     39        (WebCore::AudioTrackPrivateMediaStream::createNewRenderer):
     40        * platform/mediastream/gstreamer/GStreamerMediaStreamSource.cpp:
     41        (mediaStreamTrackPrivateGetTags):
     42        (WebKitMediaStreamObserver::didRemoveTrack):
     43        (webkitMediaStreamSrcConstructed):
     44        (webkitMediaStreamSrcDispose):
     45        (webkitMediaStreamSrcChangeState):
     46        (webkitMediaStreamSrcPostStreamCollection):
     47        (webkitMediaStreamSrcAddPad):
     48        (ProbeData::ProbeData):
     49        (webkitMediaStreamSrcPadProbeCb):
     50        (webkitMediaStreamSrcAddTrack):
     51        (webkitMediaStreamSrcSetStream):
     52        (webkitMediaStreamSrcTrackEnded):
     53        (InternalSource::trackEnded):
     54        (webkitMediaStreamSrcConfigureAudioTracks):
     55        * platform/mediastream/gstreamer/GStreamerMediaStreamSource.h:
     56
    1572021-04-16  Brent Fulgham  <bfulgham@apple.com>
    258
  • trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp

    r275821 r276197  
    15121512        GST_DEBUG_OBJECT(pipeline(), "Inspecting %s track with ID %s", gst_stream_type_get_name(type), streamId.utf8().data());
    15131513
    1514         if (type & GST_STREAM_TYPE_AUDIO)
     1514        if (type & GST_STREAM_TYPE_AUDIO) {
    15151515            CREATE_TRACK(audio, Audio);
    1516         else if (type & GST_STREAM_TYPE_VIDEO && m_player->isVideoPlayer())
     1516            configureMediaStreamAudioTracks();
     1517        } else if (type & GST_STREAM_TYPE_VIDEO && m_player->isVideoPlayer())
    15171518            CREATE_TRACK(video, Video);
    15181519        else if (type & GST_STREAM_TYPE_TEXT && !useMediaSource) {
     
    16541655}
    16551656
     1657void MediaPlayerPrivateGStreamer::configureMediaStreamAudioTracks()
     1658{
     1659    if (WEBKIT_IS_MEDIA_STREAM_SRC(m_source.get()))
     1660        webkitMediaStreamSrcConfigureAudioTracks(WEBKIT_MEDIA_STREAM_SRC(m_source.get()), volume(), isMuted(), !m_isPaused);
     1661}
     1662
    16561663void MediaPlayerPrivateGStreamer::setVolume(float volume)
    16571664{
     
    16611668    GST_DEBUG_OBJECT(pipeline(), "Setting volume: %f", volume);
    16621669    gst_stream_volume_set_volume(m_volumeElement.get(), GST_STREAM_VOLUME_FORMAT_LINEAR, static_cast<double>(volume));
     1670    configureMediaStreamAudioTracks();
    16631671}
    16641672
     
    17181726    GST_INFO_OBJECT(pipeline(), "Setting muted state to %s", boolForPrinting(shouldMute));
    17191727    g_object_set(m_volumeElement.get(), "mute", shouldMute, nullptr);
     1728    configureMediaStreamAudioTracks();
    17201729}
    17211730
     
    22592268    MediaPlayer::NetworkState oldNetworkState = m_networkState;
    22602269    MediaPlayer::ReadyState oldReadyState = m_readyState;
     2270    bool oldIsPaused = m_isPaused;
    22612271    GstState pending, state;
    22622272    bool stateReallyChanged = false;
     
    24252435        }
    24262436    }
     2437
     2438    if (oldIsPaused != m_isPaused)
     2439        configureMediaStreamAudioTracks();
    24272440}
    24282441
     
    25602573        changePipelineState(GST_STATE_READY);
    25612574        m_didDownloadFinish = false;
     2575        configureMediaStreamAudioTracks();
    25622576
    25632577#if USE(WPE_VIDEO_PLANE_DISPLAY_DMABUF)
  • trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h

    r275596 r276197  
    459459#endif
    460460
     461    void configureMediaStreamAudioTracks();
     462
    461463    Atomic<bool> m_isPlayerShuttingDown;
    462464    GRefPtr<GstElement> m_textSink;
  • trunk/Source/WebCore/platform/mediastream/AudioTrackPrivateMediaStream.cpp

    r272213 r276197  
    5252{
    5353    auto renderer = AudioMediaStreamTrackRenderer::create();
     54    if (!renderer)
     55        return nullptr;
    5456    renderer->setCrashCallback([stream = makeWeakPtr(stream)] {
    5557        if (stream)
     
    6365{
    6466    TrackPrivateBase::setLogger(logger, identifier);
    65     m_renderer->setLogger(logger, identifier);
     67    if (m_renderer)
     68        m_renderer->setLogger(logger, identifier);
    6669}
    6770#endif
     
    7881
    7982    streamTrack().removeObserver(*this);
    80     m_renderer->clear();
     83    if (m_renderer)
     84        m_renderer->clear();
    8185}
    8286
     
    104108void AudioTrackPrivateMediaStream::setVolume(float volume)
    105109{
    106     m_renderer->setVolume(volume);
     110    if (m_renderer)
     111        m_renderer->setVolume(volume);
    107112    updateRenderer();
    108113}
     
    110115void AudioTrackPrivateMediaStream::setAudioOutputDevice(const String& deviceId)
    111116{
    112     m_renderer->setAudioOutputDevice(deviceId);
     117    if (m_renderer)
     118        m_renderer->setAudioOutputDevice(deviceId);
    113119}
    114120
    115121float AudioTrackPrivateMediaStream::volume() const
    116122{
    117     return m_renderer->volume();
     123    if (m_renderer)
     124        return m_renderer->volume();
     125    return 1;
    118126}
    119127
     
    121129void AudioTrackPrivateMediaStream::audioSamplesAvailable(const MediaTime& sampleTime, const PlatformAudioData& audioData, const AudioStreamDescription& description, size_t sampleCount)
    122130{
    123     m_renderer->pushSamples(sampleTime, audioData, description, sampleCount);
     131    if (m_renderer)
     132        m_renderer->pushSamples(sampleTime, audioData, description, sampleCount);
    124133}
    125134
     
    155164
    156165    m_isPlaying = true;
    157     m_renderer->start();
     166    if (m_renderer)
     167        m_renderer->start();
    158168    m_audioSource->addAudioSampleObserver(*this);
    159169}
     
    167177    m_isPlaying = false;
    168178    m_audioSource->removeAudioSampleObserver(*this);
    169     m_renderer->stop();
     179    if (m_renderer)
     180        m_renderer->stop();
    170181}
    171182
     
    177188    float volume = this->volume();
    178189    m_renderer = createRenderer(*this);
    179     m_renderer->setVolume(volume);
     190    if (m_renderer)
     191        m_renderer->setVolume(volume);
    180192
    181193    if (isPlaying)
  • trunk/Source/WebCore/platform/mediastream/gstreamer/GStreamerMediaStreamSource.cpp

    r275514 r276197  
    2727#if ENABLE(VIDEO) && ENABLE(MEDIA_STREAM) && USE(GSTREAMER)
    2828
    29 #include "AudioTrackPrivate.h"
     29#include "AudioTrackPrivateMediaStream.h"
    3030#include "GStreamerAudioData.h"
    3131#include "GStreamerCommon.h"
    3232#include "MediaSampleGStreamer.h"
    3333#include "MediaStreamPrivate.h"
    34 #include "MediaStreamTrackPrivate.h"
    35 #include "VideoTrackPrivate.h"
     34#include "VideoTrackPrivateMediaStream.h"
    3635
    3736#include <gst/app/gstappsrc.h>
     
    4140using namespace WebCore;
    4241
    43 static void webkitMediaStreamSrcPushVideoSample(WebKitMediaStreamSrc*, GstSample*);
    44 static void webkitMediaStreamSrcPushAudioSample(WebKitMediaStreamSrc*, const GRefPtr<GstSample>&);
    45 static void webkitMediaStreamSrcTrackEnded(WebKitMediaStreamSrc*, MediaStreamTrackPrivate&);
    46 static void webkitMediaStreamSrcRemoveTrackByType(WebKitMediaStreamSrc*, RealtimeMediaSource::Type);
    47 static void webkitMediaStreamSrcRemoveTrackObserver(WebKitMediaStreamSrc*, MediaStreamTrackPrivate&);
    48 static void webkitMediaStreamSrcPostStreamCollection(WebKitMediaStreamSrc*);
    49 static void webkitMediaStreamSrcRemovePad(WebKitMediaStreamSrc*, const char* padName);
    50 
    51 static GstStaticPadTemplate videoSrcTemplate = GST_STATIC_PAD_TEMPLATE("video_src", GST_PAD_SRC, GST_PAD_SOMETIMES,
     42static GstStaticPadTemplate videoSrcTemplate = GST_STATIC_PAD_TEMPLATE("video_src%u", GST_PAD_SRC, GST_PAD_SOMETIMES,
    5243    GST_STATIC_CAPS("video/x-raw;video/x-h264;video/x-vp8"));
    5344
    54 static GstStaticPadTemplate audioSrcTemplate = GST_STATIC_PAD_TEMPLATE("audio_src", GST_PAD_SRC, GST_PAD_SOMETIMES,
     45static GstStaticPadTemplate audioSrcTemplate = GST_STATIC_PAD_TEMPLATE("audio_src%u", GST_PAD_SRC, GST_PAD_SOMETIMES,
    5546    GST_STATIC_CAPS("audio/x-raw(ANY);"));
    5647
     
    5849#define GST_CAT_DEFAULT webkitMediaStreamSrcDebug
    5950
    60 GRefPtr<GstTagList> mediaStreamTrackPrivateGetTags(MediaStreamTrackPrivate* track)
     51GRefPtr<GstTagList> mediaStreamTrackPrivateGetTags(const MediaStreamTrackPrivate* track)
    6152{
    6253    auto tagList = adoptGRef(gst_tag_list_new_empty());
     
    10192}
    10293
    103 class WebKitMediaStreamTrackObserver
    104     : public MediaStreamTrackPrivate::Observer
    105     , public RealtimeMediaSource::AudioSampleObserver
    106     , public RealtimeMediaSource::VideoSampleObserver {
    107     WTF_MAKE_FAST_ALLOCATED;
    108 public:
    109     virtual ~WebKitMediaStreamTrackObserver() { };
    110     WebKitMediaStreamTrackObserver(GstElement* src)
    111         : m_src(src) { }
    112     void trackStarted(MediaStreamTrackPrivate&) final { };
    113 
    114     void trackEnded(MediaStreamTrackPrivate& track) final
    115     {
    116         if (m_src)
    117             webkitMediaStreamSrcTrackEnded(WEBKIT_MEDIA_STREAM_SRC(m_src), track);
    118     }
    119 
    120     void trackEnabledChanged(MediaStreamTrackPrivate& track) final
    121     {
    122         m_enabled = track.enabled();
    123     }
    124 
    125     void trackMutedChanged(MediaStreamTrackPrivate&) final { };
    126     void trackSettingsChanged(MediaStreamTrackPrivate&) final { };
    127     void readyStateChanged(MediaStreamTrackPrivate&) final { };
    128 
    129     void videoSampleAvailable(MediaSample& sample) final
    130     {
    131         if (!m_enabled || !m_src)
    132             return;
    133 
    134         auto* gstSample = static_cast<MediaSampleGStreamer*>(&sample)->platformSample().sample.gstSample;
    135         webkitMediaStreamSrcPushVideoSample(WEBKIT_MEDIA_STREAM_SRC(m_src), gstSample);
    136     }
    137 
    138     void audioSamplesAvailable(const MediaTime&, const PlatformAudioData& audioData, const AudioStreamDescription&, size_t) final
    139     {
    140         if (!m_enabled || !m_src)
    141             return;
    142 
    143         auto data = static_cast<const GStreamerAudioData&>(audioData);
    144         webkitMediaStreamSrcPushAudioSample(WEBKIT_MEDIA_STREAM_SRC(m_src), data.getSample());
    145     }
    146 
    147 private:
    148     GstElement* m_src { nullptr };
    149     bool m_enabled { true };
    150 };
    151 
    15294class WebKitMediaStreamObserver : public MediaStreamPrivate::Observer {
    15395    WTF_MAKE_FAST_ALLOCATED;
     
    167109    {
    168110        if (m_src)
    169             webkitMediaStreamSrcAddTrack(WEBKIT_MEDIA_STREAM_SRC(m_src), &track, false);
    170     }
    171 
    172     void didRemoveTrack(MediaStreamTrackPrivate& track) final
    173     {
    174         if (!m_src)
    175             return;
    176 
    177         webkitMediaStreamSrcRemoveTrackObserver(WEBKIT_MEDIA_STREAM_SRC(m_src), track);
    178         webkitMediaStreamSrcRemoveTrackByType(WEBKIT_MEDIA_STREAM_SRC(m_src), track.type());
    179     }
     111            webkitMediaStreamSrcAddTrack(WEBKIT_MEDIA_STREAM_SRC_CAST(m_src), &track, false);
     112    }
     113
     114    void didRemoveTrack(MediaStreamTrackPrivate&) final;
    180115
    181116private:
     
    183118};
    184119
    185 class InternalSource {
     120class InternalSource final : public MediaStreamTrackPrivate::Observer,
     121    public RealtimeMediaSource::AudioSampleObserver,
     122    public RealtimeMediaSource::VideoSampleObserver {
    186123    WTF_MAKE_FAST_ALLOCATED;
    187124public:
    188     InternalSource(bool isCaptureTrack, RealtimeMediaSource::Type type)
    189         : m_type(type)
    190     {
     125    InternalSource(GstElement* parent, MediaStreamTrackPrivate& track, const String& padName)
     126        : m_parent(parent)
     127        , m_track(track)
     128        , m_padName(padName)
     129    {
     130        if (track.type() == RealtimeMediaSource::Type::Audio)
     131            m_audioTrack = AudioTrackPrivateMediaStream::create(track);
     132        else if (track.type() == RealtimeMediaSource::Type::Video)
     133            m_videoTrack = VideoTrackPrivateMediaStream::create(track);
     134
     135        bool isCaptureTrack = track.isCaptureTrack();
    191136        m_src = gst_element_factory_make("appsrc", nullptr);
    192137        RELEASE_ASSERT_WITH_MESSAGE(GST_IS_APP_SRC(m_src.get()), "GStreamer appsrc element not found. Please make sure to install gst-plugins-base");
     
    202147    }
    203148
    204     ~InternalSource()
    205     {
    206         g_signal_handlers_disconnect_matched(m_src.get(), G_SIGNAL_MATCH_DATA, 0, 0, nullptr, nullptr, this);
    207 
    208         if (auto parent = adoptGRef(gst_object_get_parent(GST_OBJECT_CAST(m_src.get())))) {
    209             GST_STATE_LOCK(GST_ELEMENT_CAST(parent.get()));
    210             gst_element_set_locked_state(m_src.get(), true);
    211             gst_element_set_state(m_src.get(), GST_STATE_NULL);
    212             gst_bin_remove(GST_BIN_CAST(parent.get()), m_src.get());
    213             gst_element_set_locked_state(m_src.get(), false);
    214             GST_STATE_UNLOCK(GST_ELEMENT_CAST(parent.get()));
    215 
    216             const char* padName = m_type == RealtimeMediaSource::Type::Video ? "video_src" : "audio_src";
    217             webkitMediaStreamSrcRemovePad(WEBKIT_MEDIA_STREAM_SRC(parent.get()), padName);
     149    virtual ~InternalSource()
     150    {
     151        stopObserving();
     152
     153        if (m_src)
     154            g_signal_handlers_disconnect_matched(m_src.get(), G_SIGNAL_MATCH_DATA, 0, 0, nullptr, nullptr, this);
     155    }
     156
     157    const MediaStreamTrackPrivate& track() const { return m_track; }
     158    const String& padName() const { return m_padName; }
     159    GstElement* get() const { return m_src.get(); }
     160
     161    void startObserving()
     162    {
     163        if (m_isObserving)
     164            return;
     165
     166        m_track.addObserver(*this);
     167        switch (m_track.type()) {
     168        case RealtimeMediaSource::Type::Audio:
     169            m_track.source().addAudioSampleObserver(*this);
     170            break;
     171        case RealtimeMediaSource::Type::Video:
     172            m_track.source().addVideoSampleObserver(*this);
     173            break;
     174        case RealtimeMediaSource::Type::None:
     175            ASSERT_NOT_REACHED();
    218176        }
    219     }
    220 
    221     GstElement* get() const { return m_src.get(); }
     177        m_isObserving = true;
     178    }
     179
     180    void stopObserving()
     181    {
     182        if (!m_isObserving)
     183            return;
     184
     185        m_isObserving = false;
     186        switch (m_track.type()) {
     187        case RealtimeMediaSource::Type::Audio:
     188            m_track.source().removeAudioSampleObserver(*this);
     189            break;
     190        case RealtimeMediaSource::Type::Video:
     191            m_track.source().removeVideoSampleObserver(*this);
     192            break;
     193        case RealtimeMediaSource::Type::None:
     194            ASSERT_NOT_REACHED();
     195        }
     196        m_track.removeObserver(*this);
     197    }
     198
     199    void configureAudioTrack(float volume, bool isMuted, bool isPlaying)
     200    {
     201        ASSERT(m_track.type() == RealtimeMediaSource::Type::Audio);
     202        m_audioTrack->setVolume(volume);
     203        m_audioTrack->setMuted(isMuted);
     204        m_audioTrack->setEnabled(m_audioTrack->streamTrack().enabled() && !m_audioTrack->streamTrack().muted());
     205        if (isPlaying)
     206            m_audioTrack->play();
     207    }
    222208
    223209    void pushSample(GstSample* sample)
     
    236222        }
    237223
    238         if (m_type == RealtimeMediaSource::Type::Video && drop)
     224        if (m_track.type() == RealtimeMediaSource::Type::Video && drop)
    239225            drop = doCapsHaveType(caps, "video/x-raw") || GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT);
    240226
    241227        if (drop) {
    242228            m_needsDiscont = true;
    243             GST_INFO_OBJECT(m_src.get(), "%s queue full already... not pushing", m_type == RealtimeMediaSource::Type::Video ? "Video" : "Audio");
     229            GST_INFO_OBJECT(m_src.get(), "%s queue full already... not pushing", m_track.type() == RealtimeMediaSource::Type::Video ? "Video" : "Audio");
    244230            return;
    245231        }
     
    253239    }
    254240
     241    void trackStarted(MediaStreamTrackPrivate&) final { };
     242    void trackEnded(MediaStreamTrackPrivate&) final;
     243
     244    void trackEnabledChanged(MediaStreamTrackPrivate& track) final
     245    {
     246        m_enabled = track.enabled();
     247    }
     248
     249    void trackMutedChanged(MediaStreamTrackPrivate&) final { };
     250    void trackSettingsChanged(MediaStreamTrackPrivate&) final { };
     251    void readyStateChanged(MediaStreamTrackPrivate&) final { };
     252
     253    void videoSampleAvailable(MediaSample& sample) final
     254    {
     255        if (!m_enabled || !m_parent)
     256            return;
     257
     258        auto* gstSample = static_cast<MediaSampleGStreamer*>(&sample)->platformSample().sample.gstSample;
     259        pushSample(gstSample);
     260    }
     261
     262    void audioSamplesAvailable(const MediaTime&, const PlatformAudioData& audioData, const AudioStreamDescription&, size_t) final
     263    {
     264        if (!m_enabled || !m_parent)
     265            return;
     266
     267        const auto& data = static_cast<const GStreamerAudioData&>(audioData);
     268        auto sample = data.getSample();
     269        pushSample(sample.get());
     270    }
     271
    255272private:
    256     RealtimeMediaSource::Type m_type { RealtimeMediaSource::Type::None };
     273    GstElement* m_parent { nullptr };
     274    MediaStreamTrackPrivate& m_track;
    257275    GRefPtr<GstElement> m_src;
     276    bool m_enabled { true };
    258277    GstClockTime m_firstBufferPts { GST_CLOCK_TIME_NONE };
    259278    bool m_enoughData { false };
    260279    bool m_needsDiscont { false };
     280    String m_padName;
     281    bool m_isObserving { false };
     282    RefPtr<AudioTrackPrivateMediaStream> m_audioTrack;
     283    RefPtr<VideoTrackPrivateMediaStream> m_videoTrack;
    261284};
    262285
    263286struct _WebKitMediaStreamSrcPrivate {
    264287    CString uri;
    265     Optional<InternalSource> audioSrc;
    266     Optional<InternalSource> videoSrc;
    267     std::unique_ptr<WebKitMediaStreamTrackObserver> mediaStreamTrackObserver;
     288    Vector<std::unique_ptr<InternalSource>> sources;
    268289    std::unique_ptr<WebKitMediaStreamObserver> mediaStreamObserver;
    269290    RefPtr<MediaStreamPrivate> stream;
     
    271292    GUniquePtr<GstFlowCombiner> flowCombiner;
    272293    GRefPtr<GstStreamCollection> streamCollection;
     294    Atomic<unsigned> audioPadCounter;
     295    Atomic<unsigned> videoPadCounter;
    273296};
    274297
     
    279302};
    280303
     304void WebKitMediaStreamObserver::didRemoveTrack(MediaStreamTrackPrivate& track)
     305{
     306    if (!m_src)
     307        return;
     308
     309    auto* element = WEBKIT_MEDIA_STREAM_SRC_CAST(m_src);
     310    element->priv->sources.removeFirstMatching([&](auto& item) {
     311        return item->track().id() == track.id();
     312    });
     313}
     314
    281315static GstURIType webkitMediaStreamSrcUriGetType(GType)
    282316{
     
    292326static char* webkitMediaStreamSrcUriGetUri(GstURIHandler* handler)
    293327{
    294     WebKitMediaStreamSrc* self = WEBKIT_MEDIA_STREAM_SRC(handler);
     328    WebKitMediaStreamSrc* self = WEBKIT_MEDIA_STREAM_SRC_CAST(handler);
    295329    return g_strdup(self->priv->uri.data());
    296330}
     
    298332static gboolean webkitMediaStreamSrcUriSetUri(GstURIHandler* handler, const char* uri, GError**)
    299333{
    300     WebKitMediaStreamSrc* self = WEBKIT_MEDIA_STREAM_SRC(handler);
     334    WebKitMediaStreamSrc* self = WEBKIT_MEDIA_STREAM_SRC_CAST(handler);
    301335    self->priv->uri = CString(uri);
    302336    return TRUE;
     
    346380{
    347381    GST_CALL_PARENT(G_OBJECT_CLASS, constructed, (object));
    348     WebKitMediaStreamSrc* self = WEBKIT_MEDIA_STREAM_SRC(object);
     382    WebKitMediaStreamSrc* self = WEBKIT_MEDIA_STREAM_SRC_CAST(object);
    349383    auto* priv = self->priv;
    350384
    351     priv->mediaStreamTrackObserver = makeUnique<WebKitMediaStreamTrackObserver>(GST_ELEMENT_CAST(self));
    352385    priv->mediaStreamObserver = makeUnique<WebKitMediaStreamObserver>(GST_ELEMENT_CAST(self));
    353386    priv->flowCombiner = GUniquePtr<GstFlowCombiner>(gst_flow_combiner_new());
     
    358391}
    359392
    360 static void webkitMediaStreamSrcRemoveTrackObserver(WebKitMediaStreamSrc* self, MediaStreamTrackPrivate& track)
    361 {
    362     auto* priv = self->priv;
    363     switch (track.type()) {
    364     case RealtimeMediaSource::Type::Video:
    365         track.source().removeVideoSampleObserver(*priv->mediaStreamTrackObserver);
    366         break;
    367     case RealtimeMediaSource::Type::Audio:
    368         track.source().removeAudioSampleObserver(*priv->mediaStreamTrackObserver);
    369         break;
    370     case RealtimeMediaSource::Type::None:
    371         ASSERT_NOT_REACHED();
    372     }
    373     track.removeObserver(*priv->mediaStreamTrackObserver);
    374 }
    375 
    376 static void stopObservingTracks(WebKitMediaStreamSrc* self)
    377 {
    378     GST_OBJECT_LOCK(self);
    379     auto* priv = self->priv;
    380     for (auto& track : priv->tracks)
    381         webkitMediaStreamSrcRemoveTrackObserver(self, *track);
    382     GST_OBJECT_UNLOCK(self);
    383 }
    384 
    385393static void webkitMediaStreamSrcDispose(GObject* object)
    386394{
    387     WebKitMediaStreamSrc* self = WEBKIT_MEDIA_STREAM_SRC(object);
    388 
    389     stopObservingTracks(self);
     395    WebKitMediaStreamSrc* self = WEBKIT_MEDIA_STREAM_SRC_CAST(object);
    390396
    391397    GST_OBJECT_LOCK(self);
     
    403409{
    404410    GST_DEBUG_OBJECT(element, "%s", gst_state_change_get_name(transition));
    405 
    406     if (transition == GST_STATE_CHANGE_PAUSED_TO_READY)
    407         stopObservingTracks(WEBKIT_MEDIA_STREAM_SRC(element));
     411    WebKitMediaStreamSrc* self = WEBKIT_MEDIA_STREAM_SRC_CAST(element);
     412
     413    if (transition == GST_STATE_CHANGE_PAUSED_TO_READY) {
     414        GST_OBJECT_LOCK(self);
     415        for (auto& item : self->priv->sources)
     416            item->stopObserving();
     417        GST_OBJECT_UNLOCK(self);
     418    }
    408419
    409420    GstStateChangeReturn result = GST_ELEMENT_CLASS(webkit_media_stream_src_parent_class)->change_state(element, transition);
    410421
    411     if (transition == GST_STATE_CHANGE_READY_TO_PAUSED)
     422    if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
     423        GST_OBJECT_LOCK(self);
     424        for (auto& item : self->priv->sources)
     425            item->startObserving();
     426        GST_OBJECT_UNLOCK(self);
    412427        result = GST_STATE_CHANGE_NO_PREROLL;
     428    }
    413429
    414430    return result;
     
    437453    GRefPtr<GstElement> element = adoptGRef(GST_ELEMENT_CAST(gst_object_get_parent(parent)));
    438454    GstFlowReturn chainResult = gst_proxy_pad_chain_default(pad, GST_OBJECT_CAST(element.get()), buffer);
    439     auto* self = WEBKIT_MEDIA_STREAM_SRC(element.get());
     455    auto* self = WEBKIT_MEDIA_STREAM_SRC_CAST(element.get());
    440456    GstFlowReturn result = gst_flow_combiner_update_pad_flow(self->priv->flowCombiner.get(), pad, chainResult);
    441457
     
    446462}
    447463
    448 static void webkitMediaStreamSrcAddPad(WebKitMediaStreamSrc* self, GstPad* target, GstStaticPadTemplate* padTemplate, GRefPtr<GstTagList>&& tags, RealtimeMediaSource::Type sourceType)
    449 {
     464static void webkitMediaStreamSrcPostStreamCollection(WebKitMediaStreamSrc* self)
     465{
     466    auto* priv = self->priv;
     467
     468    GST_OBJECT_LOCK(self);
     469    if (priv->stream && (!priv->stream->active() || !priv->stream->hasTracks())) {
     470        GST_OBJECT_UNLOCK(self);
     471        return;
     472    }
     473
     474    auto upstreamId = priv->stream ? priv->stream->id() : createCanonicalUUIDString();
     475    priv->streamCollection = adoptGRef(gst_stream_collection_new(upstreamId.ascii().data()));
     476    for (auto& track : priv->tracks) {
     477        if (!track->isActive())
     478            continue;
     479        gst_stream_collection_add_stream(priv->streamCollection.get(), webkitMediaStreamNew(track.get()));
     480    }
     481
     482    GST_OBJECT_UNLOCK(self);
     483
     484    GST_DEBUG_OBJECT(self, "Posting stream collection");
     485    gst_element_post_message(GST_ELEMENT_CAST(self), gst_message_new_stream_collection(GST_OBJECT_CAST(self), priv->streamCollection.get()));
     486}
     487
     488static void webkitMediaStreamSrcAddPad(WebKitMediaStreamSrc* self, GstPad* target, GstStaticPadTemplate* padTemplate, GRefPtr<GstTagList>&& tags, RealtimeMediaSource::Type sourceType, const String& padName)
     489{
     490    ASSERT(sourceType != RealtimeMediaSource::Type::None);
     491    if (sourceType == RealtimeMediaSource::Type::None)
     492        return;
     493
    450494    GST_DEBUG_OBJECT(self, "%s Ghosting %" GST_PTR_FORMAT, gst_object_get_path_string(GST_OBJECT_CAST(self)), target);
    451495
    452     const char* padName = sourceType == RealtimeMediaSource::Type::Audio ? "audio_src" : "video_src";
    453     auto* ghostPad = webkitGstGhostPadFromStaticTemplate(padTemplate, padName, target);
     496    auto* ghostPad = webkitGstGhostPadFromStaticTemplate(padTemplate, padName.ascii().data(), target);
    454497    gst_pad_set_active(ghostPad, TRUE);
    455498    gst_element_add_pad(GST_ELEMENT_CAST(self), ghostPad);
     
    462505}
    463506
    464 static void webkitMediaStreamSrcRemovePad(WebKitMediaStreamSrc* self, const char* padName)
    465 {
    466     auto pad = adoptGRef(gst_element_get_static_pad(GST_ELEMENT_CAST(self), padName));
    467     if (!pad)
    468         return;
    469 
    470     auto proxyPad = adoptGRef(GST_PAD_CAST(gst_proxy_pad_get_internal(GST_PROXY_PAD(pad.get()))));
    471     if (proxyPad)
    472         gst_flow_combiner_remove_pad(self->priv->flowCombiner.get(), proxyPad.get());
    473 
    474     gst_pad_set_active(pad.get(), FALSE);
    475     gst_element_remove_pad(GST_ELEMENT_CAST(self), pad.get());
    476 }
    477 
    478507struct ProbeData {
    479     ProbeData(GstElement* element, GstStaticPadTemplate* padTemplate, GRefPtr<GstTagList>&& tags, const char* trackId, RealtimeMediaSource::Type sourceType)
     508    ProbeData(GstElement* element, GstStaticPadTemplate* padTemplate, GRefPtr<GstTagList>&& tags, const char* trackId, RealtimeMediaSource::Type sourceType, const String& padName)
    480509        : element(element)
    481510        , padTemplate(padTemplate)
     
    483512        , trackId(g_strdup(trackId))
    484513        , sourceType(sourceType)
     514        , padName(padName)
    485515    {
    486516    }
     
    491521    GUniquePtr<char> trackId;
    492522    RealtimeMediaSource::Type sourceType;
     523    String padName;
    493524};
    494525
     
    496527{
    497528    GstEvent* event = GST_PAD_PROBE_INFO_EVENT(info);
    498     WebKitMediaStreamSrc* self = WEBKIT_MEDIA_STREAM_SRC(data->element.get());
     529    WebKitMediaStreamSrc* self = WEBKIT_MEDIA_STREAM_SRC_CAST(data->element.get());
    499530
    500531    GST_DEBUG_OBJECT(self, "Event %" GST_PTR_FORMAT, event);
     
    512543        gst_pad_push_event(pad, streamStart);
    513544
    514         webkitMediaStreamSrcAddPad(self, pad, data->padTemplate, WTFMove(data->tags), data->sourceType);
     545        webkitMediaStreamSrcAddPad(self, pad, data->padTemplate, WTFMove(data->tags), data->sourceType, data->padName);
    515546        callOnMainThreadAndWait([element = data->element] {
    516             webkitMediaStreamSrcPostStreamCollection(WEBKIT_MEDIA_STREAM_SRC(element.get()));
     547            webkitMediaStreamSrcPostStreamCollection(WEBKIT_MEDIA_STREAM_SRC_CAST(element.get()));
    517548        });
    518549        return GST_PAD_PROBE_REMOVE;
     
    525556}
    526557
    527 static void webkitMediaStreamSrcSetupSrc(WebKitMediaStreamSrc* self, MediaStreamTrackPrivate* track, GstElement* element, GstStaticPadTemplate* padTemplate, bool onlyTrack)
     558void webkitMediaStreamSrcAddTrack(WebKitMediaStreamSrc* self, MediaStreamTrackPrivate* track, bool onlyTrack)
    528559{
    529560    const char* sourceType = "unknown";
    530     switch (track->source().type()) {
    531     case RealtimeMediaSource::Type::Audio:
     561    unsigned counter = 0;
     562    GstStaticPadTemplate* padTemplate = nullptr;
     563    if (track->type() == RealtimeMediaSource::Type::Audio) {
     564        padTemplate = &audioSrcTemplate;
    532565        sourceType = "audio";
    533         break;
    534     case RealtimeMediaSource::Type::Video:
     566        counter = self->priv->audioPadCounter.exchangeAdd(1);
     567    } else if (track->type() == RealtimeMediaSource::Type::Video) {
     568        padTemplate = &videoSrcTemplate;
    535569        sourceType = "video";
    536         break;
    537     case RealtimeMediaSource::Type::None:
    538         ASSERT_NOT_REACHED();
    539     }
     570        counter = self->priv->videoPadCounter.exchangeAdd(1);
     571    } else {
     572        GST_WARNING_OBJECT(self, "Unsupported track type: %d", static_cast<int>(track->type()));
     573        return;
     574    }
     575
     576    StringBuilder padName;
     577    padName.append(sourceType);
     578    padName.append("_src");
     579    padName.append(counter);
    540580
    541581    GST_DEBUG_OBJECT(self, "Setup %s source for track %s, only track: %s", sourceType, track->id().utf8().data(), boolForPrinting(onlyTrack));
     582
     583    auto source = makeUnique<InternalSource>(GST_ELEMENT_CAST(self), *track, padName.toString());
     584    auto* element = source->get();
    542585    gst_bin_add(GST_BIN_CAST(self), element);
    543586
     
    545588    auto tags = mediaStreamTrackPrivateGetTags(track);
    546589    if (!onlyTrack) {
    547         auto* data = new ProbeData(GST_ELEMENT_CAST(self), padTemplate, WTFMove(tags), track->id().utf8().data(), track->source().type());
     590        auto* data = new ProbeData(GST_ELEMENT_CAST(self), padTemplate, WTFMove(tags), track->id().utf8().data(), track->source().type(), source->padName());
    548591        gst_pad_add_probe(pad.get(), GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, reinterpret_cast<GstPadProbeCallback>(webkitMediaStreamSrcPadProbeCb), data, [](gpointer data) {
    549592            delete reinterpret_cast<ProbeData*>(data);
     
    551594    } else {
    552595        gst_pad_set_active(pad.get(), TRUE);
    553         webkitMediaStreamSrcAddPad(self, pad.get(), padTemplate, WTFMove(tags), track->source().type());
    554     }
    555 
    556     auto* priv = self->priv;
    557     track->addObserver(*priv->mediaStreamTrackObserver);
    558     switch (track->type()) {
    559     case RealtimeMediaSource::Type::Audio:
    560         track->source().addAudioSampleObserver(*priv->mediaStreamTrackObserver);
    561         break;
    562     case RealtimeMediaSource::Type::Video:
    563         track->source().addVideoSampleObserver(*priv->mediaStreamTrackObserver);
    564         break;
    565     case RealtimeMediaSource::Type::None:
    566         ASSERT_NOT_REACHED();
    567     }
    568 
     596        webkitMediaStreamSrcAddPad(self, pad.get(), padTemplate, WTFMove(tags), track->source().type(), source->padName());
     597    }
    569598    gst_element_sync_state_with_parent(element);
    570 }
    571 
    572 static void webkitMediaStreamSrcPostStreamCollection(WebKitMediaStreamSrc* self)
    573 {
    574     auto* priv = self->priv;
    575 
    576     GST_OBJECT_LOCK(self);
    577     if (priv->stream && (!priv->stream->active() || !priv->stream->hasTracks())) {
    578         GST_OBJECT_UNLOCK(self);
    579         return;
    580     }
    581 
    582     auto upstreamId = priv->stream ? priv->stream->id() : createCanonicalUUIDString();
    583     priv->streamCollection = adoptGRef(gst_stream_collection_new(upstreamId.ascii().data()));
    584     for (auto& track : priv->tracks) {
    585         if (!track->isActive())
    586             continue;
    587         gst_stream_collection_add_stream(priv->streamCollection.get(), webkitMediaStreamNew(track.get()));
    588     }
    589 
    590     GST_OBJECT_UNLOCK(self);
    591 
    592     GST_DEBUG_OBJECT(self, "Posting stream collection");
    593     gst_element_post_message(GST_ELEMENT_CAST(self), gst_message_new_stream_collection(GST_OBJECT_CAST(self), priv->streamCollection.get()));
    594 }
    595 
    596 void webkitMediaStreamSrcAddTrack(WebKitMediaStreamSrc* self, MediaStreamTrackPrivate* track, bool onlyTrack)
    597 {
    598     auto* priv = self->priv;
    599     if (track->type() == RealtimeMediaSource::Type::Audio) {
    600         priv->audioSrc.emplace(track->isCaptureTrack(), track->type());
    601         webkitMediaStreamSrcSetupSrc(self, track, priv->audioSrc->get(), &audioSrcTemplate, onlyTrack);
    602     } else if (track->type() == RealtimeMediaSource::Type::Video) {
    603         priv->videoSrc.emplace(track->isCaptureTrack(), track->type());
    604         webkitMediaStreamSrcSetupSrc(self, track, priv->videoSrc->get(), &videoSrcTemplate, onlyTrack);
    605     } else
    606         GST_INFO_OBJECT(self, "Unsupported track type: %d", static_cast<int>(track->type()));
    607 
     599
     600    source->startObserving();
     601    self->priv->sources.append(WTFMove(source));
    608602    self->priv->tracks.append(track);
    609 }
    610 
    611 static void webkitMediaStreamSrcRemoveTrackByType(WebKitMediaStreamSrc* self, RealtimeMediaSource::Type trackType)
    612 {
    613     if (trackType == RealtimeMediaSource::Type::Audio)
    614         self->priv->audioSrc.reset();
    615     else if (trackType == RealtimeMediaSource::Type::Video)
    616         self->priv->videoSrc.reset();
    617     else
    618         GST_INFO_OBJECT(self, "Unsupported track type: %d", static_cast<int>(trackType));
    619603}
    620604
     
    634618    }
    635619    webkitMediaStreamSrcPostStreamCollection(self);
    636     gst_element_no_more_pads(GST_ELEMENT_CAST(self));
    637 }
    638 
    639 static void webkitMediaStreamSrcPushVideoSample(WebKitMediaStreamSrc* self, GstSample* sample)
    640 {
    641     if (self->priv->videoSrc)
    642         self->priv->videoSrc->pushSample(sample);
    643 }
    644 
    645 static void webkitMediaStreamSrcPushAudioSample(WebKitMediaStreamSrc* self, const GRefPtr<GstSample>& sample)
    646 {
    647     if (self->priv->audioSrc)
    648         self->priv->audioSrc->pushSample(sample.get());
    649 }
    650 
    651 static void webkitMediaStreamSrcTrackEnded(WebKitMediaStreamSrc* self, MediaStreamTrackPrivate& track)
     620}
     621
     622static void webkitMediaStreamSrcTrackEnded(WebKitMediaStreamSrc* self, InternalSource& source)
    652623{
    653624    GRefPtr<GstPad> pad;
    654625
     626    auto& track = source.track();
    655627    GST_DEBUG_OBJECT(self, "Track %s ended", track.label().utf8().data());
    656628    GST_OBJECT_LOCK(self);
     
    685657    gst_pad_push_event(pad.get(), gst_event_new_tag(tags.leakRef()));
    686658    gst_pad_push_event(pad.get(), gst_event_new_eos());
     659
     660    GST_STATE_LOCK(GST_ELEMENT_CAST(self));
     661    gst_element_set_locked_state(source.get(), true);
     662    gst_element_set_state(source.get(), GST_STATE_NULL);
     663    gst_bin_remove(GST_BIN_CAST(self), source.get());
     664    gst_element_set_locked_state(source.get(), false);
     665    GST_STATE_UNLOCK(GST_ELEMENT_CAST(self));
     666
     667    auto proxyPad = adoptGRef(GST_PAD_CAST(gst_proxy_pad_get_internal(GST_PROXY_PAD(pad.get()))));
     668    if (proxyPad)
     669        gst_flow_combiner_remove_pad(self->priv->flowCombiner.get(), proxyPad.get());
     670
     671    gst_pad_set_active(pad.get(), FALSE);
     672    gst_element_remove_pad(GST_ELEMENT_CAST(self), pad.get());
     673}
     674
     675void InternalSource::trackEnded(MediaStreamTrackPrivate&)
     676{
     677    if (m_parent)
     678        webkitMediaStreamSrcTrackEnded(WEBKIT_MEDIA_STREAM_SRC_CAST(m_parent), *this);
     679
     680    stopObserving();
     681}
     682
     683void webkitMediaStreamSrcConfigureAudioTracks(WebKitMediaStreamSrc* self, float volume, bool isMuted, bool isPlaying)
     684{
     685    for (auto& source : self->priv->sources) {
     686        if (source->track().type() == RealtimeMediaSource::Type::Audio)
     687            source->configureAudioTrack(volume, isMuted, isPlaying);
     688    }
    687689}
    688690
  • trunk/Source/WebCore/platform/mediastream/gstreamer/GStreamerMediaStreamSource.h

    r275514 r276197  
    3131}
    3232
    33 G_BEGIN_DECLS
    34 
    3533#define WEBKIT_MEDIA_TRACK_TAG_WIDTH "webkit-media-stream-width"
    3634#define WEBKIT_MEDIA_TRACK_TAG_HEIGHT "webkit-media-stream-height"
     
    3937#define WEBKIT_MEDIA_STREAM_SRC(o) (G_TYPE_CHECK_INSTANCE_CAST((o), WEBKIT_TYPE_MEDIA_STREAM_SRC, WebKitMediaStreamSrc))
    4038#define WEBKIT_IS_MEDIA_STREAM_SRC(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), WEBKIT_TYPE_MEDIA_STREAM_SRC))
     39#define WEBKIT_MEDIA_STREAM_SRC_CAST(o) ((WebKitMediaStreamSrc*) o)
     40
    4141#define WEBKIT_TYPE_MEDIA_STREAM_SRC (webkit_media_stream_src_get_type())
    4242GType webkit_media_stream_src_get_type(void);
     
    5555};
    5656
     57GstElement* webkitMediaStreamSrcNew();
    5758void webkitMediaStreamSrcSetStream(WebKitMediaStreamSrc*, WebCore::MediaStreamPrivate*, bool isVideoPlayer);
    5859void webkitMediaStreamSrcAddTrack(WebKitMediaStreamSrc*, WebCore::MediaStreamTrackPrivate*, bool onlyTrack);
    59 GstElement* webkitMediaStreamSrcNew();
    60 
    61 G_END_DECLS
     60void webkitMediaStreamSrcConfigureAudioTracks(WebKitMediaStreamSrc*, float volume, bool isMuted, bool isPlaying);
    6261
    6362#endif // ENABLE(VIDEO) && ENABLE(MEDIA_STREAM) && USE(GSTREAMER)
Note: See TracChangeset for help on using the changeset viewer.