diff --git a/dlls/dsound/dsound.c b/dlls/dsound/dsound.c index 0b5c3b4b6d1..195da0b31db 100644 --- a/dlls/dsound/dsound.c +++ b/dlls/dsound/dsound.c @@ -161,24 +161,20 @@ static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice) device->guid = GUID_NULL; /* Set default wave format (may need it for waveOutOpen) */ - device->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEXTENSIBLE)); device->primary_pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEXTENSIBLE)); - if (!device->pwfx || !device->primary_pwfx) { + if (!device->primary_pwfx) { WARN("out of memory\n"); - HeapFree(GetProcessHeap(),0,device->primary_pwfx); - HeapFree(GetProcessHeap(),0,device->pwfx); HeapFree(GetProcessHeap(),0,device); return DSERR_OUTOFMEMORY; } - device->pwfx->wFormatTag = WAVE_FORMAT_PCM; - device->pwfx->nSamplesPerSec = 22050; - device->pwfx->wBitsPerSample = 8; - device->pwfx->nChannels = 2; - device->pwfx->nBlockAlign = device->pwfx->wBitsPerSample * device->pwfx->nChannels / 8; - device->pwfx->nAvgBytesPerSec = device->pwfx->nSamplesPerSec * device->pwfx->nBlockAlign; - device->pwfx->cbSize = 0; - memcpy(device->primary_pwfx, device->pwfx, sizeof(*device->pwfx)); + device->primary_pwfx->wFormatTag = WAVE_FORMAT_PCM; + device->primary_pwfx->nSamplesPerSec = 22050; + device->primary_pwfx->wBitsPerSample = 8; + device->primary_pwfx->nChannels = 2; + device->primary_pwfx->nBlockAlign = device->primary_pwfx->wBitsPerSample * device->primary_pwfx->nChannels / 8; + device->primary_pwfx->nAvgBytesPerSec = device->primary_pwfx->nSamplesPerSec * device->primary_pwfx->nBlockAlign; + device->primary_pwfx->cbSize = 0; InitializeCriticalSection(&(device->mixlock)); device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundDevice.mixlock"); @@ -228,12 +224,12 @@ static ULONG DirectSoundDevice_Release(DirectSoundDevice * device) if (hr != DS_OK) WARN("DSOUND_PrimaryDestroy failed\n"); - if(device->client) + if(device->client) { + IAudioClient_Stop(device->client); IAudioClient_Release(device->client); + } if(device->render) IAudioRenderClient_Release(device->render); - if(device->clock) - IAudioClock_Release(device->clock); if(device->volume) IAudioStreamVolume_Release(device->volume); @@ -323,6 +319,7 @@ static HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGU device->mmdevice = mmdevice; device->guid = devGUID; device->sleepev = CreateEventW(0, 0, 0, 0); + device->buflen = ds_hel_buflen; hr = DSOUND_ReopenDevice(device, FALSE); if (FAILED(hr)) @@ -381,13 +378,9 @@ static HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGU ZeroMemory(&device->volpan, sizeof(device->volpan)); - hr = DSOUND_PrimaryCreate(device); - if (hr == DS_OK) { - device->thread_finished = CreateEventW(0, 0, 0, 0); - device->thread = CreateThread(0, 0, DSOUND_mixthread, device, 0, 0); - SetThreadPriority(device->thread, THREAD_PRIORITY_TIME_CRITICAL); - } else - WARN("DSOUND_PrimaryCreate failed: %08x\n", hr); + device->thread_finished = CreateEventW(0, 0, 0, 0); + device->thread = CreateThread(0, 0, DSOUND_mixthread, device, 0, 0); + SetThreadPriority(device->thread, THREAD_PRIORITY_TIME_CRITICAL); *ppDevice = device; list_add_tail(&DSOUND_renderers, &device->entry); @@ -851,7 +844,6 @@ static HRESULT WINAPI IDirectSound8Impl_SetCooperativeLevel(IDirectSound8 *iface { IDirectSoundImpl *This = impl_from_IDirectSound8(iface); DirectSoundDevice *device = This->device; - DWORD oldlevel; HRESULT hr = S_OK; TRACE("(%p,%p,%s)\n", This, hwnd, dumpCooperativeLevel(level)); @@ -868,15 +860,10 @@ static HRESULT WINAPI IDirectSound8Impl_SetCooperativeLevel(IDirectSound8 *iface RtlAcquireResourceExclusive(&device->buffer_list_lock, TRUE); EnterCriticalSection(&device->mixlock); - oldlevel = device->priolevel; - device->priolevel = level; - if ((level == DSSCL_WRITEPRIMARY) != (oldlevel == DSSCL_WRITEPRIMARY)) { + if ((level == DSSCL_WRITEPRIMARY) != (device->priolevel == DSSCL_WRITEPRIMARY)) hr = DSOUND_ReopenDevice(device, level == DSSCL_WRITEPRIMARY); - if (FAILED(hr)) - device->priolevel = oldlevel; - else - DSOUND_PrimaryOpen(device); - } + if (SUCCEEDED(hr)) + device->priolevel = level; LeaveCriticalSection(&device->mixlock); RtlReleaseResource(&device->buffer_list_lock); return hr; diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h index 8bf9c9daae1..3da0c194530 100644 --- a/dlls/dsound/dsound_private.h +++ b/dlls/dsound/dsound_private.h @@ -100,7 +100,6 @@ struct DirectSoundDevice IMMDevice *mmdevice; IAudioClient *client; - IAudioClock *clock; IAudioStreamVolume *volume; IAudioRenderClient *render; @@ -204,13 +203,11 @@ void DSOUND_ParseSpeakerConfig(DirectSoundDevice *device) DECLSPEC_HIDDEN; /* primary.c */ -HRESULT DSOUND_PrimaryCreate(DirectSoundDevice *device) DECLSPEC_HIDDEN; HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device) DECLSPEC_HIDDEN; HRESULT DSOUND_PrimaryPlay(DirectSoundDevice *device) DECLSPEC_HIDDEN; HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device) DECLSPEC_HIDDEN; LPWAVEFORMATEX DSOUND_CopyFormat(LPCWAVEFORMATEX wfex) DECLSPEC_HIDDEN; HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave) DECLSPEC_HIDDEN; -HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device) DECLSPEC_HIDDEN; HRESULT primarybuffer_create(DirectSoundDevice *device, IDirectSoundBufferImpl **ppdsb, const DSBUFFERDESC *dsbd) DECLSPEC_HIDDEN; void primarybuffer_destroy(IDirectSoundBufferImpl *This) DECLSPEC_HIDDEN; diff --git a/dlls/dsound/primary.c b/dlls/dsound/primary.c index a5fe039e8c9..72c94758d77 100644 --- a/dlls/dsound/primary.c +++ b/dlls/dsound/primary.c @@ -197,16 +197,8 @@ static HRESULT DSOUND_WaveFormat(DirectSoundDevice *device, IAudioClient *client return S_OK; } -HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave) +static void DSOUND_ReleaseDevice(DirectSoundDevice *device) { - WAVEFORMATEX *wfx = NULL; - HRESULT hres; - REFERENCE_TIME period, buflen = 800000; - UINT32 frames; - DWORD period_ms; - - TRACE("(%p, %d)\n", device, forcewave); - if(device->client){ IAudioClient_Release(device->client); device->client = NULL; @@ -215,10 +207,6 @@ HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave) IAudioRenderClient_Release(device->render); device->render = NULL; } - if(device->clock){ - IAudioClock_Release(device->clock); - device->clock = NULL; - } if(device->volume){ IAudioStreamVolume_Release(device->volume); device->volume = NULL; @@ -229,145 +217,75 @@ HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave) device->playpos %= device->buflen; device->pad = 0; } +} - hres = IMMDevice_Activate(device->mmdevice, &IID_IAudioClient, - CLSCTX_INPROC_SERVER, NULL, (void **)&device->client); - if(FAILED(hres)) { - WARN("Activate failed: %08x\n", hres); - return hres; +static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device, WAVEFORMATEX *wfx, DWORD frames, BOOL forcewave) +{ + IDirectSoundBufferImpl** dsb = device->buffers; + LPBYTE newbuf; + DWORD new_buflen; + BOOL mixfloat = FALSE; + int i; + + TRACE("(%p)\n", device); + + new_buflen = device->buflen; + new_buflen -= new_buflen % wfx->nBlockAlign; + + if (wfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT || + (wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE && + IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)wfx)->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))) + mixfloat = TRUE; + + /* reallocate emulated primary buffer */ + if (forcewave) { + if (device->buffer) + newbuf = HeapReAlloc(GetProcessHeap(), 0, device->buffer, new_buflen); + else + newbuf = HeapAlloc(GetProcessHeap(), 0, new_buflen); + + if (!newbuf) { + ERR("failed to allocate primary buffer\n"); + return DSERR_OUTOFMEMORY; + } + FillMemory(newbuf, new_buflen, (wfx->wBitsPerSample == 8) ? 128 : 0); + } else if (!mixfloat) { + DWORD alloc_len = frames * sizeof(float); + + if (device->buffer) + newbuf = HeapReAlloc(GetProcessHeap(), 0, device->buffer, alloc_len); + else + newbuf = HeapAlloc(GetProcessHeap(), 0, alloc_len); + + if (!newbuf) { + ERR("failed to allocate primary buffer\n"); + return DSERR_OUTOFMEMORY; + } + FillMemory(newbuf, alloc_len, (wfx->wBitsPerSample == 8) ? 128 : 0); + } else { + HeapFree(GetProcessHeap(), 0, device->buffer); + newbuf = NULL; } - device->speaker_config = DSOUND_FindSpeakerConfig(device->mmdevice, 0); - - DSOUND_ParseSpeakerConfig(device); - - hres = DSOUND_WaveFormat(device, device->client, forcewave, &wfx); - if (FAILED(hres)) { - IAudioClient_Release(device->client); - device->client = NULL; - return hres; - } + device->buffer = newbuf; + device->buflen = new_buflen; HeapFree(GetProcessHeap(), 0, device->pwfx); device->pwfx = wfx; - hres = IAudioClient_Initialize(device->client, - AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST | - AUDCLNT_STREAMFLAGS_EVENTCALLBACK, buflen, 0, device->pwfx, NULL); - if(FAILED(hres)){ - IAudioClient_Release(device->client); - device->client = NULL; - WARN("Initialize failed: %08x\n", hres); - return hres; - } - IAudioClient_SetEventHandle(device->client, device->sleepev); + if (device->state == STATE_PLAYING) + device->state = STATE_STARTING; + else if (device->state == STATE_STOPPING) + device->state = STATE_STOPPED; - hres = IAudioClient_GetService(device->client, &IID_IAudioRenderClient, - (void**)&device->render); - if(FAILED(hres)){ - IAudioClient_Release(device->client); - device->client = NULL; - WARN("GetService failed: %08x\n", hres); - return hres; - } - - hres = IAudioClient_GetService(device->client, &IID_IAudioClock, - (void**)&device->clock); - if(FAILED(hres)){ - IAudioClient_Release(device->client); - IAudioRenderClient_Release(device->render); - device->client = NULL; - device->render = NULL; - WARN("GetService failed: %08x\n", hres); - return hres; - } - - hres = IAudioClient_GetService(device->client, &IID_IAudioStreamVolume, - (void**)&device->volume); - if(FAILED(hres)){ - IAudioClient_Release(device->client); - IAudioRenderClient_Release(device->render); - IAudioClock_Release(device->clock); - device->client = NULL; - device->render = NULL; - device->clock = NULL; - WARN("GetService failed: %08x\n", hres); - return hres; - } - - /* Now kick off the timer so the event fires periodically */ - hres = IAudioClient_Start(device->client); - if (FAILED(hres)) - WARN("starting failed with %08x\n", hres); - - hres = IAudioClient_GetStreamLatency(device->client, &period); - if (FAILED(hres)) { - WARN("GetStreamLatency failed with %08x\n", hres); - period = 100000; - } - period_ms = (period + 9999) / 10000; - - hres = IAudioClient_GetBufferSize(device->client, &frames); - if (FAILED(hres)) { - WARN("GetBufferSize failed with %08x\n", hres); - frames = (UINT64)device->pwfx->nSamplesPerSec * buflen / 10000000; - } - - device->fraglen = MulDiv(device->pwfx->nSamplesPerSec, period, 10000000) * device->pwfx->nBlockAlign; - device->aclen = frames * device->pwfx->nBlockAlign; - TRACE("period %u ms fraglen %u buflen %u\n", period_ms, device->fraglen, device->aclen); - - if (period_ms < 3) - device->sleeptime = 5; - else - device->sleeptime = period_ms * 5 / 2; - - return S_OK; -} - -HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device) -{ - IDirectSoundBufferImpl** dsb = device->buffers; - LPBYTE newbuf; - int i; - - TRACE("(%p)\n", device); - - /* on original windows, the buffer it set to a fixed size, no matter what the settings are. - on windows this size is always fixed (tested on win-xp) */ - if (!device->buflen) - device->buflen = ds_hel_buflen; - device->buflen -= device->buflen % device->pwfx->nBlockAlign; - - if (device->state == STATE_PLAYING) device->state = STATE_STARTING; - else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED; - - /* reallocate emulated primary buffer */ - if (device->buffer) - newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer, device->buflen); - else - newbuf = HeapAlloc(GetProcessHeap(),0, device->buflen); - - if (!newbuf) { - ERR("failed to allocate primary buffer\n"); - return DSERR_OUTOFMEMORY; - /* but the old buffer might still exist and must be re-prepared */ - } - - device->writelead = (device->pwfx->nSamplesPerSec / 100) * device->pwfx->nBlockAlign; - - device->buffer = newbuf; + device->writelead = (wfx->nSamplesPerSec / 100) * wfx->nBlockAlign; TRACE("buflen: %u, fraglen: %u\n", device->buflen, device->fraglen); - if(device->pwfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT || - (device->pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)device->pwfx)->SubFormat, - &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))) - device->normfunction = NULL; + if (!mixfloat) + device->normfunction = normfunctions[wfx->wBitsPerSample/8 - 1]; else - device->normfunction = normfunctions[device->pwfx->wBitsPerSample/8 - 1]; + device->normfunction = NULL; - FillMemory(device->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0); device->playpos = 0; for (i = 0; i < device->nrofbuffers; i++) { @@ -379,35 +297,105 @@ HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device) return DS_OK; } - -static void DSOUND_PrimaryClose(DirectSoundDevice *device) +HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave) { - HRESULT hr; + HRESULT hres; + REFERENCE_TIME period; + UINT32 frames; + DWORD period_ms; + IAudioClient *client = NULL; + IAudioRenderClient *render = NULL; + IAudioStreamVolume *volume = NULL; + DWORD fraglen; + WAVEFORMATEX *wfx = NULL; + DWORD oldspeakerconfig = device->speaker_config; - TRACE("(%p)\n", device); + TRACE("(%p, %d)\n", device, forcewave); - if(device->client){ - hr = IAudioClient_Stop(device->client); - if(FAILED(hr)) - WARN("Stop failed: %08x\n", hr); + hres = IMMDevice_Activate(device->mmdevice, &IID_IAudioClient, + CLSCTX_INPROC_SERVER, NULL, (void **)&client); + if(FAILED(hres)){ + WARN("Activate failed: %08x\n", hres); + return hres; } -} -HRESULT DSOUND_PrimaryCreate(DirectSoundDevice *device) -{ - HRESULT err = DS_OK; - TRACE("(%p)\n", device); + hres = DSOUND_WaveFormat(device, client, forcewave, &wfx); + if (FAILED(hres)) { + IAudioClient_Release(client); + return hres; + } - device->buflen = ds_hel_buflen; - err = DSOUND_PrimaryOpen(device); + hres = IAudioClient_Initialize(client, + AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST | + AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 800000, 0, wfx, NULL); + if(FAILED(hres)){ + IAudioClient_Release(client); + ERR("Initialize failed: %08x\n", hres); + return hres; + } - if (err != DS_OK) { - WARN("DSOUND_PrimaryOpen failed\n"); - return err; - } + IAudioClient_SetEventHandle(client, device->sleepev); - device->state = STATE_STOPPED; - return DS_OK; + hres = IAudioClient_GetService(client, &IID_IAudioRenderClient, (void**)&render); + if(FAILED(hres)) + goto err_service; + + hres = IAudioClient_GetService(client, &IID_IAudioStreamVolume, (void**)&volume); + if(FAILED(hres)) + goto err_service; + + /* Now kick off the timer so the event fires periodically */ + hres = IAudioClient_Start(client); + if (FAILED(hres)) { + WARN("Start failed with %08x\n", hres); + goto err; + } + hres = IAudioClient_GetStreamLatency(client, &period); + if (FAILED(hres)) { + WARN("GetStreamLatency failed with %08x\n", hres); + goto err; + } + hres = IAudioClient_GetBufferSize(client, &frames); + if (FAILED(hres)) { + WARN("GetBufferSize failed with %08x\n", hres); + goto err; + } + + period_ms = (period + 9999) / 10000; + fraglen = MulDiv(wfx->nSamplesPerSec, period, 10000000) * wfx->nBlockAlign; + TRACE("period %u ms fraglen %u buflen %u\n", period_ms, fraglen, frames * wfx->nBlockAlign); + + hres = DSOUND_PrimaryOpen(device, wfx, frames, forcewave); + if(FAILED(hres)) + goto err; + + DSOUND_ReleaseDevice(device); + device->client = client; + device->render = render; + device->volume = volume; + device->fraglen = fraglen; + device->aclen = frames * wfx->nBlockAlign; + + if (period_ms < 3) + device->sleeptime = 5; + else + device->sleeptime = period_ms * 5 / 2; + + return S_OK; + +err_service: + ERR("GetService failed: %08x\n", hres); +err: + device->speaker_config = oldspeakerconfig; + DSOUND_ParseSpeakerConfig(device); + if (volume) + IAudioStreamVolume_Release(volume); + if (render) + IAudioRenderClient_Release(render); + if (client) + IAudioClient_Release(client); + HeapFree(GetProcessHeap(), 0, wfx); + return hres; } HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device) @@ -417,8 +405,6 @@ HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device) /* **** */ EnterCriticalSection(&(device->mixlock)); - DSOUND_PrimaryClose(device); - if(device->primary && (device->primary->ref || device->primary->numIfaces)) WARN("Destroying primary buffer while references held (%u %u)\n", device->primary->ref, device->primary->numIfaces); @@ -470,10 +456,14 @@ WAVEFORMATEX *DSOUND_CopyFormat(const WAVEFORMATEX *wfex) WAVEFORMATEX *pwfx; if(wfex->wFormatTag == WAVE_FORMAT_PCM){ pwfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEX)); + if (!pwfx) + return NULL; CopyMemory(pwfx, wfex, sizeof(PCMWAVEFORMAT)); pwfx->cbSize = 0; }else{ pwfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEX) + wfex->cbSize); + if (!pwfx) + return NULL; CopyMemory(pwfx, wfex, sizeof(WAVEFORMATEX) + wfex->cbSize); } @@ -490,7 +480,6 @@ HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX passe HRESULT err = S_OK; WAVEFORMATEX *old_fmt; WAVEFORMATEXTENSIBLE *fmtex, *passed_fmtex = (WAVEFORMATEXTENSIBLE*)passed_fmt; - BOOL forced = (device->priolevel == DSSCL_WRITEPRIMARY); TRACE("(%p,%p)\n", device, passed_fmt); @@ -540,28 +529,20 @@ HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX passe fmtex->Samples.wValidBitsPerSample = fmtex->Format.wBitsPerSample; } - DSOUND_PrimaryClose(device); - - err = DSOUND_ReopenDevice(device, forced); + err = DSOUND_ReopenDevice(device, TRUE); if (FAILED(err)) { ERR("No formats could be opened\n"); - goto done; - } - - err = DSOUND_PrimaryOpen(device); - if (err != DS_OK) { - ERR("DSOUND_PrimaryOpen failed\n"); - goto done; - } - -done: - if (err != DS_OK) + HeapFree(GetProcessHeap(), 0, device->primary_pwfx); device->primary_pwfx = old_fmt; - else + } else HeapFree(GetProcessHeap(), 0, old_fmt); } else { - HeapFree(GetProcessHeap(), 0, device->primary_pwfx); - device->primary_pwfx = DSOUND_CopyFormat(passed_fmt); + WAVEFORMATEX *wfx = DSOUND_CopyFormat(passed_fmt); + if (wfx) { + HeapFree(GetProcessHeap(), 0, device->primary_pwfx); + device->primary_pwfx = wfx; + } else + err = DSERR_OUTOFMEMORY; } out: