diff --git a/src/cubeb_wasapi.cpp b/src/cubeb_wasapi.cpp index 0bb77261..592dab65 100644 --- a/src/cubeb_wasapi.cpp +++ b/src/cubeb_wasapi.cpp @@ -437,6 +437,10 @@ struct cubeb_stream { * practice, we read from the input stream in the output callback, so * this is not used, but it is necessary to start getting input data. */ HANDLE input_available_event = 0; + /* Signaled by stream_start/stream_stop when the active state changes, + so the render thread can promote/demote its MMCSS task accordingly + instead of remaining promoted while idle. */ + HANDLE mmcss_event = 0; /* Each cubeb_stream has its own thread. */ HANDLE thread = 0; /* The lock protects all members that are touched by the render thread or @@ -1503,8 +1507,9 @@ static unsigned int __stdcall wasapi_stream_render_loop(LPVOID stream) } com; bool is_playing = true; - HANDLE wait_array[4] = {stm->shutdown_event, stm->reconfigure_event, - stm->refill_event, stm->input_available_event}; + HANDLE wait_array[5] = {stm->shutdown_event, stm->mmcss_event, + stm->reconfigure_event, stm->refill_event, + stm->input_available_event}; HANDLE mmcss_handle = NULL; HRESULT hr = 0; DWORD mmcss_task_index = 0; @@ -1517,15 +1522,6 @@ static unsigned int __stdcall wasapi_stream_render_loop(LPVOID stream) return 0; } - /* We could consider using "Pro Audio" here for WebAudio and - maybe WebRTC. */ - mmcss_handle = AvSetMmThreadCharacteristicsA("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: %lx", - GetLastError()); - } - while (is_playing) { DWORD waitResult = WaitForMultipleObjects(ARRAY_LENGTH(wait_array), wait_array, FALSE, INFINITE); @@ -1539,7 +1535,30 @@ static unsigned int __stdcall wasapi_stream_render_loop(LPVOID stream) } continue; } - case WAIT_OBJECT_0 + 1: { /* reconfigure */ + case WAIT_OBJECT_0 + 1: { /* mmcss: active state changed */ + /* stm->active was set by wasapi_stream_start/_stop before signaling, + and SetEvent provides the necessary memory barrier. */ + if (stm->active && !mmcss_handle) { + /* We could consider using "Pro Audio" here for WebAudio and + maybe WebRTC. */ + mmcss_handle = + AvSetMmThreadCharacteristicsA("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: %lx", + GetLastError()); + } else { + LOG("MMCSS render thread promoted (task index %lu)", + mmcss_task_index); + } + } else if (!stm->active && mmcss_handle) { + AvRevertMmThreadCharacteristics(mmcss_handle); + mmcss_handle = NULL; + LOG("MMCSS render thread demoted"); + } + continue; + } + case WAIT_OBJECT_0 + 2: { /* reconfigure */ auto_lock lock(stm->stream_reset_lock); if (!stm->active) { /* Avoid reconfiguring, stream start will handle it. */ @@ -1592,12 +1611,12 @@ static unsigned int __stdcall wasapi_stream_render_loop(LPVOID stream) } break; } - case WAIT_OBJECT_0 + 2: /* refill */ + case WAIT_OBJECT_0 + 3: /* refill */ XASSERT((has_input(stm) && has_output(stm)) || (!has_input(stm) && has_output(stm))); is_playing = stm->refill_callback(stm); break; - case WAIT_OBJECT_0 + 3: { /* input available */ + case WAIT_OBJECT_0 + 4: { /* input available */ bool rv = get_input_buffer(stm); if (!rv) { is_playing = false; @@ -2946,6 +2965,12 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream, return CUBEB_ERROR; } + stm->mmcss_event = CreateEvent(NULL, 0, 0, NULL); + if (!stm->mmcss_event) { + LOG("Can't create the mmcss event, error: %lx", GetLastError()); + return CUBEB_ERROR; + } + stm->thread_ready_event = CreateEvent(NULL, 0, 0, NULL); if (!stm->thread_ready_event) { LOG("Can't create the thread ready event, error: %lx", GetLastError()); @@ -3071,6 +3096,7 @@ wasapi_stream_release(cubeb_stream * stm) CloseHandle(stm->reconfigure_event); CloseHandle(stm->refill_event); CloseHandle(stm->input_available_event); + CloseHandle(stm->mmcss_event); CloseHandle(stm->thread); @@ -3167,6 +3193,11 @@ wasapi_stream_start(cubeb_stream * stm) stm->active = true; + if (!SetEvent(stm->mmcss_event)) { + LOG("wasapi_stream_start: SetEvent(mmcss_event) failed: %lx", + GetLastError()); + } + stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STARTED); return CUBEB_OK; @@ -3199,6 +3230,11 @@ wasapi_stream_stop(cubeb_stream * stm) stm->active = false; + if (!SetEvent(stm->mmcss_event)) { + LOG("wasapi_stream_stop: SetEvent(mmcss_event) failed: %lx", + GetLastError()); + } + wasapi_state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED); }