From: Shaun Ren sren@codeweavers.com
--- dlls/sapi/mmaudio.c | 53 +++++++++++++++++++++++++++++++++++-- dlls/sapi/tests/mmaudio.c | 55 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 102 insertions(+), 6 deletions(-)
diff --git a/dlls/sapi/mmaudio.c b/dlls/sapi/mmaudio.c index add670ff3dc..dadd767b9a1 100644 --- a/dlls/sapi/mmaudio.c +++ b/dlls/sapi/mmaudio.c @@ -400,9 +400,58 @@ static HRESULT WINAPI mmsysaudio_Read(ISpMMSysAudio *iface, void *pv, ULONG cb,
static HRESULT WINAPI mmsysaudio_Write(ISpMMSysAudio *iface, const void *pv, ULONG cb, ULONG *cb_written) { - FIXME("(%p, %p, %lu, %p): stub.\n", iface, pv, cb, cb_written); + struct mmaudio *This = impl_from_ISpMMSysAudio(iface); + HRESULT hr = S_OK; + WAVEHDR *buf;
- return E_NOTIMPL; + TRACE("(%p, %p, %lu, %p).\n", iface, pv, cb, cb_written); + + if (This->flow != FLOW_OUT) + return STG_E_ACCESSDENIED; + + if (cb_written) + *cb_written = 0; + + EnterCriticalSection(&This->cs); + + if (This->state == SPAS_CLOSED || This->state == SPAS_STOP) + { + LeaveCriticalSection(&This->cs); + return SP_AUDIO_STOPPED; + } + + if (!(buf = heap_alloc(sizeof(WAVEHDR) + cb))) + { + LeaveCriticalSection(&This->cs); + return E_OUTOFMEMORY; + } + memcpy((char *)(buf + 1), pv, cb); + buf->lpData = (char *)(buf + 1); + buf->dwBufferLength = cb; + buf->dwFlags = 0; + + if (waveOutPrepareHeader(This->hwave.out, buf, sizeof(WAVEHDR)) != MMSYSERR_NOERROR) + { + LeaveCriticalSection(&This->cs); + heap_free(buf); + return E_FAIL; + } + + waveOutWrite(This->hwave.out, buf, sizeof(WAVEHDR)); + + EnterCriticalSection(&This->pending_cs); + ++This->pending_buf_count; + TRACE("pending_buf_count = %Iu\n", This->pending_buf_count); + LeaveCriticalSection(&This->pending_cs); + + ResetEvent(This->event); + + LeaveCriticalSection(&This->cs); + + if (cb_written) + *cb_written = cb; + + return hr; }
static HRESULT WINAPI mmsysaudio_Seek(ISpMMSysAudio *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER *new_pos) diff --git a/dlls/sapi/tests/mmaudio.c b/dlls/sapi/tests/mmaudio.c index 85a3570f490..38df432c181 100644 --- a/dlls/sapi/tests/mmaudio.c +++ b/dlls/sapi/tests/mmaudio.c @@ -163,7 +163,10 @@ static void test_audio_out(void) ISpMMSysAudio *mmaudio; GUID fmtid; WAVEFORMATEX *wfx = NULL; + WAVEFORMATEX wfx2; UINT devid; + char *buf = NULL; + ULONG written; HRESULT hr;
if (waveOutGetNumDevs() == 0) { @@ -182,6 +185,8 @@ static void test_audio_out(void) ok(hr == S_OK, "got %#lx.\n", hr); ok(IsEqualGUID(&fmtid, &SPDFID_WaveFormatEx), "got %s.\n", wine_dbgstr_guid(&fmtid)); ok(wfx != NULL, "wfx == NULL.\n"); + ok(wfx->wFormatTag == WAVE_FORMAT_PCM, "got %u.\n", wfx->wFormatTag); + ok(wfx->cbSize == 0, "got %u.\n", wfx->cbSize);
hr = ISpMMSysAudio_SetFormat(mmaudio, &fmtid, wfx); ok(hr == S_OK, "got %#lx.\n", hr); @@ -201,10 +206,12 @@ static void test_audio_out(void) hr = ISpMMSysAudio_SetFormat(mmaudio, &fmtid, wfx); ok(hr == S_OK, "got %#lx.\n", hr);
- wfx->nChannels = wfx->nChannels == 1 ? 2 : 1; - wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nChannels * wfx->wBitsPerSample / 8; - wfx->nBlockAlign = wfx->nChannels * wfx->wBitsPerSample / 8; - hr = ISpMMSysAudio_SetFormat(mmaudio, &fmtid, wfx); + memcpy(&wfx2, wfx, sizeof(wfx2)); + wfx2.nChannels = wfx->nChannels == 1 ? 2 : 1; + wfx2.nAvgBytesPerSec = wfx2.nSamplesPerSec * wfx2.nChannels * wfx2.wBitsPerSample / 8; + wfx2.nBlockAlign = wfx2.nChannels * wfx2.wBitsPerSample / 8; + + hr = ISpMMSysAudio_SetFormat(mmaudio, &fmtid, &wfx2); ok(hr == SPERR_DEVICE_BUSY, "got %#lx.\n", hr);
devid = 0xdeadbeef; @@ -215,7 +222,47 @@ static void test_audio_out(void) hr = ISpMMSysAudio_SetState(mmaudio, SPAS_CLOSED, 0); ok(hr == S_OK, "got %#lx.\n", hr);
+ buf = calloc(1, wfx->nAvgBytesPerSec); + ok(buf != NULL, "failed to allocate buffer.\n"); + + hr = ISpMMSysAudio_Write(mmaudio, buf, wfx->nAvgBytesPerSec, NULL); + ok(hr == SP_AUDIO_STOPPED, "got %#lx.\n", hr); + + hr = ISpMMSysAudio_SetState(mmaudio, SPAS_STOP, 0); + todo_wine ok(hr == S_OK, "got %#lx.\n", hr); + if (hr == S_OK) + { + hr = ISpMMSysAudio_Write(mmaudio, buf, wfx->nAvgBytesPerSec, NULL); + ok(hr == SP_AUDIO_STOPPED, "got %#lx.\n", hr); + } + + hr = ISpMMSysAudio_SetState(mmaudio, SPAS_CLOSED, 0); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = ISpMMSysAudio_SetState(mmaudio, SPAS_RUN, 0); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = ISpMMSysAudio_Write(mmaudio, buf, wfx->nAvgBytesPerSec, NULL); + ok(hr == S_OK, "got %#lx.\n", hr); + + Sleep(200); + + hr = ISpMMSysAudio_SetState(mmaudio, SPAS_CLOSED, 0); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = ISpMMSysAudio_SetState(mmaudio, SPAS_RUN, 0); + ok(hr == S_OK, "got %#lx.\n", hr); + + written = 0xdeadbeef; + hr = ISpMMSysAudio_Write(mmaudio, buf, wfx->nAvgBytesPerSec * 200 / 1000, &written); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(written == wfx->nAvgBytesPerSec * 200 / 1000, "got %lu.\n", written); + + hr = ISpMMSysAudio_SetState(mmaudio, SPAS_CLOSED, 0); + ok(hr == S_OK, "got %#lx.\n", hr); + CoTaskMemFree(wfx); + free(buf); ISpMMSysAudio_Release(mmaudio); }