diff --git a/media/libcubeb/README_MOZILLA b/media/libcubeb/README_MOZILLA index c682ea4f7f2e..141b1a0727c5 100644 --- a/media/libcubeb/README_MOZILLA +++ b/media/libcubeb/README_MOZILLA @@ -5,4 +5,4 @@ Makefile.in build files for the Mozilla build system. The cubeb git repository is: git://github.com/kinetiknz/cubeb.git -The git commit ID used was 14d97931da6435d10aa4dcb444896af0314372f4. +The git commit ID used was 66aa55bb3b883381a73ad12d20688b932858be28. diff --git a/media/libcubeb/src/cubeb_audiounit.c b/media/libcubeb/src/cubeb_audiounit.c index 28201d19c8c3..fbe7f9244c0a 100644 --- a/media/libcubeb/src/cubeb_audiounit.c +++ b/media/libcubeb/src/cubeb_audiounit.c @@ -477,7 +477,6 @@ audiounit_stream_init(cubeb * context, cubeb_stream ** stream, char const * stre unsigned int buffer_size, default_buffer_size; OSStatus r; UInt32 size; - AudioDeviceID output_device_id; AudioValueRange latency_range; assert(context); @@ -783,7 +782,6 @@ audiounit_stream_get_latency(cubeb_stream * stm, uint32_t * latency) int audiounit_stream_set_volume(cubeb_stream * stm, float volume) { - AudioDeviceID id; OSStatus r; r = AudioUnitSetParameter(stm->unit, diff --git a/media/libcubeb/src/cubeb_wasapi.cpp b/media/libcubeb/src/cubeb_wasapi.cpp index d769ab1570ed..d40f78019f23 100644 --- a/media/libcubeb/src/cubeb_wasapi.cpp +++ b/media/libcubeb/src/cubeb_wasapi.cpp @@ -34,15 +34,14 @@ // #define LOGGING_ENABLED #ifdef LOGGING_ENABLED -# define LOG(...) do { \ - fprintf(stdout, __VA_ARGS__); \ - fprintf(stdout, "\n"); \ -} while(0); +#define LOG(...) do { \ + fprintf(stderr, __VA_ARGS__); \ + } while(0) #else -# define LOG(...) +#define LOG(...) #endif -#define ARRAY_LENGTH(array_) \ +#define ARRAY_LENGTH(array_) \ (sizeof(array_) / sizeof(array_[0])) namespace { @@ -85,7 +84,6 @@ void SafeRelease(T * ptr) class owned_critical_section { public: - owned_critical_section() #ifdef DEBUG : owner(0) @@ -136,7 +134,7 @@ private: struct auto_lock { auto_lock(owned_critical_section * lock) - :lock(lock) + : lock(lock) { lock->enter(); } @@ -150,7 +148,7 @@ private: struct auto_unlock { auto_unlock(owned_critical_section * lock) - :lock(lock) + : lock(lock) { lock->leave(); } @@ -163,33 +161,29 @@ private: }; struct auto_com { - auto_com() - : need_uninit(false) { - HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); - // This is for information purposes only, in anycase, COM is initialized - // at the end of the constructor. - if (hr == RPC_E_CHANGED_MODE) { - // This is an error, COM was not initialized by this function, so it is + auto_com() { + result = CoInitializeEx(NULL, COINIT_MULTITHREADED); + } + ~auto_com() { + 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."); - } else if (hr == S_FALSE) { + 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"); - need_uninit = true; - } else if (hr == S_OK) { - LOG("COM initialized."); - need_uninit = true; + LOG("COM already initialized in MTA\n"); } - } - ~auto_com() { - if (need_uninit) { + if (SUCCEEDED(result)) { CoUninitialize(); } } + bool ok() { + return result == RPC_E_CHANGED_MODE || SUCCEEDED(result); + } private: - bool need_uninit; + HRESULT result; }; typedef HANDLE (WINAPI *set_mm_thread_characteristics_function)( @@ -205,7 +199,6 @@ int setup_wasapi_stream(cubeb_stream * stm); } - struct cubeb { cubeb_ops const * ops; @@ -258,7 +251,7 @@ struct cubeb_stream HANDLE refill_event; /* Each cubeb_stream has its own thread. */ HANDLE thread; - /* We synthetize our clock from the callbacks. */ + /* We synthesize our clock from the callbacks. */ LONG64 clock; owned_critical_section * stream_reset_lock; /* Maximum number of frames we can be requested in a callback. */ @@ -296,7 +289,7 @@ public: HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID **ppvInterface) { - if (IID_IUnknown == riid) { + if (__uuidof(IUnknown) == riid) { AddRef(); *ppvInterface = (IUnknown*)this; } else if (__uuidof(IMMNotificationClient) == riid) { @@ -326,7 +319,10 @@ public: return S_OK; } - auto_com autocom; + auto_com com; + if (!com.ok()) { + return E_FAIL; + } /* Close the stream */ wasapi_stream_stop(stm); @@ -346,27 +342,27 @@ public: * log is enabled), for debugging. */ HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR device_id) { - LOG("Audio device added."); + LOG("Audio device added.\n"); return S_OK; }; HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR device_id) { - LOG("Audio device removed."); + LOG("Audio device removed.\n"); return S_OK; } HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR device_id, DWORD new_state) { - LOG("Audio device state changed."); + LOG("Audio device state changed.\n"); return S_OK; } HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(LPCWSTR device_id, const PROPERTYKEY key) { - LOG("Audio device property value changed."); + LOG("Audio device property value changed.\n"); return S_OK; } private: @@ -488,7 +484,7 @@ refill(cubeb_stream * stm, float * data, long frames_needed) /* Go in draining mode if we got fewer frames than requested. */ if (out_frames < frames_needed) { - LOG("draining."); + LOG("draining.\n"); stm->draining = true; } @@ -513,10 +509,14 @@ wasapi_stream_render_loop(LPVOID stream) bool is_playing = true; HANDLE wait_array[2] = {stm->shutdown_event, stm->refill_event}; HANDLE mmcss_handle = NULL; - HRESULT hr; + HRESULT hr = 0; bool first = true; DWORD mmcss_task_index = 0; auto_com com; + if (!com.ok()) { + LOG("COM initialization failed on render_loop thread.\n"); + return 0; + } /* We could consider using "Pro Audio" here for WebAudio and * maybe WebRTC. */ @@ -524,7 +524,7 @@ wasapi_stream_render_loop(LPVOID stream) stm->context->set_mm_thread_characteristics("Audio", &mmcss_task_index); if (!mmcss_handle) { /* This is not fatal, but we might glitch under heavy load. */ - LOG("Unable to use mmcss to bump the render thread priority: %x", GetLastError()); + LOG("Unable to use mmcss to bump the render thread priority: %x\n", GetLastError()); } @@ -549,7 +549,7 @@ wasapi_stream_render_loop(LPVOID stream) hr = stm->client->GetCurrentPadding(&padding); if (FAILED(hr)) { - LOG("Failed to get padding"); + LOG("Failed to get padding\n"); is_playing = false; continue; } @@ -576,11 +576,11 @@ wasapi_stream_render_loop(LPVOID stream) hr = stm->render_client->ReleaseBuffer(available, 0); if (FAILED(hr)) { - LOG("failed to release buffer."); + LOG("failed to release buffer.\n"); is_playing = false; } } else { - LOG("failed to get buffer."); + LOG("failed to get buffer.\n"); is_playing = false; } } @@ -619,7 +619,7 @@ HRESULT register_notification_client(cubeb_stream * stm) IID_PPV_ARGS(&stm->device_enumerator)); if (FAILED(hr)) { - LOG("Could not get device enumerator: %x", hr); + LOG("Could not get device enumerator: %x\n", hr); return hr; } @@ -628,7 +628,7 @@ HRESULT register_notification_client(cubeb_stream * stm) hr = stm->device_enumerator->RegisterEndpointNotificationCallback(stm->notification_client); if (FAILED(hr)) { - LOG("Could not register endpoint notification callback: %x", hr); + LOG("Could not register endpoint notification callback: %x\n", hr); return hr; } @@ -657,9 +657,8 @@ HRESULT get_default_endpoint(IMMDevice ** device) HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&enumerator)); - if (FAILED(hr)) { - LOG("Could not get device enumerator."); + LOG("Could not get device enumerator.\n"); return hr; } /* eMultimedia is okay for now ("Music, movies, narration, [...]"). @@ -668,7 +667,7 @@ HRESULT get_default_endpoint(IMMDevice ** device) * and eCommunication ("Voice communication"). */ hr = enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, device); if (FAILED(hr)) { - LOG("Could not get default audio endpoint. %d", __LINE__); + LOG("Could not get default audio endpoint. %d\n", __LINE__); SafeRelease(enumerator); return hr; } @@ -684,6 +683,9 @@ int wasapi_init(cubeb ** context, char const * context_name) { 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 @@ -691,7 +693,7 @@ int wasapi_init(cubeb ** context, char const * context_name) IMMDevice * device; hr = get_default_endpoint(&device); if (FAILED(hr)) { - LOG("Could not get device."); + LOG("Could not get device.\n"); return CUBEB_ERROR; } SafeRelease(device); @@ -710,13 +712,13 @@ int wasapi_init(cubeb ** context, char const * context_name) (revert_mm_thread_characteristics_function) GetProcAddress( ctx->mmcss_module, "AvRevertMmThreadCharacteristics"); if (!(ctx->set_mm_thread_characteristics && ctx->revert_mm_thread_characteristics)) { - LOG("Could not load AvSetMmThreadCharacteristics or AvRevertMmThreadCharacteristics: %x", GetLastError()); + LOG("Could not load AvSetMmThreadCharacteristics or AvRevertMmThreadCharacteristics: %x\n", GetLastError()); FreeLibrary(ctx->mmcss_module); } } else { // This is not a fatal error, but we might end up glitching when // the system is under high load. - LOG("Could not load Avrt.dll"); + LOG("Could not load Avrt.dll\n"); ctx->set_mm_thread_characteristics = &set_mm_thread_characteristics_noop; ctx->revert_mm_thread_characteristics = &revert_mm_thread_characteristics_noop; } @@ -749,6 +751,9 @@ wasapi_get_max_channel_count(cubeb * ctx, uint32_t * max_channels) IAudioClient * client; WAVEFORMATEX * mix_format; auto_com com; + if (!com.ok()) { + return CUBEB_ERROR; + } assert(ctx && max_channels); @@ -787,11 +792,14 @@ wasapi_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * laten IAudioClient * client; REFERENCE_TIME default_period; auto_com com; + if (!com.ok()) { + return CUBEB_ERROR; + } IMMDevice * device; hr = get_default_endpoint(&device); if (FAILED(hr)) { - LOG("Could not get default endpoint:%x.", hr) + LOG("Could not get default endpoint:%x.\n", hr); return CUBEB_ERROR; } @@ -800,7 +808,7 @@ wasapi_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * laten NULL, (void **)&client); SafeRelease(device); if (FAILED(hr)) { - LOG("Could not activate device for latency: %x.", hr) + LOG("Could not activate device for latency: %x.\n", hr); return CUBEB_ERROR; } @@ -808,11 +816,11 @@ wasapi_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * laten hr = client->GetDevicePeriod(&default_period, NULL); if (FAILED(hr)) { SafeRelease(client); - LOG("Could not get device period: %x.", hr) + LOG("Could not get device period: %x.\n", hr); return CUBEB_ERROR; } - LOG("default device period: %ld", default_period) + LOG("default device period: %ld\n", default_period); /* According to the docs, the best latency we can achieve is by synchronizing * the stream and the engine. @@ -831,6 +839,9 @@ wasapi_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate) IAudioClient * client; WAVEFORMATEX * mix_format; auto_com com; + if (!com.ok()) { + return CUBEB_ERROR; + } IMMDevice * device; hr = get_default_endpoint(&device); @@ -915,7 +926,7 @@ handle_channel_layout(cubeb_stream * stm, WAVEFORMATEX ** mix_format, const cub if (hr == S_FALSE) { /* Not supported, but WASAPI gives us a suggestion. Use it, and handle the * eventual upmix/downmix ourselves */ - LOG("Using WASAPI suggested format: channels: %d", closest->nChannels); + LOG("Using WASAPI suggested format: channels: %d\n", closest->nChannels); WAVEFORMATEXTENSIBLE * closest_pcm = reinterpret_cast(closest); assert(closest_pcm->SubFormat == format_pcm->SubFormat); CoTaskMemFree(*mix_format); @@ -926,7 +937,7 @@ handle_channel_layout(cubeb_stream * stm, WAVEFORMATEX ** mix_format, const cub * of the code figure out the right conversion path. */ **mix_format = hw_mixformat; } else if (hr == S_OK) { - LOG("Requested format accepted by WASAPI."); + LOG("Requested format accepted by WASAPI.\n"); } } @@ -936,15 +947,20 @@ int setup_wasapi_stream(cubeb_stream * stm) IMMDevice * device; WAVEFORMATEX * mix_format; +#ifdef DEBUG stm->stream_reset_lock->assert_current_thread_owns(); +#endif auto_com com; + if (!com.ok()) { + return CUBEB_ERROR; + } assert(!stm->client && "WASAPI stream already setup, close it first."); hr = get_default_endpoint(&device); if (FAILED(hr)) { - LOG("Could not get default endpoint, error: %x", hr); + LOG("Could not get default endpoint, error: %x\n", hr); auto_unlock unlock(stm->stream_reset_lock); wasapi_stream_destroy(stm); return CUBEB_ERROR; @@ -953,11 +969,11 @@ int setup_wasapi_stream(cubeb_stream * stm) /* Get a client. We will get all other interfaces we need from * this pointer. */ hr = device->Activate(__uuidof(IAudioClient), - CLSCTX_INPROC_SERVER, - NULL, (void **)&stm->client); + CLSCTX_INPROC_SERVER, + NULL, (void **)&stm->client); SafeRelease(device); if (FAILED(hr)) { - LOG("Could not activate the device to get an audio client: error: %x", hr); + LOG("Could not activate the device to get an audio client: error: %x\n", hr); auto_unlock unlock(stm->stream_reset_lock); wasapi_stream_destroy(stm); return CUBEB_ERROR; @@ -967,7 +983,7 @@ int setup_wasapi_stream(cubeb_stream * stm) * and the format the stream we want to play uses. */ hr = stm->client->GetMixFormat(&mix_format); if (FAILED(hr)) { - LOG("Could not fetch current mix format from the audio client: error: %x", hr); + LOG("Could not fetch current mix format from the audio client: error: %x\n", hr); auto_unlock unlock(stm->stream_reset_lock); wasapi_stream_destroy(stm); return CUBEB_ERROR; @@ -982,17 +998,17 @@ int setup_wasapi_stream(cubeb_stream * stm) stm->mix_params.channels = mix_format->nChannels; hr = stm->client->Initialize(AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_EVENTCALLBACK | - AUDCLNT_STREAMFLAGS_NOPERSIST, - ms_to_hns(stm->latency), - 0, - mix_format, - NULL); + AUDCLNT_STREAMFLAGS_EVENTCALLBACK | + AUDCLNT_STREAMFLAGS_NOPERSIST, + ms_to_hns(stm->latency), + 0, + mix_format, + NULL); CoTaskMemFree(mix_format); if (FAILED(hr)) { - LOG("Unable to initialize audio client: %x.", hr); + LOG("Unable to initialize audio client: %x.\n", hr); auto_unlock unlock(stm->stream_reset_lock); wasapi_stream_destroy(stm); return CUBEB_ERROR; @@ -1000,37 +1016,37 @@ int setup_wasapi_stream(cubeb_stream * stm) hr = stm->client->GetBufferSize(&stm->buffer_frame_count); if (FAILED(hr)) { - LOG("Could not get the buffer size from the client %x.", hr); + LOG("Could not get the buffer size from the client %x.\n", hr); auto_unlock unlock(stm->stream_reset_lock); wasapi_stream_destroy(stm); return CUBEB_ERROR; } if (should_upmix(stm) || should_downmix(stm)) { - stm->mix_buffer = (float *)malloc(frames_to_bytes_before_mix(stm, stm->buffer_frame_count)); + stm->mix_buffer = (float *) malloc(frames_to_bytes_before_mix(stm, stm->buffer_frame_count)); } hr = stm->client->SetEventHandle(stm->refill_event); if (FAILED(hr)) { - LOG("Could set the event handle for the client %x.", hr); + LOG("Could set the event handle for the client %x.\n", hr); auto_unlock unlock(stm->stream_reset_lock); wasapi_stream_destroy(stm); return CUBEB_ERROR; } hr = stm->client->GetService(__uuidof(IAudioRenderClient), - (void **)&stm->render_client); + (void **)&stm->render_client); if (FAILED(hr)) { - LOG("Could not get the render client %x.", hr); + LOG("Could not get the render client %x.\n", hr); auto_unlock unlock(stm->stream_reset_lock); wasapi_stream_destroy(stm); return CUBEB_ERROR; } hr = stm->client->GetService(__uuidof(IAudioStreamVolume), - (void **)&stm->audio_stream_volume); + (void **)&stm->audio_stream_volume); if (FAILED(hr)) { - LOG("Could not get the IAudioStreamVolume %x.", hr); + LOG("Could not get the IAudioStreamVolume %x.\n", hr); auto_unlock unlock(stm->stream_reset_lock); wasapi_stream_destroy(stm); return CUBEB_ERROR; @@ -1041,14 +1057,14 @@ int setup_wasapi_stream(cubeb_stream * stm) * of channels of the stream, not the number of channels * that WASAPI wants. */ stm->resampler = cubeb_resampler_create(stm, stm->stream_params, - stm->mix_params.rate, - stm->data_callback, - stm->buffer_frame_count, - stm->user_ptr, - CUBEB_RESAMPLER_QUALITY_DESKTOP); + stm->mix_params.rate, + stm->data_callback, + stm->buffer_frame_count, + stm->user_ptr, + CUBEB_RESAMPLER_QUALITY_DESKTOP); if (!stm->resampler) { + LOG("Could not get a resampler\n"); auto_unlock unlock(stm->stream_reset_lock); - LOG("Could not get a resampler"); wasapi_stream_destroy(stm); return CUBEB_ERROR; } @@ -1065,6 +1081,9 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream, HRESULT hr; int rv; auto_com com; + if (!com.ok()) { + return CUBEB_ERROR; + } assert(context && stream); @@ -1082,12 +1101,12 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream, stm->clock = 0; /* Null out WASAPI-specific state */ - stm->resampler = nullptr; - stm->client = nullptr; - stm->render_client = nullptr; - stm->audio_stream_volume = nullptr; - stm->device_enumerator = nullptr; - stm->notification_client = nullptr; + stm->resampler = NULL; + stm->client = NULL; + stm->render_client = NULL; + stm->audio_stream_volume = NULL; + stm->device_enumerator = NULL; + stm->notification_client = NULL; stm->stream_reset_lock = new owned_critical_section(); @@ -1095,14 +1114,14 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream, stm->refill_event = CreateEvent(NULL, 0, 0, NULL); if (!stm->shutdown_event) { - LOG("Can't create the shutdown event, error: %x.", GetLastError()); + LOG("Can't create the shutdown event, error: %x\n", GetLastError()); wasapi_stream_destroy(stm); return CUBEB_ERROR; } if (!stm->refill_event) { SafeRelease(stm->shutdown_event); - LOG("Can't create the refill event, error: %x.", GetLastError()); + LOG("Can't create the refill event, error: %x\n", GetLastError()); wasapi_stream_destroy(stm); return CUBEB_ERROR; } @@ -1122,7 +1141,7 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream, if (FAILED(hr)) { /* this is not fatal, we can still play audio, but we won't be able * to keep using the default audio endpoint if it changes. */ - LOG("failed to register notification client, %x", hr); + LOG("failed to register notification client, %x\n", hr); } *stream = stm; @@ -1134,21 +1153,23 @@ void close_wasapi_stream(cubeb_stream * stm) { assert(stm); +#ifdef DEBUG stm->stream_reset_lock->assert_current_thread_owns(); +#endif SafeRelease(stm->client); - stm->client = nullptr; + stm->client = NULL; SafeRelease(stm->render_client); - stm->client = nullptr; + stm->render_client = NULL; if (stm->resampler) { cubeb_resampler_destroy(stm->resampler); - stm->resampler = nullptr; + stm->resampler = NULL; } free(stm->mix_buffer); - stm->mix_buffer = nullptr; + stm->mix_buffer = NULL; } void wasapi_stream_destroy(cubeb_stream * stm) @@ -1158,8 +1179,14 @@ void wasapi_stream_destroy(cubeb_stream * stm) unregister_notification_client(stm); if (stm->thread) { - SetEvent(stm->shutdown_event); - WaitForSingleObject(stm->thread, INFINITE); + BOOL ok = SetEvent(stm->shutdown_event); + if (!ok) { + LOG("Destroy SetEvent failed: %d\n", GetLastError()); + } + DWORD r = WaitForSingleObject(stm->thread, INFINITE); + if (r == WAIT_FAILED) { + LOG("Destroy WaitForSingleObject on thread failed: %d\n", GetLastError()); + } CloseHandle(stm->thread); stm->thread = 0; } @@ -1179,27 +1206,25 @@ void wasapi_stream_destroy(cubeb_stream * stm) int wasapi_stream_start(cubeb_stream * stm) { - HRESULT hr; - auto_lock lock(stm->stream_reset_lock); - assert(stm); + assert(stm && !stm->thread); stm->thread = (HANDLE) _beginthreadex(NULL, 256 * 1024, wasapi_stream_render_loop, stm, STACK_SIZE_PARAM_IS_A_RESERVATION, NULL); if (stm->thread == NULL) { - LOG("could not create WASAPI render thread."); + LOG("could not create WASAPI render thread.\n"); return CUBEB_ERROR; } - hr = stm->client->Start(); + HRESULT hr = stm->client->Start(); if (FAILED(hr)) { - LOG("could not start the stream."); + LOG("could not start the stream.\n"); return CUBEB_ERROR; + } else { + stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STARTED); } - stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STARTED); - - return CUBEB_OK; + return FAILED(hr) ? CUBEB_ERROR : CUBEB_OK; } int wasapi_stream_stop(cubeb_stream * stm) @@ -1208,23 +1233,31 @@ int wasapi_stream_stop(cubeb_stream * stm) auto_lock lock(stm->stream_reset_lock); - SetEvent(stm->shutdown_event); + BOOL ok = SetEvent(stm->shutdown_event); + if (!ok) { + LOG("Stop SetEvent failed: %d\n", GetLastError()); + } HRESULT hr = stm->client->Stop(); if (FAILED(hr)) { - LOG("could not stop AudioClient"); + LOG("could not stop AudioClient\n"); } if (stm->thread) { auto_unlock lock(stm->stream_reset_lock); - WaitForSingleObject(stm->thread, INFINITE); + DWORD r = WaitForSingleObject(stm->thread, INFINITE); + if (r == WAIT_FAILED) { + LOG("Stop WaitForSingleObject on thread failed: %d\n", GetLastError()); + } CloseHandle(stm->thread); stm->thread = NULL; } - stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED); + if (SUCCEEDED(hr)) { + stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED); + } - return CUBEB_OK; + return FAILED(hr) ? CUBEB_ERROR : CUBEB_OK; } int wasapi_stream_get_position(cubeb_stream * stm, uint64_t * position) @@ -1267,7 +1300,7 @@ int wasapi_stream_set_volume(cubeb_stream * stm, float volume) hr = stm->audio_stream_volume->GetChannelCount(&channels); if (hr != S_OK) { - LOG("could not get the channel count: %x", hr); + LOG("could not get the channel count: %x\n", hr); return CUBEB_ERROR; } @@ -1279,7 +1312,7 @@ int wasapi_stream_set_volume(cubeb_stream * stm, float volume) hr = stm->audio_stream_volume->SetAllVolumes(channels, volumes); if (hr != S_OK) { - LOG("coult not set the channels volume: %x", hr); + LOG("could not set the channels volume: %x\n", hr); return CUBEB_ERROR; } return CUBEB_OK; @@ -1303,6 +1336,5 @@ cubeb_ops const wasapi_ops = { /*.stream_get_current_device =*/ NULL, /*.stream_device_destroy =*/ NULL, /*.stream_register_device_changed_callback =*/ NULL - }; +}; } // namespace anonymous - diff --git a/media/libcubeb/src/cubeb_winmm.c b/media/libcubeb/src/cubeb_winmm.c index c438f647a040..1d0186924035 100644 --- a/media/libcubeb/src/cubeb_winmm.c +++ b/media/libcubeb/src/cubeb_winmm.c @@ -654,6 +654,10 @@ winmm_stream_get_latency(cubeb_stream * stm, uint32_t * latency) written = stm->written; LeaveCriticalSection(&stm->lock); + if (r != MMSYSERR_NOERROR || time.wType != TIME_SAMPLES) { + return CUBEB_ERROR; + } + *latency = written - time.u.sample; return CUBEB_OK;