Changeset 271197 in webkit
- Timestamp:
- Jan 6, 2021, 1:56:37 AM (6 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 7 edited
-
ChangeLog (modified) (1 diff)
-
platform/audio/gstreamer/AudioDestinationGStreamer.cpp (modified) (9 diffs)
-
platform/audio/gstreamer/AudioDestinationGStreamer.h (modified) (4 diffs)
-
platform/audio/gstreamer/WebKitWebAudioSourceGStreamer.cpp (modified) (18 diffs)
-
platform/audio/gstreamer/WebKitWebAudioSourceGStreamer.h (modified) (1 diff)
-
platform/graphics/gstreamer/GStreamerCommon.cpp (modified) (2 diffs)
-
platform/graphics/gstreamer/GStreamerCommon.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r271194 r271197 1 2021-01-06 Philippe Normand <pnormand@igalia.com> 2 3 REGRESSION[r270947][GStreamer]: Deadlocks audio rendering 4 https://bugs.webkit.org/show_bug.cgi?id=220112 5 6 Reviewed by Chris Dumez. 7 8 This patch fixes the mentioned regression by making the webaudiosrc element wait on the 9 dispatch condition only if it wasn't done synchronously. Additionally several race 10 conditions are now fixed in the AudioDestination, by ensuring the start and stop completion 11 handlers are invoked only after the corresponding pipeline state has been reached. Also the 12 AudioDestination now correctly notifies its parent node of is-playing changes. 13 14 * platform/audio/gstreamer/AudioDestinationGStreamer.cpp: 15 (WebCore::AudioDestinationGStreamer::AudioDestinationGStreamer): 16 (WebCore::AudioDestinationGStreamer::~AudioDestinationGStreamer): 17 (WebCore::AudioDestinationGStreamer::handleMessage): 18 (WebCore::AudioDestinationGStreamer::start): 19 (WebCore::AudioDestinationGStreamer::startRendering): 20 (WebCore::AudioDestinationGStreamer::stop): 21 (WebCore::AudioDestinationGStreamer::stopRendering): 22 (WebCore::AudioDestinationGStreamer::notifyStartupResult): 23 (WebCore::AudioDestinationGStreamer::notifyStopResult): 24 (WebCore::AudioDestinationGStreamer::notifyIsPlaying): 25 * platform/audio/gstreamer/AudioDestinationGStreamer.h: 26 * platform/audio/gstreamer/WebKitWebAudioSourceGStreamer.cpp: 27 (webkit_web_audio_src_class_init): 28 (webKitWebAudioSrcConstructed): 29 (webKitWebAudioSrcSetProperty): 30 (webKitWebAudioSrcGetProperty): 31 (webKitWebAudioSrcAllocateBuffers): 32 (webKitWebAudioSrcRenderAndPushFrames): 33 (webKitWebAudioSrcRenderIteration): 34 (webKitWebAudioSrcChangeState): 35 (webkitWebAudioSourceSetDispatchToRenderThreadFunction): 36 * platform/audio/gstreamer/WebKitWebAudioSourceGStreamer.h: 37 * platform/graphics/gstreamer/GStreamerCommon.cpp: 38 (WebCore::webkitGstSetElementStateSynchronously): 39 * platform/graphics/gstreamer/GStreamerCommon.h: 40 (WebCore::webkitGstSetElementStateSynchronously): 41 1 42 2021-01-05 Eric Carlson <eric.carlson@apple.com> 2 43 -
trunk/Source/WebCore/platform/audio/gstreamer/AudioDestinationGStreamer.cpp
r270947 r271197 33 33 #include <gst/audio/gstaudiobasesink.h> 34 34 #include <gst/gst.h> 35 #include <wtf/PrintStream.h> 35 36 #include <wtf/glib/GUniquePtr.h> 36 37 #include <wtf/glib/RunLoopSourcePriority.h> 38 #include <wtf/text/StringConcatenateNumbers.h> 37 39 38 40 namespace WebCore { … … 121 123 , m_sampleRate(sampleRate) 122 124 { 123 m_pipeline = gst_pipeline_new("audio-destination"); 124 GRefPtr<GstBus> bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_pipeline.get()))); 125 static Atomic<uint32_t> pipelineId; 126 m_pipeline = gst_pipeline_new(makeString("audio-destination-", pipelineId.exchangeAdd(1)).ascii().data()); 127 auto bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_pipeline.get()))); 125 128 ASSERT(bus); 126 129 gst_bus_add_signal_watch_full(bus.get(), RunLoopSourcePriority::RunLoopDispatcher); 127 130 g_signal_connect(bus.get(), "message", G_CALLBACK(messageCallback), this); 128 131 129 m_src = reinterpret_cast<GstElement*>(g_object_new(WEBKIT_TYPE_WEB_AUDIO_SRC, "rate", sampleRate,130 "bus", m_renderBus.get(), " provider", this, "frames", AudioUtilities::renderQuantumSize, nullptr));132 m_src = GST_ELEMENT_CAST(g_object_new(WEBKIT_TYPE_WEB_AUDIO_SRC, "rate", sampleRate, 133 "bus", m_renderBus.get(), "destination", this, "frames", AudioUtilities::renderQuantumSize, nullptr)); 131 134 132 135 GRefPtr<GstElement> audioSink = createPlatformAudioSink(); … … 166 169 AudioDestinationGStreamer::~AudioDestinationGStreamer() 167 170 { 168 GRefPtr<GstBus> bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_pipeline.get()))); 171 GST_DEBUG_OBJECT(m_pipeline.get(), "Disposing"); 172 auto bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_pipeline.get()))); 169 173 ASSERT(bus); 170 174 g_signal_handlers_disconnect_by_func(bus.get(), reinterpret_cast<gpointer>(messageCallback), this); … … 172 176 173 177 gst_element_set_state(m_pipeline.get(), GST_STATE_NULL); 178 notifyStopResult(true); 174 179 } 175 180 … … 193 198 g_warning("Error: %d, %s. Debug output: %s", error->code, error->message, debug.get()); 194 199 gst_element_set_state(m_pipeline.get(), GST_STATE_NULL); 195 m_isPlaying = false;200 notifyIsPlaying(false); 196 201 break; 197 202 case GST_MESSAGE_STATE_CHANGED: … … 201 206 202 207 GST_INFO_OBJECT(m_pipeline.get(), "State changed (old: %s, new: %s, pending: %s)", 203 gst_element_state_get_name(oldState), 204 gst_element_state_get_name(newState), 205 gst_element_state_get_name(pending)); 208 gst_element_state_get_name(oldState), gst_element_state_get_name(newState), gst_element_state_get_name(pending)); 206 209 207 210 WTF::String dotFileName = makeString(GST_OBJECT_NAME(m_pipeline.get()), '_', 208 gst_element_state_get_name(oldState), '_', 209 gst_element_state_get_name(newState)); 211 gst_element_state_get_name(oldState), '_', gst_element_state_get_name(newState)); 210 212 211 213 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN_CAST(m_pipeline.get()), GST_DEBUG_GRAPH_SHOW_ALL, dotFileName.utf8().data()); … … 213 215 break; 214 216 default: 217 GST_DEBUG_OBJECT(m_pipeline.get(), "Unhandled message: %s", GST_MESSAGE_TYPE_NAME(message)); 215 218 break; 216 219 } … … 220 223 void AudioDestinationGStreamer::start(Function<void(Function<void()>&&)>&& dispatchToRenderThread, CompletionHandler<void(bool)>&& completionHandler) 221 224 { 222 webkitWebAudioSourceSetDispatchToRenderThread Callback(WEBKIT_WEB_AUDIO_SRC(m_src.get()), WTFMove(dispatchToRenderThread));225 webkitWebAudioSourceSetDispatchToRenderThreadFunction(WEBKIT_WEB_AUDIO_SRC(m_src.get()), WTFMove(dispatchToRenderThread)); 223 226 startRendering(WTFMove(completionHandler)); 224 227 } … … 227 230 { 228 231 ASSERT(m_audioSinkAvailable); 229 bool success = false; 230 if (m_audioSinkAvailable) { 231 GST_DEBUG("Starting"); 232 if (gst_element_set_state(m_pipeline.get(), GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { 233 g_warning("Error: Failed to set pipeline to playing"); 234 m_isPlaying = false; 235 } else { 236 m_isPlaying = true; 237 success = true; 238 } 239 } 240 241 callOnMainThread([completionHandler = WTFMove(completionHandler), success]() mutable { 242 completionHandler(success); 232 m_startupCompletionHandler = WTFMove(completionHandler); 233 GST_DEBUG_OBJECT(m_pipeline.get(), "Starting audio rendering, sink %s", m_audioSinkAvailable ? "available" : "not available"); 234 235 if (m_isPlaying) { 236 notifyStartupResult(true); 237 return; 238 } 239 240 if (!m_audioSinkAvailable) { 241 notifyStartupResult(false); 242 return; 243 } 244 245 notifyStartupResult(webkitGstSetElementStateSynchronously(m_pipeline.get(), GST_STATE_PLAYING, [this](GstMessage* message) -> bool { 246 return handleMessage(message); 247 })); 248 } 249 250 void AudioDestinationGStreamer::stop(CompletionHandler<void(bool)>&& completionHandler) 251 { 252 stopRendering(WTFMove(completionHandler)); 253 webkitWebAudioSourceSetDispatchToRenderThreadFunction(WEBKIT_WEB_AUDIO_SRC(m_src.get()), nullptr); 254 } 255 256 void AudioDestinationGStreamer::stopRendering(CompletionHandler<void(bool)>&& completionHandler) 257 { 258 ASSERT(m_audioSinkAvailable); 259 m_stopCompletionHandler = WTFMove(completionHandler); 260 GST_DEBUG_OBJECT(m_pipeline.get(), "Stopping audio rendering, sink %s", m_audioSinkAvailable ? "available" : "not available"); 261 262 if (!m_isPlaying) { 263 GST_DEBUG_OBJECT(m_pipeline.get(), "Already stopped"); 264 notifyStopResult(true); 265 return; 266 } 267 268 if (!m_audioSinkAvailable) { 269 notifyStopResult(false); 270 return; 271 } 272 273 notifyStopResult(webkitGstSetElementStateSynchronously(m_pipeline.get(), GST_STATE_READY, [this](GstMessage* message) -> bool { 274 return handleMessage(message); 275 })); 276 } 277 278 void AudioDestinationGStreamer::notifyStartupResult(bool success) 279 { 280 callOnMainThreadAndWait([this, completionHandler = WTFMove(m_startupCompletionHandler), success]() mutable { 281 GST_DEBUG_OBJECT(m_pipeline.get(), "Has start completion handler: %s", boolForPrinting(!!completionHandler)); 282 if (completionHandler) 283 completionHandler(success); 243 284 }); 244 285 } 245 286 246 void AudioDestinationGStreamer::stop(CompletionHandler<void(bool)>&& completionHandler) 247 { 248 stopRendering(WTFMove(completionHandler)); 249 } 250 251 void AudioDestinationGStreamer::stopRendering(CompletionHandler<void(bool)>&& completionHandler) 252 { 253 ASSERT(m_audioSinkAvailable); 254 bool success = false; 255 if (m_audioSinkAvailable) { 256 GST_DEBUG("Stopping"); 257 gst_element_set_state(m_pipeline.get(), GST_STATE_PAUSED); 258 m_isPlaying = false; 259 success = true; 260 } 261 callOnMainThread([completionHandler = WTFMove(completionHandler), success]() mutable { 262 completionHandler(success); 287 void AudioDestinationGStreamer::notifyStopResult(bool success) 288 { 289 if (success) 290 notifyIsPlaying(false); 291 292 callOnMainThreadAndWait([this, completionHandler = WTFMove(m_stopCompletionHandler), success]() mutable { 293 GST_DEBUG_OBJECT(m_pipeline.get(), "Has stop completion handler: %s", boolForPrinting(!!completionHandler)); 294 if (completionHandler) 295 completionHandler(success); 263 296 }); 264 297 } 265 298 299 void AudioDestinationGStreamer::notifyIsPlaying(bool isPlaying) 300 { 301 if (m_isPlaying == isPlaying) 302 return; 303 304 GST_DEBUG("Is playing: %s", boolForPrinting(isPlaying)); 305 m_isPlaying = isPlaying; 306 if (m_callback) 307 m_callback->isPlayingDidChange(); 308 } 309 266 310 } // namespace WebCore 267 311 -
trunk/Source/WebCore/platform/audio/gstreamer/AudioDestinationGStreamer.h
r270947 r271197 22 22 #include "AudioDestination.h" 23 23 #include "GRefPtrGStreamer.h" 24 #include <wtf/Condition.h> 24 25 #include <wtf/Forward.h> 25 26 typedef struct _GstElement GstElement;27 typedef struct _GstPad GstPad;28 typedef struct _GstMessage GstMessage;29 26 30 27 namespace WebCore { … … 43 40 44 41 gboolean handleMessage(GstMessage*); 42 void notifyIsPlaying(bool); 45 43 46 44 protected: … … 49 47 50 48 private: 49 void notifyStartupResult(bool); 50 void notifyStopResult(bool); 51 51 52 RefPtr<AudioBus> m_renderBus; 52 53 … … 56 57 GRefPtr<GstElement> m_pipeline; 57 58 GRefPtr<GstElement> m_src; 59 CompletionHandler<void(bool)> m_startupCompletionHandler; 60 CompletionHandler<void(bool)> m_stopCompletionHandler; 61 Lock m_setStateLock; 62 Condition m_setStateCondition; 58 63 }; 59 64 -
trunk/Source/WebCore/platform/audio/gstreamer/WebKitWebAudioSourceGStreamer.cpp
r270840 r271197 25 25 26 26 #include "AudioBus.h" 27 #include "AudioDestination .h"27 #include "AudioDestinationGStreamer.h" 28 28 #include "AudioIOCallback.h" 29 29 #include "AudioUtilities.h" … … 60 60 gfloat sampleRate; 61 61 AudioBus* bus; 62 AudioDestination * provider;62 AudioDestinationGStreamer* destination; 63 63 guint framesToPull; 64 64 guint bufferSize; … … 80 80 81 81 bool enableGapBufferSupport; 82 83 Optional<Function<void(Function<void()>&&)>> dispatchToRenderThreadCallback; 84 Lock dispatchMutex; 82 bool hasRenderedAudibleFrame { false }; 83 84 Lock dispatchToRenderThreadLock; 85 Function<void(Function<void()>&&)> dispatchToRenderThreadFunction; 86 87 bool dispatchDone; 88 Lock dispatchLock; 85 89 Condition dispatchCondition; 86 90 … … 106 110 PROP_RATE = 1, 107 111 PROP_BUS, 108 PROP_ PROVIDER,112 PROP_DESTINATION, 109 113 PROP_FRAMES 110 114 }; … … 117 121 static void webKitWebAudioSrcGetProperty(GObject*, guint propertyId, GValue*, GParamSpec*); 118 122 static GstStateChangeReturn webKitWebAudioSrcChangeState(GstElement*, GstStateChange); 119 static void webKitWebAudioSrc Loop(WebKitWebAudioSrc*);123 static void webKitWebAudioSrcRenderIteration(WebKitWebAudioSrc*); 120 124 121 125 static GstCaps* getGStreamerMonoAudioCaps(float sampleRate) … … 186 190 "Bus", flags)); 187 191 188 g_object_class_install_property(objectClass, 189 PROP_PROVIDER, 190 g_param_spec_pointer("provider", "provider", 191 "Provider", flags)); 192 g_object_class_install_property(objectClass, PROP_DESTINATION, g_param_spec_pointer("destination", "destination", 193 "Destination", flags)); 192 194 193 195 g_object_class_install_property(objectClass, … … 204 206 205 207 ASSERT(priv->bus); 206 ASSERT(priv-> provider);208 ASSERT(priv->destination); 207 209 ASSERT(priv->sampleRate); 208 210 209 211 gst_element_add_pad(GST_ELEMENT(src), priv->sourcePad); 210 212 211 priv->task = adoptGRef(gst_task_new(reinterpret_cast<GstTaskFunction>(webKitWebAudioSrc Loop), src, nullptr));213 priv->task = adoptGRef(gst_task_new(reinterpret_cast<GstTaskFunction>(webKitWebAudioSrcRenderIteration), src, nullptr)); 212 214 gst_task_set_lock(priv->task.get(), &priv->mutex); 213 215 … … 261 263 priv->bus = static_cast<AudioBus*>(g_value_get_pointer(value)); 262 264 break; 263 case PROP_ PROVIDER:264 priv-> provider = static_cast<AudioDestination*>(g_value_get_pointer(value));265 case PROP_DESTINATION: 266 priv->destination = static_cast<AudioDestinationGStreamer*>(g_value_get_pointer(value)); 265 267 break; 266 268 case PROP_FRAMES: … … 286 288 g_value_set_pointer(value, priv->bus); 287 289 break; 288 case PROP_ PROVIDER:289 g_value_set_pointer(value, priv-> provider);290 case PROP_DESTINATION: 291 g_value_set_pointer(value, priv->destination); 290 292 break; 291 293 case PROP_FRAMES: … … 298 300 } 299 301 300 static Optional<Vector<GRefPtr<GstBuffer>>> webKitWebAudioSrcAllocateBuffers AndRenderAudio(WebKitWebAudioSrc* src)302 static Optional<Vector<GRefPtr<GstBuffer>>> webKitWebAudioSrcAllocateBuffers(WebKitWebAudioSrc* src) 301 303 { 302 304 WebKitWebAudioSrcPrivate* priv = src->priv; 303 305 304 306 ASSERT(priv->bus); 305 ASSERT(priv-> provider);306 if (!priv-> provider|| !priv->bus) {307 GST_ELEMENT_ERROR(src, CORE, FAILED, ("Internal WebAudioSrc error"), ("Can't start without provideror bus"));307 ASSERT(priv->destination); 308 if (!priv->destination || !priv->bus) { 309 GST_ELEMENT_ERROR(src, CORE, FAILED, ("Internal WebAudioSrc error"), ("Can't start without destination or bus")); 308 310 gst_task_stop(src->priv->task.get()); 309 311 return WTF::nullopt; … … 311 313 312 314 ASSERT(priv->pool); 313 GstClockTime timestamp = gst_util_uint64_scale(priv->numberOfSamples, GST_SECOND, priv->sampleRate);314 priv->numberOfSamples += priv->framesToPull;315 GstClockTime duration = gst_util_uint64_scale(priv->numberOfSamples, GST_SECOND, priv->sampleRate) - timestamp;316 315 317 316 Vector<GRefPtr<GstBuffer>> channelBufferList; … … 330 329 331 330 ASSERT(buffer); 332 GST_BUFFER_TIMESTAMP(buffer.get()) = timestamp;333 GST_BUFFER_DURATION(buffer.get()) = duration;334 331 GstMappedBuffer mappedBuffer(buffer.get(), GST_MAP_READWRITE); 335 332 ASSERT(mappedBuffer); … … 339 336 } 340 337 338 return makeOptional(channelBufferList); 339 } 340 341 static void webKitWebAudioSrcRenderAndPushFrames(GRefPtr<GstElement>&& element, Vector<GRefPtr<GstBuffer>>&& channelBufferList) 342 { 343 auto* src = WEBKIT_WEB_AUDIO_SRC(element.get()); 344 auto* priv = src->priv; 345 346 ASSERT(channelBufferList.size() == priv->sources.size()); 347 348 GstClockTime timestamp = gst_util_uint64_scale(priv->numberOfSamples, GST_SECOND, priv->sampleRate); 349 priv->numberOfSamples += priv->framesToPull; 350 GstClockTime duration = gst_util_uint64_scale(priv->numberOfSamples, GST_SECOND, priv->sampleRate) - timestamp; 351 341 352 AudioIOPosition outputTimestamp; 342 auto clock = adoptGRef(gst_element_get_clock(GST_ELEMENT_CAST(src))); 343 if (clock) { 353 if (auto clock = adoptGRef(gst_element_get_clock(element.get()))) { 344 354 auto clockTime = gst_clock_get_time(clock.get()); 345 355 outputTimestamp.position = Seconds::fromNanoseconds(timestamp); … … 348 358 349 359 // FIXME: Add support for local/live audio input. 350 351 if (src->priv->dispatchToRenderThreadCallback.hasValue()) { 352 LockHolder holder(priv->dispatchMutex); 353 (*priv->dispatchToRenderThreadCallback)([src, outputTimestamp]() mutable { 354 auto* priv = src->priv; 355 priv->provider->callRenderCallback(nullptr, priv->bus, priv->framesToPull, outputTimestamp); 356 priv->dispatchCondition.notifyOne(); 357 }); 358 priv->dispatchCondition.wait(priv->dispatchMutex); 359 } else 360 priv->provider->callRenderCallback(nullptr, priv->bus, priv->framesToPull, outputTimestamp); 361 362 return makeOptional(channelBufferList); 363 } 364 365 static void webKitWebAudioSrcLoop(WebKitWebAudioSrc* src) 366 { 367 WebKitWebAudioSrcPrivate* priv = src->priv; 368 369 Optional<Vector<GRefPtr<GstBuffer>>> channelBufferList = webKitWebAudioSrcAllocateBuffersAndRenderAudio(src); 370 if (!channelBufferList) { 371 gst_task_stop(src->priv->task.get()); 372 return; 373 } 374 375 ASSERT(channelBufferList->size() == priv->sources.size()); 360 priv->destination->callRenderCallback(nullptr, priv->bus, priv->framesToPull, outputTimestamp); 361 362 if (!priv->hasRenderedAudibleFrame && !priv->bus->isSilent()) { 363 priv->destination->notifyIsPlaying(true); 364 priv->hasRenderedAudibleFrame = true; 365 } 376 366 377 367 bool failed = false; 378 368 for (unsigned i = 0; i < priv->sources.size(); ++i) { 379 auto& buffer = channelBufferList.value()[i]; 369 auto& buffer = channelBufferList[i]; 370 GST_BUFFER_TIMESTAMP(buffer.get()) = outputTimestamp.position.nanoseconds(); 371 GST_BUFFER_DURATION(buffer.get()) = duration; 380 372 381 373 if (priv->enableGapBufferSupport && priv->bus->channel(i)->isSilent()) … … 392 384 if (ret < GST_FLOW_EOS || ret == GST_FLOW_NOT_LINKED) 393 385 GST_ELEMENT_ERROR(src, CORE, PAD, ("Internal WebAudioSrc error"), ("Failed to push buffer on %s flow: %s", GST_OBJECT_NAME(appsrc.get()), gst_flow_get_name(ret))); 394 gst_task_stop( src->priv->task.get());386 gst_task_stop(priv->task.get()); 395 387 failed = true; 396 388 } 397 389 } 390 391 { 392 LockHolder lock(priv->dispatchLock); 393 priv->dispatchDone = true; 394 priv->dispatchCondition.notifyOne(); 395 } 396 } 397 398 static void webKitWebAudioSrcRenderIteration(WebKitWebAudioSrc* src) 399 { 400 auto* priv = src->priv; 401 auto channelBufferList = webKitWebAudioSrcAllocateBuffers(src); 402 if (!channelBufferList) { 403 gst_task_stop(priv->task.get()); 404 return; 405 } 406 407 { 408 LockHolder lock(priv->dispatchLock); 409 priv->dispatchDone = false; 410 } 411 412 auto locker = tryHoldLock(priv->dispatchToRenderThreadLock); 413 if (!locker || !priv->dispatchToRenderThreadFunction) 414 return; 415 416 priv->dispatchToRenderThreadFunction([channels = WTFMove(*channelBufferList), protectedThis = GRefPtr<GstElement>(GST_ELEMENT_CAST(src))]() mutable { 417 webKitWebAudioSrcRenderAndPushFrames(WTFMove(protectedThis), WTFMove(channels)); 418 }); 419 420 { 421 LockHolder lock(priv->dispatchLock); 422 if (!priv->dispatchDone) 423 priv->dispatchCondition.wait(priv->dispatchLock); 424 } 398 425 } 399 426 … … 401 428 { 402 429 GstStateChangeReturn returnValue = GST_STATE_CHANGE_SUCCESS; 403 WebKitWebAudioSrc* src = WEBKIT_WEB_AUDIO_SRC(element); 430 auto* src = WEBKIT_WEB_AUDIO_SRC(element); 431 auto* priv = src->priv; 432 433 #if GST_CHECK_VERSION(1, 14, 0) 434 GST_DEBUG_OBJECT(element, "%s", gst_state_change_get_name(transition)); 435 #endif 404 436 405 437 switch (transition) { 406 438 case GST_STATE_CHANGE_NULL_TO_READY: 407 if (! src->priv->interleave) {439 if (!priv->interleave) { 408 440 gst_element_post_message(element, gst_missing_element_message_new(element, "audiointerleave")); 409 441 GST_ELEMENT_ERROR(src, CORE, MISSING_PLUGIN, (nullptr), ("no audiointerleave")); 410 442 return GST_STATE_CHANGE_FAILURE; 411 443 } 412 src->priv->numberOfSamples = 0;444 priv->numberOfSamples = 0; 413 445 break; 414 446 default: … … 424 456 switch (transition) { 425 457 case GST_STATE_CHANGE_READY_TO_PAUSED: { 426 GST_DEBUG_OBJECT(src, "READY->PAUSED"); 427 428 src->priv->pool = gst_buffer_pool_new(); 429 GstStructure* config = gst_buffer_pool_get_config(src->priv->pool.get()); 430 gst_buffer_pool_config_set_params(config, nullptr, src->priv->bufferSize, 0, 0); 431 gst_buffer_pool_set_config(src->priv->pool.get(), config); 432 if (!gst_buffer_pool_set_active(src->priv->pool.get(), TRUE)) 458 priv->pool = gst_buffer_pool_new(); 459 GstStructure* config = gst_buffer_pool_get_config(priv->pool.get()); 460 gst_buffer_pool_config_set_params(config, nullptr, priv->bufferSize, 0, 0); 461 gst_buffer_pool_set_config(priv->pool.get(), config); 462 if (!gst_buffer_pool_set_active(priv->pool.get(), TRUE)) 433 463 returnValue = GST_STATE_CHANGE_FAILURE; 434 else if (!gst_task_start( src->priv->task.get()))464 else if (!gst_task_start(priv->task.get())) 435 465 returnValue = GST_STATE_CHANGE_FAILURE; 436 466 break; 437 467 } 438 468 case GST_STATE_CHANGE_PAUSED_TO_READY: 439 GST_DEBUG_OBJECT(src, "PAUSED->READY"); 440 441 gst_buffer_pool_set_flushing(src->priv->pool.get(), TRUE); 442 if (!gst_task_join(src->priv->task.get())) 469 { 470 LockHolder lock(priv->dispatchLock); 471 priv->dispatchDone = false; 472 priv->dispatchCondition.notifyAll(); 473 } 474 gst_buffer_pool_set_flushing(priv->pool.get(), TRUE); 475 if (!gst_task_join(priv->task.get())) 443 476 returnValue = GST_STATE_CHANGE_FAILURE; 444 gst_buffer_pool_set_active(src->priv->pool.get(), FALSE); 445 src->priv->pool = nullptr; 477 478 gst_buffer_pool_set_active(priv->pool.get(), FALSE); 479 priv->pool = nullptr; 446 480 break; 447 481 default: … … 452 486 } 453 487 454 void webkitWebAudioSourceSetDispatchToRenderThread Callback(WebKitWebAudioSrc* src, Function<void(Function<void()>&&)>&& function)455 { 456 ASSERT(function);457 src->priv->dispatchToRenderThread Callback= WTFMove(function);488 void webkitWebAudioSourceSetDispatchToRenderThreadFunction(WebKitWebAudioSrc* src, Function<void(Function<void()>&&)>&& function) 489 { 490 auto locker = holdLock(src->priv->dispatchToRenderThreadLock); 491 src->priv->dispatchToRenderThreadFunction = WTFMove(function); 458 492 } 459 493 -
trunk/Source/WebCore/platform/audio/gstreamer/WebKitWebAudioSourceGStreamer.h
r268579 r271197 31 31 GType webkit_web_audio_src_get_type(); 32 32 33 void webkitWebAudioSourceSetDispatchToRenderThread Callback(WebKitWebAudioSrc*, Function<void(Function<void()>&&)>&&);33 void webkitWebAudioSourceSetDispatchToRenderThreadFunction(WebKitWebAudioSrc*, Function<void(Function<void()>&&)>&&); 34 34 35 35 #endif // USE(GSTREAMER) -
trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.cpp
r271128 r271197 33 33 #include <gst/gst.h> 34 34 #include <mutex> 35 #include <wtf/Scope.h> 35 36 #include <wtf/glib/GLibUtilities.h> 36 37 #include <wtf/glib/GUniquePtr.h> … … 455 456 } 456 457 458 bool webkitGstSetElementStateSynchronously(GstElement* pipeline, GstState targetState, Function<bool(GstMessage*)>&& messageHandler) 459 { 460 GST_DEBUG_OBJECT(pipeline, "Setting state to %s", gst_element_state_get_name(targetState)); 461 462 GstState currentState; 463 auto result = gst_element_get_state(pipeline, ¤tState, nullptr, 10); 464 if (result == GST_STATE_CHANGE_SUCCESS && currentState >= targetState) { 465 GST_DEBUG_OBJECT(pipeline, "Target state already reached"); 466 return true; 467 } 468 469 auto bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(pipeline))); 470 gst_bus_enable_sync_message_emission(bus.get()); 471 472 auto cleanup = makeScopeExit([bus = GRefPtr<GstBus>(bus), pipeline, targetState] { 473 gst_bus_disable_sync_message_emission(bus.get()); 474 GstState currentState; 475 auto result = gst_element_get_state(pipeline, ¤tState, nullptr, 0); 476 GST_DEBUG_OBJECT(pipeline, "Task finished, result: %s, target state reached: %s", gst_element_state_change_return_get_name(result), boolForPrinting(currentState == targetState)); 477 }); 478 479 result = gst_element_set_state(pipeline, targetState); 480 if (result == GST_STATE_CHANGE_FAILURE) 481 return false; 482 483 if (result == GST_STATE_CHANGE_ASYNC) { 484 while (auto message = adoptGRef(gst_bus_timed_pop_filtered(bus.get(), GST_CLOCK_TIME_NONE, GST_MESSAGE_STATE_CHANGED))) { 485 if (!messageHandler(message.get())) 486 return false; 487 488 result = gst_element_get_state(pipeline, ¤tState, nullptr, 10); 489 if (result == GST_STATE_CHANGE_FAILURE) 490 return false; 491 492 if (currentState == targetState) 493 return true; 494 } 495 } 496 return true; 497 } 498 457 499 } 458 500 -
trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.h
r271128 r271197 295 295 GstElement* createPlatformAudioSink(); 296 296 297 bool webkitGstSetElementStateSynchronously(GstElement*, GstState, Function<bool(GstMessage*)>&& = [](GstMessage*) -> bool { 298 return true; 299 }); 300 297 301 } 298 302
Note:
See TracChangeset
for help on using the changeset viewer.