Commit d5e648dc authored by Andrew Eikum's avatar Andrew Eikum Committed by Alexandre Julliard

dsound: For capture, use MMDevAPI event API instead of timers.

parent 927324ce
...@@ -59,6 +59,8 @@ typedef struct IDirectSoundCaptureBufferImpl ...@@ -59,6 +59,8 @@ typedef struct IDirectSoundCaptureBufferImpl
/* IDirectSoundNotify fields */ /* IDirectSoundNotify fields */
DSBPOSITIONNOTIFY *notifies; DSBPOSITIONNOTIFY *notifies;
int nrofnotifies; int nrofnotifies;
HANDLE thread;
HANDLE sleepev;
} IDirectSoundCaptureBufferImpl; } IDirectSoundCaptureBufferImpl;
/* DirectSoundCaptureDevice implementation structure */ /* DirectSoundCaptureDevice implementation structure */
...@@ -72,7 +74,6 @@ struct DirectSoundCaptureDevice ...@@ -72,7 +74,6 @@ struct DirectSoundCaptureDevice
WAVEFORMATEX *pwfx; WAVEFORMATEX *pwfx;
IDirectSoundCaptureBufferImpl *capture_buffer; IDirectSoundCaptureBufferImpl *capture_buffer;
DWORD state; DWORD state;
UINT timerID;
CRITICAL_SECTION lock; CRITICAL_SECTION lock;
IMMDevice *mmdevice; IMMDevice *mmdevice;
IAudioClient *client; IAudioClient *client;
...@@ -80,12 +81,20 @@ struct DirectSoundCaptureDevice ...@@ -80,12 +81,20 @@ struct DirectSoundCaptureDevice
struct list entry; struct list entry;
}; };
static DWORD WINAPI DSOUND_capture_thread(void *user);
static void capturebuffer_destroy(IDirectSoundCaptureBufferImpl *This) static void capturebuffer_destroy(IDirectSoundCaptureBufferImpl *This)
{ {
if (This->device->state == STATE_CAPTURING) if (This->device->state == STATE_CAPTURING)
This->device->state = STATE_STOPPING; This->device->state = STATE_STOPPING;
if(This->thread){
SetEvent(This->sleepev);
WaitForSingleObject(This->thread, INFINITE);
CloseHandle(This->thread);
}
CloseHandle(This->sleepev);
HeapFree(GetProcessHeap(),0, This->pdscbd); HeapFree(GetProcessHeap(),0, This->pdscbd);
if (This->device->client) { if (This->device->client) {
...@@ -739,8 +748,8 @@ static HRESULT IDirectSoundCaptureBufferImpl_Create( ...@@ -739,8 +748,8 @@ static HRESULT IDirectSoundCaptureBufferImpl_Create(
} }
err = IAudioClient_Initialize(device->client, err = IAudioClient_Initialize(device->client,
AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST, AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST | AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
200 * 100000, 50000, device->pwfx, NULL); 200 * 100000, 0, device->pwfx, NULL);
if(FAILED(err)){ if(FAILED(err)){
WARN("Initialize failed: %08x\n", err); WARN("Initialize failed: %08x\n", err);
IAudioClient_Release(device->client); IAudioClient_Release(device->client);
...@@ -753,12 +762,27 @@ static HRESULT IDirectSoundCaptureBufferImpl_Create( ...@@ -753,12 +762,27 @@ static HRESULT IDirectSoundCaptureBufferImpl_Create(
return err; return err;
} }
This->sleepev = CreateEventW(NULL, 0, 0, NULL);
err = IAudioClient_SetEventHandle(device->client, This->sleepev);
if(FAILED(err)){
WARN("SetEventHandle failed: %08x\n", err);
IAudioClient_Release(device->client);
device->client = NULL;
CloseHandle(This->sleepev);
HeapFree(GetProcessHeap(), 0, This->pdscbd);
This->device->capture_buffer = 0;
HeapFree( GetProcessHeap(), 0, This );
return err;
}
err = IAudioClient_GetService(device->client, &IID_IAudioCaptureClient, err = IAudioClient_GetService(device->client, &IID_IAudioCaptureClient,
(void**)&device->capture); (void**)&device->capture);
if(FAILED(err)){ if(FAILED(err)){
WARN("GetService failed: %08x\n", err); WARN("GetService failed: %08x\n", err);
IAudioClient_Release(device->client); IAudioClient_Release(device->client);
device->client = NULL; device->client = NULL;
CloseHandle(This->sleepev);
HeapFree(GetProcessHeap(), 0, This->pdscbd); HeapFree(GetProcessHeap(), 0, This->pdscbd);
This->device->capture_buffer = 0; This->device->capture_buffer = 0;
HeapFree( GetProcessHeap(), 0, This ); HeapFree( GetProcessHeap(), 0, This );
...@@ -776,6 +800,7 @@ static HRESULT IDirectSoundCaptureBufferImpl_Create( ...@@ -776,6 +800,7 @@ static HRESULT IDirectSoundCaptureBufferImpl_Create(
device->client = NULL; device->client = NULL;
IAudioCaptureClient_Release(device->capture); IAudioCaptureClient_Release(device->capture);
device->capture = NULL; device->capture = NULL;
CloseHandle(This->sleepev);
HeapFree(GetProcessHeap(), 0, This->pdscbd); HeapFree(GetProcessHeap(), 0, This->pdscbd);
This->device->capture_buffer = 0; This->device->capture_buffer = 0;
HeapFree( GetProcessHeap(), 0, This ); HeapFree( GetProcessHeap(), 0, This );
...@@ -783,6 +808,7 @@ static HRESULT IDirectSoundCaptureBufferImpl_Create( ...@@ -783,6 +808,7 @@ static HRESULT IDirectSoundCaptureBufferImpl_Create(
} }
device->buffer = newbuf; device->buffer = newbuf;
device->buflen = buflen; device->buflen = buflen;
This->thread = CreateThread(NULL, 0, DSOUND_capture_thread, This, 0, NULL);
} }
IDirectSoundCaptureBuffer_AddRef(&This->IDirectSoundCaptureBuffer8_iface); IDirectSoundCaptureBuffer_AddRef(&This->IDirectSoundCaptureBuffer8_iface);
...@@ -830,9 +856,6 @@ static ULONG DirectSoundCaptureDevice_Release( ...@@ -830,9 +856,6 @@ static ULONG DirectSoundCaptureDevice_Release(
if (!ref) { if (!ref) {
TRACE("deleting object\n"); TRACE("deleting object\n");
timeKillEvent(device->timerID);
timeEndPeriod(DS_TIME_RES);
EnterCriticalSection(&DSOUND_capturers_lock); EnterCriticalSection(&DSOUND_capturers_lock);
list_remove(&device->entry); list_remove(&device->entry);
LeaveCriticalSection(&DSOUND_capturers_lock); LeaveCriticalSection(&DSOUND_capturers_lock);
...@@ -851,29 +874,19 @@ static ULONG DirectSoundCaptureDevice_Release( ...@@ -851,29 +874,19 @@ static ULONG DirectSoundCaptureDevice_Release(
return ref; return ref;
} }
static void CALLBACK DSOUND_capture_timer(UINT timerID, UINT msg, DWORD_PTR user, static HRESULT DSOUND_capture_data(DirectSoundCaptureDevice *device)
DWORD_PTR dw1, DWORD_PTR dw2)
{ {
DirectSoundCaptureDevice *device = (DirectSoundCaptureDevice*)user; HRESULT hr;
UINT32 packet_frames, packet_bytes, avail_bytes, skip_bytes = 0; UINT32 packet_frames, packet_bytes, avail_bytes, skip_bytes = 0;
DWORD flags; DWORD flags;
BYTE *buf; BYTE *buf;
HRESULT hr;
if(!device->ref)
return;
EnterCriticalSection(&device->lock); if(!device->capture_buffer || device->state == STATE_STOPPED)
return S_FALSE;
if(!device->capture_buffer || device->state == STATE_STOPPED){
LeaveCriticalSection(&device->lock);
return;
}
if(device->state == STATE_STOPPING){ if(device->state == STATE_STOPPING){
device->state = STATE_STOPPED; device->state = STATE_STOPPED;
LeaveCriticalSection(&device->lock); return S_FALSE;
return;
} }
if(device->state == STATE_STARTING) if(device->state == STATE_STARTING)
...@@ -882,9 +895,8 @@ static void CALLBACK DSOUND_capture_timer(UINT timerID, UINT msg, DWORD_PTR user ...@@ -882,9 +895,8 @@ static void CALLBACK DSOUND_capture_timer(UINT timerID, UINT msg, DWORD_PTR user
hr = IAudioCaptureClient_GetBuffer(device->capture, &buf, &packet_frames, hr = IAudioCaptureClient_GetBuffer(device->capture, &buf, &packet_frames,
&flags, NULL, NULL); &flags, NULL, NULL);
if(FAILED(hr)){ if(FAILED(hr)){
LeaveCriticalSection(&device->lock);
WARN("GetBuffer failed: %08x\n", hr); WARN("GetBuffer failed: %08x\n", hr);
return; return hr;
} }
packet_bytes = packet_frames * device->pwfx->nBlockAlign; packet_bytes = packet_frames * device->pwfx->nBlockAlign;
...@@ -917,12 +929,44 @@ static void CALLBACK DSOUND_capture_timer(UINT timerID, UINT msg, DWORD_PTR user ...@@ -917,12 +929,44 @@ static void CALLBACK DSOUND_capture_timer(UINT timerID, UINT msg, DWORD_PTR user
hr = IAudioCaptureClient_ReleaseBuffer(device->capture, packet_frames); hr = IAudioCaptureClient_ReleaseBuffer(device->capture, packet_frames);
if(FAILED(hr)){ if(FAILED(hr)){
LeaveCriticalSection(&device->lock);
WARN("ReleaseBuffer failed: %08x\n", hr); WARN("ReleaseBuffer failed: %08x\n", hr);
return; return hr;
} }
LeaveCriticalSection(&device->lock); return S_OK;
}
static DWORD WINAPI DSOUND_capture_thread(void *user)
{
IDirectSoundCaptureBufferImpl *buffer = user;
HRESULT hr;
DWORD ret, wait_ms;
REFERENCE_TIME period;
hr = IAudioClient_GetDevicePeriod(buffer->device->client, &period, NULL);
if(FAILED(hr)){
WARN("GetDevicePeriod failed: %08x\n", hr);
wait_ms = 5;
}else
wait_ms = MulDiv(5, period, 10000);
while(buffer->ref){
ret = WaitForSingleObject(buffer->sleepev, wait_ms);
if(!buffer->device->ref)
break;
if(ret == WAIT_OBJECT_0){
EnterCriticalSection(&buffer->device->lock);
DSOUND_capture_data(buffer->device);
LeaveCriticalSection(&buffer->device->lock);
}else if(ret != WAIT_TIMEOUT)
WARN("WaitForSingleObject failed: %u\n", GetLastError());
}
return 0;
} }
static struct _TestFormat { static struct _TestFormat {
...@@ -1020,8 +1064,6 @@ static HRESULT DirectSoundCaptureDevice_Initialize( ...@@ -1020,8 +1064,6 @@ static HRESULT DirectSoundCaptureDevice_Initialize(
} }
IAudioClient_Release(client); IAudioClient_Release(client);
device->timerID = DSOUND_create_timer(DSOUND_capture_timer, (DWORD_PTR)device);
list_add_tail(&DSOUND_capturers, &device->entry); list_add_tail(&DSOUND_capturers, &device->entry);
*ppDevice = device; *ppDevice = device;
......
...@@ -735,30 +735,6 @@ BOOL DSOUND_check_supported(IAudioClient *client, DWORD rate, ...@@ -735,30 +735,6 @@ BOOL DSOUND_check_supported(IAudioClient *client, DWORD rate,
return hr == S_OK; return hr == S_OK;
} }
UINT DSOUND_create_timer(LPTIMECALLBACK cb, DWORD_PTR user)
{
UINT triggertime = DS_TIME_DEL, res = DS_TIME_RES, id;
TIMECAPS time;
timeGetDevCaps(&time, sizeof(TIMECAPS));
TRACE("Minimum timer resolution: %u, max timer: %u\n", time.wPeriodMin, time.wPeriodMax);
if (triggertime < time.wPeriodMin)
triggertime = time.wPeriodMin;
if (res < time.wPeriodMin)
res = time.wPeriodMin;
if (timeBeginPeriod(res) == TIMERR_NOCANDO)
WARN("Could not set minimum resolution, don't expect sound\n");
id = timeSetEvent(triggertime, res, cb, user, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
if (!id)
{
WARN("Timer not created! Retrying without TIME_KILL_SYNCHRONOUS\n");
id = timeSetEvent(triggertime, res, cb, user, TIME_PERIODIC);
if (!id)
ERR("Could not create timer, sound playback will not occur\n");
}
return id;
}
HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID) HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
{ {
HRESULT hr = DS_OK; HRESULT hr = DS_OK;
......
...@@ -261,6 +261,5 @@ HRESULT get_mmdevice(EDataFlow flow, const GUID *tgt, IMMDevice **device) DECLSP ...@@ -261,6 +261,5 @@ HRESULT get_mmdevice(EDataFlow flow, const GUID *tgt, IMMDevice **device) DECLSP
BOOL DSOUND_check_supported(IAudioClient *client, DWORD rate, BOOL DSOUND_check_supported(IAudioClient *client, DWORD rate,
DWORD depth, WORD channels) DECLSPEC_HIDDEN; DWORD depth, WORD channels) DECLSPEC_HIDDEN;
UINT DSOUND_create_timer(LPTIMECALLBACK cb, DWORD_PTR user) DECLSPEC_HIDDEN;
HRESULT enumerate_mmdevices(EDataFlow flow, GUID *guids, HRESULT enumerate_mmdevices(EDataFlow flow, GUID *guids,
LPDSENUMCALLBACKW cb, void *user) DECLSPEC_HIDDEN; LPDSENUMCALLBACKW cb, void *user) DECLSPEC_HIDDEN;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment