diff options
author | Chris Robinson <[email protected]> | 2012-03-05 07:11:09 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2012-03-05 07:11:09 -0800 |
commit | fe6e532c876bf3ec6776f76f9542038ac9c94d68 (patch) | |
tree | 31d29eb21462dbc02287030d8e3b6174dcab92cc /Alc/backends/mmdevapi.c | |
parent | 5cdeeb47f3b4dedefd1ceb2b32c2f7754abc058d (diff) |
Use a separate backend callback to start playback of the device
This allows us to properly update the ALCdevice and its resources with the new
parameters before starting playback, instead of expecting the mixer to block
and wait after it has begun.
This also lets us avoid holding the device lock while resetting and starting
the device, which helps prevent lock inversion on some backends (ie, one thread
locking A then B, and another thread locking B then A), ultimately allowing
certain backends to asynchronously update the ALCdevice without risk of lockup.
Capture still has issues here, however.
Diffstat (limited to 'Alc/backends/mmdevapi.c')
-rw-r--r-- | Alc/backends/mmdevapi.c | 84 |
1 files changed, 54 insertions, 30 deletions
diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index 52b54eb4..ccfb1a44 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -90,9 +90,10 @@ typedef struct { #define WM_USER_OpenDevice (WM_USER+0) #define WM_USER_ResetDevice (WM_USER+1) -#define WM_USER_StopDevice (WM_USER+2) -#define WM_USER_CloseDevice (WM_USER+3) -#define WM_USER_Enumerate (WM_USER+4) +#define WM_USER_StartDevice (WM_USER+2) +#define WM_USER_StopDevice (WM_USER+3) +#define WM_USER_CloseDevice (WM_USER+4) +#define WM_USER_Enumerate (WM_USER+5) static HRESULT WaitForResponse(ThreadRequest *req) { @@ -315,7 +316,6 @@ static HRESULT DoReset(ALCdevice *device) REFERENCE_TIME min_per, buf_time; UINT32 buffer_len, min_len; HRESULT hr; - void *ptr; hr = IAudioClient_GetMixFormat(data->client, &wfx); if(FAILED(hr)) @@ -532,32 +532,6 @@ static HRESULT DoReset(ALCdevice *device) ERR("Audio client returned buffer_len < period*2; expect break up\n"); } - ResetEvent(data->hNotifyEvent); - hr = IAudioClient_SetEventHandle(data->client, data->hNotifyEvent); - if(SUCCEEDED(hr)) - hr = IAudioClient_Start(data->client); - if(FAILED(hr)) - { - ERR("Failed to start audio client: 0x%08lx\n", hr); - return hr; - } - - hr = IAudioClient_GetService(data->client, &IID_IAudioRenderClient, &ptr); - if(SUCCEEDED(hr)) - { - data->render = ptr; - data->thread = StartThread(MMDevApiProc, device); - } - if(!data->thread) - { - if(data->render) - IAudioRenderClient_Release(data->render); - data->render = NULL; - IAudioClient_Stop(data->client); - ERR("Failed to start thread\n"); - return E_FAIL; - } - return hr; } @@ -656,6 +630,43 @@ static DWORD CALLBACK MMDevApiMsgProc(void *ptr) SetEvent(req->FinishedEvt); continue; + case WM_USER_StartDevice: + req = (ThreadRequest*)msg.wParam; + device = (ALCdevice*)msg.lParam; + data = device->ExtraData; + + ResetEvent(data->hNotifyEvent); + hr = IAudioClient_SetEventHandle(data->client, data->hNotifyEvent); + if(FAILED(hr)) + ERR("Failed to set event handle: 0x%08lx\n", hr); + else + { + hr = IAudioClient_Start(data->client); + if(FAILED(hr)) + ERR("Failed to start audio client: 0x%08lx\n", hr); + } + + if(SUCCEEDED(hr)) + hr = IAudioClient_GetService(data->client, &IID_IAudioRenderClient, &ptr); + if(SUCCEEDED(hr)) + { + data->render = ptr; + data->thread = StartThread(MMDevApiProc, device); + if(!data->thread) + { + if(data->render) + IAudioRenderClient_Release(data->render); + data->render = NULL; + IAudioClient_Stop(data->client); + ERR("Failed to start thread\n"); + hr = E_FAIL; + } + } + + req->result = hr; + SetEvent(req->FinishedEvt); + continue; + case WM_USER_StopDevice: req = (ThreadRequest*)msg.wParam; device = (ALCdevice*)msg.lParam; @@ -885,6 +896,18 @@ static ALCboolean MMDevApiResetPlayback(ALCdevice *device) return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; } +static ALCboolean MMDevApiStartPlayback(ALCdevice *device) +{ + MMDevApiData *data = device->ExtraData; + ThreadRequest req = { data->MsgEvent, 0 }; + HRESULT hr = E_FAIL; + + if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)device)) + hr = WaitForResponse(&req); + + return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; +} + static void MMDevApiStopPlayback(ALCdevice *device) { MMDevApiData *data = device->ExtraData; @@ -899,6 +922,7 @@ static const BackendFuncs MMDevApiFuncs = { MMDevApiOpenPlayback, MMDevApiClosePlayback, MMDevApiResetPlayback, + MMDevApiStartPlayback, MMDevApiStopPlayback, NULL, NULL, |