Changeset 276197 in webkit
- Timestamp:
- Apr 17, 2021, 4:23:09 AM (5 years ago)
- Location:
- trunk
- Files:
-
- 9 edited
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/fast/mediastream/play-newly-added-audio-track.html (modified) (2 diffs)
-
LayoutTests/platform/gtk/TestExpectations (modified) (1 diff)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp (modified) (7 diffs)
-
Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h (modified) (1 diff)
-
Source/WebCore/platform/mediastream/AudioTrackPrivateMediaStream.cpp (modified) (9 diffs)
-
Source/WebCore/platform/mediastream/gstreamer/GStreamerMediaStreamSource.cpp (modified) (28 diffs)
-
Source/WebCore/platform/mediastream/gstreamer/GStreamerMediaStreamSource.h (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r276194 r276197 1 2021-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 1 14 2021-04-16 Diego Pino Garcia <dpino@igalia.com> 2 15 -
trunk/LayoutTests/fast/mediastream/play-newly-added-audio-track.html
r260380 r276197 12 12 await video.play(); 13 13 14 video.srcObject.ontrackadded = () => { 15 if (window.internals) 16 assert_true(internals.shouldAudioTrackPlay(video.audioTracks[0])); 17 }; 18 14 19 let stream2 = await navigator.mediaDevices.getUserMedia({ audio : true }); 15 20 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)); 19 22 }, "Add an audio track while playing video"); 20 23 … … 25 28 await video.play(); 26 29 30 video.srcObject.ontrackadded = () => { 31 if (window.internals) 32 assert_true(internals.shouldAudioTrackPlay(video.audioTracks[1])); 33 }; 34 27 35 video.srcObject.addTrack(stream.getAudioTracks()[0]); 28 36 await new Promise(resolve => setTimeout(resolve, 50)); 29 if (window.internals)30 assert_true(internals.shouldAudioTrackPlay(video.audioTracks[1]));31 37 }, "Add an audio track while playing audio"); 32 38 </script> -
trunk/LayoutTests/platform/gtk/TestExpectations
r276134 r276197 162 162 # GStreamer - GTK-Only. Most GStreamer issues probably will go in the glib expectations 163 163 webkit.org/b/210528 media/video-supports-fullscreen.html [ Pass ] 164 webkit.org/b/210840 fast/mediastream/play-newly-added-audio-track.html [ Failure ]165 164 166 165 # Layout -
trunk/Source/WebCore/ChangeLog
r276193 r276197 1 2021-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 1 57 2021-04-16 Brent Fulgham <bfulgham@apple.com> 2 58 -
trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp
r275821 r276197 1512 1512 GST_DEBUG_OBJECT(pipeline(), "Inspecting %s track with ID %s", gst_stream_type_get_name(type), streamId.utf8().data()); 1513 1513 1514 if (type & GST_STREAM_TYPE_AUDIO) 1514 if (type & GST_STREAM_TYPE_AUDIO) { 1515 1515 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()) 1517 1518 CREATE_TRACK(video, Video); 1518 1519 else if (type & GST_STREAM_TYPE_TEXT && !useMediaSource) { … … 1654 1655 } 1655 1656 1657 void 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 1656 1663 void MediaPlayerPrivateGStreamer::setVolume(float volume) 1657 1664 { … … 1661 1668 GST_DEBUG_OBJECT(pipeline(), "Setting volume: %f", volume); 1662 1669 gst_stream_volume_set_volume(m_volumeElement.get(), GST_STREAM_VOLUME_FORMAT_LINEAR, static_cast<double>(volume)); 1670 configureMediaStreamAudioTracks(); 1663 1671 } 1664 1672 … … 1718 1726 GST_INFO_OBJECT(pipeline(), "Setting muted state to %s", boolForPrinting(shouldMute)); 1719 1727 g_object_set(m_volumeElement.get(), "mute", shouldMute, nullptr); 1728 configureMediaStreamAudioTracks(); 1720 1729 } 1721 1730 … … 2259 2268 MediaPlayer::NetworkState oldNetworkState = m_networkState; 2260 2269 MediaPlayer::ReadyState oldReadyState = m_readyState; 2270 bool oldIsPaused = m_isPaused; 2261 2271 GstState pending, state; 2262 2272 bool stateReallyChanged = false; … … 2425 2435 } 2426 2436 } 2437 2438 if (oldIsPaused != m_isPaused) 2439 configureMediaStreamAudioTracks(); 2427 2440 } 2428 2441 … … 2560 2573 changePipelineState(GST_STATE_READY); 2561 2574 m_didDownloadFinish = false; 2575 configureMediaStreamAudioTracks(); 2562 2576 2563 2577 #if USE(WPE_VIDEO_PLANE_DISPLAY_DMABUF) -
trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h
r275596 r276197 459 459 #endif 460 460 461 void configureMediaStreamAudioTracks(); 462 461 463 Atomic<bool> m_isPlayerShuttingDown; 462 464 GRefPtr<GstElement> m_textSink; -
trunk/Source/WebCore/platform/mediastream/AudioTrackPrivateMediaStream.cpp
r272213 r276197 52 52 { 53 53 auto renderer = AudioMediaStreamTrackRenderer::create(); 54 if (!renderer) 55 return nullptr; 54 56 renderer->setCrashCallback([stream = makeWeakPtr(stream)] { 55 57 if (stream) … … 63 65 { 64 66 TrackPrivateBase::setLogger(logger, identifier); 65 m_renderer->setLogger(logger, identifier); 67 if (m_renderer) 68 m_renderer->setLogger(logger, identifier); 66 69 } 67 70 #endif … … 78 81 79 82 streamTrack().removeObserver(*this); 80 m_renderer->clear(); 83 if (m_renderer) 84 m_renderer->clear(); 81 85 } 82 86 … … 104 108 void AudioTrackPrivateMediaStream::setVolume(float volume) 105 109 { 106 m_renderer->setVolume(volume); 110 if (m_renderer) 111 m_renderer->setVolume(volume); 107 112 updateRenderer(); 108 113 } … … 110 115 void AudioTrackPrivateMediaStream::setAudioOutputDevice(const String& deviceId) 111 116 { 112 m_renderer->setAudioOutputDevice(deviceId); 117 if (m_renderer) 118 m_renderer->setAudioOutputDevice(deviceId); 113 119 } 114 120 115 121 float AudioTrackPrivateMediaStream::volume() const 116 122 { 117 return m_renderer->volume(); 123 if (m_renderer) 124 return m_renderer->volume(); 125 return 1; 118 126 } 119 127 … … 121 129 void AudioTrackPrivateMediaStream::audioSamplesAvailable(const MediaTime& sampleTime, const PlatformAudioData& audioData, const AudioStreamDescription& description, size_t sampleCount) 122 130 { 123 m_renderer->pushSamples(sampleTime, audioData, description, sampleCount); 131 if (m_renderer) 132 m_renderer->pushSamples(sampleTime, audioData, description, sampleCount); 124 133 } 125 134 … … 155 164 156 165 m_isPlaying = true; 157 m_renderer->start(); 166 if (m_renderer) 167 m_renderer->start(); 158 168 m_audioSource->addAudioSampleObserver(*this); 159 169 } … … 167 177 m_isPlaying = false; 168 178 m_audioSource->removeAudioSampleObserver(*this); 169 m_renderer->stop(); 179 if (m_renderer) 180 m_renderer->stop(); 170 181 } 171 182 … … 177 188 float volume = this->volume(); 178 189 m_renderer = createRenderer(*this); 179 m_renderer->setVolume(volume); 190 if (m_renderer) 191 m_renderer->setVolume(volume); 180 192 181 193 if (isPlaying) -
trunk/Source/WebCore/platform/mediastream/gstreamer/GStreamerMediaStreamSource.cpp
r275514 r276197 27 27 #if ENABLE(VIDEO) && ENABLE(MEDIA_STREAM) && USE(GSTREAMER) 28 28 29 #include "AudioTrackPrivate .h"29 #include "AudioTrackPrivateMediaStream.h" 30 30 #include "GStreamerAudioData.h" 31 31 #include "GStreamerCommon.h" 32 32 #include "MediaSampleGStreamer.h" 33 33 #include "MediaStreamPrivate.h" 34 #include "MediaStreamTrackPrivate.h" 35 #include "VideoTrackPrivate.h" 34 #include "VideoTrackPrivateMediaStream.h" 36 35 37 36 #include <gst/app/gstappsrc.h> … … 41 40 using namespace WebCore; 42 41 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, 42 static GstStaticPadTemplate videoSrcTemplate = GST_STATIC_PAD_TEMPLATE("video_src%u", GST_PAD_SRC, GST_PAD_SOMETIMES, 52 43 GST_STATIC_CAPS("video/x-raw;video/x-h264;video/x-vp8")); 53 44 54 static GstStaticPadTemplate audioSrcTemplate = GST_STATIC_PAD_TEMPLATE("audio_src ", GST_PAD_SRC, GST_PAD_SOMETIMES,45 static GstStaticPadTemplate audioSrcTemplate = GST_STATIC_PAD_TEMPLATE("audio_src%u", GST_PAD_SRC, GST_PAD_SOMETIMES, 55 46 GST_STATIC_CAPS("audio/x-raw(ANY);")); 56 47 … … 58 49 #define GST_CAT_DEFAULT webkitMediaStreamSrcDebug 59 50 60 GRefPtr<GstTagList> mediaStreamTrackPrivateGetTags( MediaStreamTrackPrivate* track)51 GRefPtr<GstTagList> mediaStreamTrackPrivateGetTags(const MediaStreamTrackPrivate* track) 61 52 { 62 53 auto tagList = adoptGRef(gst_tag_list_new_empty()); … … 101 92 } 102 93 103 class WebKitMediaStreamTrackObserver104 : public MediaStreamTrackPrivate::Observer105 , public RealtimeMediaSource::AudioSampleObserver106 , 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) final115 {116 if (m_src)117 webkitMediaStreamSrcTrackEnded(WEBKIT_MEDIA_STREAM_SRC(m_src), track);118 }119 120 void trackEnabledChanged(MediaStreamTrackPrivate& track) final121 {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) final130 {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) final139 {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 152 94 class WebKitMediaStreamObserver : public MediaStreamPrivate::Observer { 153 95 WTF_MAKE_FAST_ALLOCATED; … … 167 109 { 168 110 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; 180 115 181 116 private: … … 183 118 }; 184 119 185 class InternalSource { 120 class InternalSource final : public MediaStreamTrackPrivate::Observer, 121 public RealtimeMediaSource::AudioSampleObserver, 122 public RealtimeMediaSource::VideoSampleObserver { 186 123 WTF_MAKE_FAST_ALLOCATED; 187 124 public: 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(); 191 136 m_src = gst_element_factory_make("appsrc", nullptr); 192 137 RELEASE_ASSERT_WITH_MESSAGE(GST_IS_APP_SRC(m_src.get()), "GStreamer appsrc element not found. Please make sure to install gst-plugins-base"); … … 202 147 } 203 148 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(); 218 176 } 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 } 222 208 223 209 void pushSample(GstSample* sample) … … 236 222 } 237 223 238 if (m_t ype== RealtimeMediaSource::Type::Video && drop)224 if (m_track.type() == RealtimeMediaSource::Type::Video && drop) 239 225 drop = doCapsHaveType(caps, "video/x-raw") || GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT); 240 226 241 227 if (drop) { 242 228 m_needsDiscont = true; 243 GST_INFO_OBJECT(m_src.get(), "%s queue full already... not pushing", m_t ype== 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"); 244 230 return; 245 231 } … … 253 239 } 254 240 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 255 272 private: 256 RealtimeMediaSource::Type m_type { RealtimeMediaSource::Type::None }; 273 GstElement* m_parent { nullptr }; 274 MediaStreamTrackPrivate& m_track; 257 275 GRefPtr<GstElement> m_src; 276 bool m_enabled { true }; 258 277 GstClockTime m_firstBufferPts { GST_CLOCK_TIME_NONE }; 259 278 bool m_enoughData { false }; 260 279 bool m_needsDiscont { false }; 280 String m_padName; 281 bool m_isObserving { false }; 282 RefPtr<AudioTrackPrivateMediaStream> m_audioTrack; 283 RefPtr<VideoTrackPrivateMediaStream> m_videoTrack; 261 284 }; 262 285 263 286 struct _WebKitMediaStreamSrcPrivate { 264 287 CString uri; 265 Optional<InternalSource> audioSrc; 266 Optional<InternalSource> videoSrc; 267 std::unique_ptr<WebKitMediaStreamTrackObserver> mediaStreamTrackObserver; 288 Vector<std::unique_ptr<InternalSource>> sources; 268 289 std::unique_ptr<WebKitMediaStreamObserver> mediaStreamObserver; 269 290 RefPtr<MediaStreamPrivate> stream; … … 271 292 GUniquePtr<GstFlowCombiner> flowCombiner; 272 293 GRefPtr<GstStreamCollection> streamCollection; 294 Atomic<unsigned> audioPadCounter; 295 Atomic<unsigned> videoPadCounter; 273 296 }; 274 297 … … 279 302 }; 280 303 304 void 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 281 315 static GstURIType webkitMediaStreamSrcUriGetType(GType) 282 316 { … … 292 326 static char* webkitMediaStreamSrcUriGetUri(GstURIHandler* handler) 293 327 { 294 WebKitMediaStreamSrc* self = WEBKIT_MEDIA_STREAM_SRC (handler);328 WebKitMediaStreamSrc* self = WEBKIT_MEDIA_STREAM_SRC_CAST(handler); 295 329 return g_strdup(self->priv->uri.data()); 296 330 } … … 298 332 static gboolean webkitMediaStreamSrcUriSetUri(GstURIHandler* handler, const char* uri, GError**) 299 333 { 300 WebKitMediaStreamSrc* self = WEBKIT_MEDIA_STREAM_SRC (handler);334 WebKitMediaStreamSrc* self = WEBKIT_MEDIA_STREAM_SRC_CAST(handler); 301 335 self->priv->uri = CString(uri); 302 336 return TRUE; … … 346 380 { 347 381 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); 349 383 auto* priv = self->priv; 350 384 351 priv->mediaStreamTrackObserver = makeUnique<WebKitMediaStreamTrackObserver>(GST_ELEMENT_CAST(self));352 385 priv->mediaStreamObserver = makeUnique<WebKitMediaStreamObserver>(GST_ELEMENT_CAST(self)); 353 386 priv->flowCombiner = GUniquePtr<GstFlowCombiner>(gst_flow_combiner_new()); … … 358 391 } 359 392 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 385 393 static void webkitMediaStreamSrcDispose(GObject* object) 386 394 { 387 WebKitMediaStreamSrc* self = WEBKIT_MEDIA_STREAM_SRC(object); 388 389 stopObservingTracks(self); 395 WebKitMediaStreamSrc* self = WEBKIT_MEDIA_STREAM_SRC_CAST(object); 390 396 391 397 GST_OBJECT_LOCK(self); … … 403 409 { 404 410 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 } 408 419 409 420 GstStateChangeReturn result = GST_ELEMENT_CLASS(webkit_media_stream_src_parent_class)->change_state(element, transition); 410 421 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); 412 427 result = GST_STATE_CHANGE_NO_PREROLL; 428 } 413 429 414 430 return result; … … 437 453 GRefPtr<GstElement> element = adoptGRef(GST_ELEMENT_CAST(gst_object_get_parent(parent))); 438 454 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()); 440 456 GstFlowReturn result = gst_flow_combiner_update_pad_flow(self->priv->flowCombiner.get(), pad, chainResult); 441 457 … … 446 462 } 447 463 448 static void webkitMediaStreamSrcAddPad(WebKitMediaStreamSrc* self, GstPad* target, GstStaticPadTemplate* padTemplate, GRefPtr<GstTagList>&& tags, RealtimeMediaSource::Type sourceType) 449 { 464 static 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 488 static 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 450 494 GST_DEBUG_OBJECT(self, "%s Ghosting %" GST_PTR_FORMAT, gst_object_get_path_string(GST_OBJECT_CAST(self)), target); 451 495 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); 454 497 gst_pad_set_active(ghostPad, TRUE); 455 498 gst_element_add_pad(GST_ELEMENT_CAST(self), ghostPad); … … 462 505 } 463 506 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 478 507 struct 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) 480 509 : element(element) 481 510 , padTemplate(padTemplate) … … 483 512 , trackId(g_strdup(trackId)) 484 513 , sourceType(sourceType) 514 , padName(padName) 485 515 { 486 516 } … … 491 521 GUniquePtr<char> trackId; 492 522 RealtimeMediaSource::Type sourceType; 523 String padName; 493 524 }; 494 525 … … 496 527 { 497 528 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()); 499 530 500 531 GST_DEBUG_OBJECT(self, "Event %" GST_PTR_FORMAT, event); … … 512 543 gst_pad_push_event(pad, streamStart); 513 544 514 webkitMediaStreamSrcAddPad(self, pad, data->padTemplate, WTFMove(data->tags), data->sourceType );545 webkitMediaStreamSrcAddPad(self, pad, data->padTemplate, WTFMove(data->tags), data->sourceType, data->padName); 515 546 callOnMainThreadAndWait([element = data->element] { 516 webkitMediaStreamSrcPostStreamCollection(WEBKIT_MEDIA_STREAM_SRC (element.get()));547 webkitMediaStreamSrcPostStreamCollection(WEBKIT_MEDIA_STREAM_SRC_CAST(element.get())); 517 548 }); 518 549 return GST_PAD_PROBE_REMOVE; … … 525 556 } 526 557 527 static void webkitMediaStreamSrcSetupSrc(WebKitMediaStreamSrc* self, MediaStreamTrackPrivate* track, GstElement* element, GstStaticPadTemplate* padTemplate, bool onlyTrack)558 void webkitMediaStreamSrcAddTrack(WebKitMediaStreamSrc* self, MediaStreamTrackPrivate* track, bool onlyTrack) 528 559 { 529 560 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; 532 565 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; 535 569 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); 540 580 541 581 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(); 542 585 gst_bin_add(GST_BIN_CAST(self), element); 543 586 … … 545 588 auto tags = mediaStreamTrackPrivateGetTags(track); 546 589 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()); 548 591 gst_pad_add_probe(pad.get(), GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, reinterpret_cast<GstPadProbeCallback>(webkitMediaStreamSrcPadProbeCb), data, [](gpointer data) { 549 592 delete reinterpret_cast<ProbeData*>(data); … … 551 594 } else { 552 595 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 } 569 598 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)); 608 602 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 else618 GST_INFO_OBJECT(self, "Unsupported track type: %d", static_cast<int>(trackType));619 603 } 620 604 … … 634 618 } 635 619 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 622 static void webkitMediaStreamSrcTrackEnded(WebKitMediaStreamSrc* self, InternalSource& source) 652 623 { 653 624 GRefPtr<GstPad> pad; 654 625 626 auto& track = source.track(); 655 627 GST_DEBUG_OBJECT(self, "Track %s ended", track.label().utf8().data()); 656 628 GST_OBJECT_LOCK(self); … … 685 657 gst_pad_push_event(pad.get(), gst_event_new_tag(tags.leakRef())); 686 658 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 675 void InternalSource::trackEnded(MediaStreamTrackPrivate&) 676 { 677 if (m_parent) 678 webkitMediaStreamSrcTrackEnded(WEBKIT_MEDIA_STREAM_SRC_CAST(m_parent), *this); 679 680 stopObserving(); 681 } 682 683 void 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 } 687 689 } 688 690 -
trunk/Source/WebCore/platform/mediastream/gstreamer/GStreamerMediaStreamSource.h
r275514 r276197 31 31 } 32 32 33 G_BEGIN_DECLS34 35 33 #define WEBKIT_MEDIA_TRACK_TAG_WIDTH "webkit-media-stream-width" 36 34 #define WEBKIT_MEDIA_TRACK_TAG_HEIGHT "webkit-media-stream-height" … … 39 37 #define WEBKIT_MEDIA_STREAM_SRC(o) (G_TYPE_CHECK_INSTANCE_CAST((o), WEBKIT_TYPE_MEDIA_STREAM_SRC, WebKitMediaStreamSrc)) 40 38 #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 41 41 #define WEBKIT_TYPE_MEDIA_STREAM_SRC (webkit_media_stream_src_get_type()) 42 42 GType webkit_media_stream_src_get_type(void); … … 55 55 }; 56 56 57 GstElement* webkitMediaStreamSrcNew(); 57 58 void webkitMediaStreamSrcSetStream(WebKitMediaStreamSrc*, WebCore::MediaStreamPrivate*, bool isVideoPlayer); 58 59 void webkitMediaStreamSrcAddTrack(WebKitMediaStreamSrc*, WebCore::MediaStreamTrackPrivate*, bool onlyTrack); 59 GstElement* webkitMediaStreamSrcNew(); 60 61 G_END_DECLS 60 void webkitMediaStreamSrcConfigureAudioTracks(WebKitMediaStreamSrc*, float volume, bool isMuted, bool isPlaying); 62 61 63 62 #endif // ENABLE(VIDEO) && ENABLE(MEDIA_STREAM) && USE(GSTREAMER)
Note:
See TracChangeset
for help on using the changeset viewer.