/* IDirectSoundNotify fields */
DSBPOSITIONNOTIFY *notifies;
int nrofnotifies;
- HANDLE thread;
- HANDLE sleepev;
} IDirectSoundCaptureBufferImpl;
/* DirectSoundCaptureDevice implementation structure */
WAVEFORMATEX *pwfx;
IDirectSoundCaptureBufferImpl *capture_buffer;
DWORD state;
+ UINT timerID;
CRITICAL_SECTION lock;
IMMDevice *mmdevice;
IAudioClient *client;
struct list entry;
};
-static DWORD WINAPI DSOUND_capture_thread(void *user);
static void capturebuffer_destroy(IDirectSoundCaptureBufferImpl *This)
{
if (This->device->state == STATE_CAPTURING)
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);
if (This->device->client) {
}
err = IAudioClient_Initialize(device->client,
- AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST | AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
- 200 * 100000, 0, device->pwfx, NULL);
+ AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST,
+ 200 * 100000, 50000, device->pwfx, NULL);
if(FAILED(err)){
WARN("Initialize failed: %08x\n", err);
IAudioClient_Release(device->client);
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,
(void**)&device->capture);
if(FAILED(err)){
WARN("GetService 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 );
device->client = NULL;
IAudioCaptureClient_Release(device->capture);
device->capture = NULL;
- CloseHandle(This->sleepev);
HeapFree(GetProcessHeap(), 0, This->pdscbd);
This->device->capture_buffer = 0;
HeapFree( GetProcessHeap(), 0, This );
}
device->buffer = newbuf;
device->buflen = buflen;
- This->thread = CreateThread(NULL, 0, DSOUND_capture_thread, This, 0, NULL);
}
IDirectSoundCaptureBuffer_AddRef(&This->IDirectSoundCaptureBuffer8_iface);
if (!ref) {
TRACE("deleting object\n");
+ timeKillEvent(device->timerID);
+ timeEndPeriod(DS_TIME_RES);
+
EnterCriticalSection(&DSOUND_capturers_lock);
list_remove(&device->entry);
LeaveCriticalSection(&DSOUND_capturers_lock);
return ref;
}
-static HRESULT DSOUND_capture_data(DirectSoundCaptureDevice *device)
+static void CALLBACK DSOUND_capture_timer(UINT timerID, UINT msg, DWORD_PTR user,
+ DWORD_PTR dw1, DWORD_PTR dw2)
{
- HRESULT hr;
- UINT32 packet_frames, packet_bytes, avail_bytes, skip_bytes = 0;
+ DirectSoundCaptureDevice *device = (DirectSoundCaptureDevice*)user;
+ UINT32 packet_frames, packet_bytes, avail_bytes;
DWORD flags;
BYTE *buf;
+ HRESULT hr;
- if(!device->capture_buffer || device->state == STATE_STOPPED)
- return S_FALSE;
+ if(!device->ref)
+ return;
+
+ EnterCriticalSection(&device->lock);
+
+ if(!device->capture_buffer || device->state == STATE_STOPPED){
+ LeaveCriticalSection(&device->lock);
+ return;
+ }
if(device->state == STATE_STOPPING){
device->state = STATE_STOPPED;
- return S_FALSE;
+ LeaveCriticalSection(&device->lock);
+ return;
}
if(device->state == STATE_STARTING)
hr = IAudioCaptureClient_GetBuffer(device->capture, &buf, &packet_frames,
&flags, NULL, NULL);
if(FAILED(hr)){
+ LeaveCriticalSection(&device->lock);
WARN("GetBuffer failed: %08x\n", hr);
- return hr;
+ return;
}
packet_bytes = packet_frames * device->pwfx->nBlockAlign;
- if(packet_bytes > device->buflen){
- TRACE("audio glitch: dsound buffer too small for data\n");
- skip_bytes = packet_bytes - device->buflen;
- packet_bytes = device->buflen;
- }
avail_bytes = device->buflen - device->write_pos_bytes;
if(avail_bytes > packet_bytes)
avail_bytes = packet_bytes;
- memcpy(device->buffer + device->write_pos_bytes, buf + skip_bytes, avail_bytes);
+ memcpy(device->buffer + device->write_pos_bytes, buf, avail_bytes);
capture_CheckNotify(device->capture_buffer, device->write_pos_bytes, avail_bytes);
packet_bytes -= avail_bytes;
if(packet_bytes > 0){
if(device->capture_buffer->flags & DSCBSTART_LOOPING){
- memcpy(device->buffer, buf + skip_bytes + avail_bytes, packet_bytes);
+ memcpy(device->buffer, buf + avail_bytes, packet_bytes);
capture_CheckNotify(device->capture_buffer, 0, packet_bytes);
}else{
device->state = STATE_STOPPED;
hr = IAudioCaptureClient_ReleaseBuffer(device->capture, packet_frames);
if(FAILED(hr)){
+ LeaveCriticalSection(&device->lock);
WARN("ReleaseBuffer failed: %08x\n", hr);
- return hr;
+ return;
}
- 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;
+ LeaveCriticalSection(&device->lock);
}
static struct _TestFormat {
EnterCriticalSection(&DSOUND_capturers_lock);
+ LIST_FOR_EACH_ENTRY(device, &DSOUND_capturers, DirectSoundCaptureDevice, entry){
+ if(IsEqualGUID(&device->guid, &devGUID)){
+ IMMDevice_Release(mmdevice);
+ LeaveCriticalSection(&DSOUND_capturers_lock);
+ return DSERR_ALLOCATED;
+ }
+ }
+
hr = DirectSoundCaptureDevice_Create(&device);
if (hr != DS_OK) {
WARN("DirectSoundCaptureDevice_Create failed\n");
}
IAudioClient_Release(client);
+ device->timerID = DSOUND_create_timer(DSOUND_capture_timer, (DWORD_PTR)device);
+
list_add_tail(&DSOUND_capturers, &device->entry);
*ppDevice = device;
return DS_OK;
}
-WAVEFORMATEX *DSOUND_CopyFormat(const WAVEFORMATEX *wfex)
+static DWORD DSOUND_GetFormatSize(LPCWAVEFORMATEX wfex)
{
- WAVEFORMATEX *pwfx;
- if(wfex->wFormatTag == WAVE_FORMAT_PCM){
- pwfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEX));
- CopyMemory(pwfx, wfex, sizeof(PCMWAVEFORMAT));
- pwfx->cbSize = 0;
- }else{
- pwfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEX) + wfex->cbSize);
- CopyMemory(pwfx, wfex, sizeof(WAVEFORMATEX) + wfex->cbSize);
- }
-
- if(pwfx->wFormatTag == WAVE_FORMAT_PCM ||
- (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
- IsEqualGUID(&((const WAVEFORMATEXTENSIBLE*)pwfx)->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)))
- pwfx->nBlockAlign = (pwfx->nChannels * pwfx->wBitsPerSample) / 8;
+ if (wfex->wFormatTag == WAVE_FORMAT_PCM)
+ return sizeof(WAVEFORMATEX);
+ else
+ return sizeof(WAVEFORMATEX) + wfex->cbSize;
+}
- return pwfx;
+LPWAVEFORMATEX DSOUND_CopyFormat(LPCWAVEFORMATEX wfex)
+{
+ DWORD size = DSOUND_GetFormatSize(wfex);
+ LPWAVEFORMATEX pwfx = HeapAlloc(GetProcessHeap(),0,size);
+ if (pwfx == NULL) {
+ WARN("out of memory\n");
+ } else if (wfex->wFormatTag != WAVE_FORMAT_PCM) {
+ CopyMemory(pwfx, wfex, size);
+ } else {
+ CopyMemory(pwfx, wfex, sizeof(PCMWAVEFORMAT));
+ pwfx->cbSize=0;
+ if (pwfx->nBlockAlign != pwfx->nChannels * pwfx->wBitsPerSample/8) {
+ WARN("Fixing bad nBlockAlign (%u)\n", pwfx->nBlockAlign);
+ pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample/8;
+ }
+ if (pwfx->nAvgBytesPerSec != pwfx->nSamplesPerSec * pwfx->nBlockAlign) {
+ WARN("Fixing bad nAvgBytesPerSec (%u)\n", pwfx->nAvgBytesPerSec);
+ pwfx->nAvgBytesPerSec = pwfx->nSamplesPerSec * pwfx->nBlockAlign;
+ }
+ }
+ return pwfx;
}
HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX passed_fmt)
device->primary_pwfx = old_fmt;
else
HeapFree(GetProcessHeap(), 0, old_fmt);
+ } else if (passed_fmt->wFormatTag == WAVE_FORMAT_PCM ||
+ passed_fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
+ /* Fill in "real" values to primary_pwfx */
+ WAVEFORMATEX *fmt = device->primary_pwfx;
+
+ *fmt = *device->pwfx;
+ fmtex = (void*)device->pwfx;
+
+ if (IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) &&
+ passed_fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
+ fmt->wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
+ } else {
+ fmt->wFormatTag = WAVE_FORMAT_PCM;
+ fmt->wBitsPerSample = 16;
+ }
+ fmt->nBlockAlign = fmt->nChannels * fmt->wBitsPerSample / 8;
+ fmt->nAvgBytesPerSec = fmt->nBlockAlign * fmt->nSamplesPerSec;
+ fmt->cbSize = 0;
} else {
- HeapFree(GetProcessHeap(), 0, device->primary_pwfx);
- device->primary_pwfx = DSOUND_CopyFormat(passed_fmt);
+ device->primary_pwfx = HeapReAlloc(GetProcessHeap(), 0, device->primary_pwfx, sizeof(*fmtex));
+ memcpy(device->primary_pwfx, device->pwfx, sizeof(*fmtex));
}
out: