diff --git a/dom/media/CubebUtils.cpp b/dom/media/CubebUtils.cpp index 10d1f1b6756..2e3ab19421b 100644 --- a/dom/media/CubebUtils.cpp +++ b/dom/media/CubebUtils.cpp @@ -104,13 +104,12 @@ void InitPreferredSampleRate() cubeb* GetCubebContextUnlocked() { sMutex.AssertCurrentThreadOwns(); - if (!sCubebContext) { - MOZ_ASSERT(NS_IsMainThread()); - if (cubeb_init(&sCubebContext, "CubebUtils") != CUBEB_OK) { - NS_WARNING("cubeb_init failed"); - } + if (sCubebContext || + cubeb_init(&sCubebContext, "CubebUtils") == CUBEB_OK) { + return sCubebContext; } - return sCubebContext; + NS_WARNING("cubeb_init failed"); + return nullptr; } uint32_t GetCubebLatency() diff --git a/dom/media/MediaDecoder.cpp b/dom/media/MediaDecoder.cpp index 8b03947073c..eafb4ea233f 100644 --- a/dom/media/MediaDecoder.cpp +++ b/dom/media/MediaDecoder.cpp @@ -10,7 +10,6 @@ #include #include "nsIObserver.h" #include "nsTArray.h" -#include "CubebUtils.h" #include "VideoUtils.h" #include "MediaDecoderStateMachine.h" #include "ImageContainer.h" @@ -402,11 +401,6 @@ bool MediaDecoder::Init(MediaDecoderOwner* aOwner) mOwner = aOwner; mVideoFrameContainer = aOwner->GetVideoFrameContainer(); MediaShutdownManager::Instance().Register(this); - // We don't use the cubeb context yet, but need to ensure it is created on - // the main thread. - if (!CubebUtils::GetCubebContext()) { - NS_WARNING("Audio backend initialization failed."); - } return true; } diff --git a/dom/media/webaudio/AudioContext.cpp b/dom/media/webaudio/AudioContext.cpp index fc7f84098c3..8e22a79d464 100644 --- a/dom/media/webaudio/AudioContext.cpp +++ b/dom/media/webaudio/AudioContext.cpp @@ -110,11 +110,6 @@ AudioContext::AudioContext(nsPIDOMWindow* aWindow, // call them after mDestination has been set up. mDestination->CreateAudioChannelAgent(); mDestination->SetIsOnlyNodeForContext(true); - // We don't use the cubeb context yet, but need to ensure it is created on - // the main thread. - if (!aIsOffline && !CubebUtils::GetCubebContext()) { - NS_WARNING("Audio backend initialization failed."); - } } AudioContext::~AudioContext() diff --git a/media/libcubeb/src/cubeb_wasapi.cpp b/media/libcubeb/src/cubeb_wasapi.cpp index 6373a37cac4..540158e30d6 100644 --- a/media/libcubeb/src/cubeb_wasapi.cpp +++ b/media/libcubeb/src/cubeb_wasapi.cpp @@ -144,17 +144,28 @@ private: }; struct auto_com { - auto_com(DWORD dwCoInit = COINIT_MULTITHREADED) { - result = CoInitializeEx(NULL, dwCoInit); + auto_com() { + result = CoInitializeEx(NULL, COINIT_MULTITHREADED); } ~auto_com() { - if (ok()) { + if (result == RPC_E_CHANGED_MODE) { + // This is not an error, COM was not initialized by this function, so it is + // not necessary to uninit it. + LOG("COM already initialized in STA.\n"); + } else if (result == S_FALSE) { + // This is not an error. We are allowed to call CoInitializeEx more than + // once, as long as it is matches by an CoUninitialize call. + // We do that in the dtor which is guaranteed to be called. + LOG("COM already initialized in MTA\n"); + } + if (SUCCEEDED(result)) { CoUninitialize(); } } bool ok() { - return SUCCEEDED(result); + return result == RPC_E_CHANGED_MODE || SUCCEEDED(result); } +private: HRESULT result; }; @@ -481,7 +492,6 @@ wasapi_stream_render_loop(LPVOID stream) auto_com com; if (!com.ok()) { LOG("COM initialization failed on render_loop thread.\n"); - stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR); return 0; } @@ -678,58 +688,28 @@ HRESULT get_default_endpoint(IMMDevice ** device) return ERROR_SUCCESS; } - -owned_critical_section g_first_init_lock; -bool g_first_init = false; } // namespace anonymous extern "C" { int wasapi_init(cubeb ** context, char const * context_name) { - auto_lock lock(&g_first_init_lock); - if (!g_first_init) { - // Per the MSDN documentation for IAudioClient, the first use *must* be made from an STA thread. - auto_com com(COINIT_APARTMENTTHREADED); - if (FAILED(com.result)) { - return CUBEB_ERROR; - } - - /* We don't use the device yet, but need to make sure we can initialize one - so that this backend is not incorrectly enabled on platforms that don't - support WASAPI. */ - IMMDevice * device; - HRESULT hr = get_default_endpoint(&device); - if (FAILED(hr)) { - LOG("Could not get device: %x\n", hr); - return CUBEB_ERROR; - } - IAudioClient * client; - hr = device->Activate(__uuidof(IAudioClient), - CLSCTX_INPROC_SERVER, - NULL, (void **)&client); - if (SUCCEEDED(hr)) { - WAVEFORMATEX * mix_format; - hr = client->GetMixFormat(&mix_format); - if (SUCCEEDED(hr)) { - hr = client->Initialize(AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_EVENTCALLBACK | - AUDCLNT_STREAMFLAGS_NOPERSIST, - ms_to_hns(100), - 0, - mix_format, - NULL); - CoTaskMemFree(mix_format); - g_first_init = true; - } - SafeRelease(client); - } - SafeRelease(device); - if (FAILED(hr)) { - LOG("Could not initialize IAudioClient: %x\n", hr); - return CUBEB_ERROR; - } + HRESULT hr; + auto_com com; + if (!com.ok()) { + return CUBEB_ERROR; } + /* We don't use the device yet, but need to make sure we can initialize one + so that this backend is not incorrectly enabled on platforms that don't + support WASAPI. */ + IMMDevice * device; + hr = get_default_endpoint(&device); + if (FAILED(hr)) { + LOG("Could not get device.\n"); + return CUBEB_ERROR; + } + SafeRelease(device); + cubeb * ctx = (cubeb *)calloc(1, sizeof(cubeb)); ctx->ops = &wasapi_ops; @@ -804,8 +784,10 @@ wasapi_get_max_channel_count(cubeb * ctx, uint32_t * max_channels) HRESULT hr; IAudioClient * client; WAVEFORMATEX * mix_format; - XASSERT(g_first_init); - auto_com com; /* don't care what COM mode we're in here */ + auto_com com; + if (!com.ok()) { + return CUBEB_ERROR; + } XASSERT(ctx && max_channels); @@ -843,8 +825,10 @@ wasapi_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * laten HRESULT hr; IAudioClient * client; REFERENCE_TIME default_period; - XASSERT(g_first_init); - auto_com com; /* don't care what COM mode we're in here */ + auto_com com; + if (!com.ok()) { + return CUBEB_ERROR; + } IMMDevice * device; hr = get_default_endpoint(&device); @@ -888,8 +872,10 @@ wasapi_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate) HRESULT hr; IAudioClient * client; WAVEFORMATEX * mix_format; - XASSERT(g_first_init); - auto_com com; /* don't care what COM mode we're in here */ + auto_com com; + if (!com.ok()) { + return CUBEB_ERROR; + } IMMDevice * device; hr = get_default_endpoint(&device);