From: Shaun Ren sren@codeweavers.com
--- dlls/sapi/mmaudio.c | 68 ++++++++++++++++++++++++++++++++++++--- dlls/sapi/tests/mmaudio.c | 56 ++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 4 deletions(-)
diff --git a/dlls/sapi/mmaudio.c b/dlls/sapi/mmaudio.c index ec9c02cb210..54b4ee12807 100644 --- a/dlls/sapi/mmaudio.c +++ b/dlls/sapi/mmaudio.c @@ -48,6 +48,7 @@ struct mmaudio enum flow_type flow; ISpObjectToken *token; UINT device_id; + WAVEFORMATEX *wfx; CRITICAL_SECTION cs; };
@@ -358,6 +359,7 @@ static ULONG WINAPI mmsysaudio_Release(ISpMMSysAudio *iface) if (!ref) { if (This->token) ISpObjectToken_Release(This->token); + heap_free(This->wfx); DeleteCriticalSection(&This->cs);
heap_free(This); @@ -450,9 +452,26 @@ static HRESULT WINAPI mmsysaudio_Clone(ISpMMSysAudio *iface, IStream **stream)
static HRESULT WINAPI mmsysaudio_GetFormat(ISpMMSysAudio *iface, GUID *format, WAVEFORMATEX **wfx) { - FIXME("(%p, %p, %p): stub.\n", iface, format, wfx); + struct mmaudio *This = impl_from_ISpMMSysAudio(iface);
- return E_NOTIMPL; + TRACE("(%p, %p, %p).\n", iface, format, wfx); + + if (!format || !wfx) + return E_POINTER; + + EnterCriticalSection(&This->cs); + + if (!(*wfx = CoTaskMemAlloc(sizeof(WAVEFORMATEX) + This->wfx->cbSize))) + { + LeaveCriticalSection(&This->cs); + return E_OUTOFMEMORY; + } + *format = SPDFID_WaveFormatEx; + memcpy(*wfx, This->wfx, sizeof(WAVEFORMATEX) + This->wfx->cbSize); + + LeaveCriticalSection(&This->cs); + + return S_OK; }
static HRESULT WINAPI mmsysaudio_SetState(ISpMMSysAudio *iface, SPAUDIOSTATE state, ULONGLONG reserved) @@ -464,9 +483,37 @@ static HRESULT WINAPI mmsysaudio_SetState(ISpMMSysAudio *iface, SPAUDIOSTATE sta
static HRESULT WINAPI mmsysaudio_SetFormat(ISpMMSysAudio *iface, const GUID *guid, const WAVEFORMATEX *wfx) { - FIXME("(%p, %s, %p): stub.\n", iface, debugstr_guid(guid), wfx); + struct mmaudio *This = impl_from_ISpMMSysAudio(iface); + MMRESULT res; + WAVEFORMATEX *new_wfx;
- return E_NOTIMPL; + TRACE("(%p, %s, %p).\n", iface, debugstr_guid(guid), wfx); + + if (!guid || !wfx || !IsEqualGUID(guid, &SPDFID_WaveFormatEx)) + return E_INVALIDARG; + + EnterCriticalSection(&This->cs); + + /* Determine whether the device supports the requested format. */ + res = waveOutOpen(NULL, This->device_id, wfx, 0, 0, WAVE_FORMAT_QUERY); + if (res != MMSYSERR_NOERROR) + { + LeaveCriticalSection(&This->cs); + return res == WAVERR_BADFORMAT ? SPERR_UNSUPPORTED_FORMAT : SPERR_GENERIC_MMSYS_ERROR; + } + + if (!(new_wfx = heap_alloc(sizeof(*wfx) + wfx->cbSize))) + { + LeaveCriticalSection(&This->cs); + return E_OUTOFMEMORY; + } + memcpy(new_wfx, wfx, sizeof(*wfx) + wfx->cbSize); + heap_free(This->wfx); + This->wfx = new_wfx; + + LeaveCriticalSection(&This->cs); + + return S_OK; }
static HRESULT WINAPI mmsysaudio_GetStatus(ISpMMSysAudio *iface, SPAUDIOSTATUS *status) @@ -642,6 +689,19 @@ static HRESULT mmaudio_create(IUnknown *outer, REFIID iid, void **obj, enum flow This->token = NULL; This->device_id = WAVE_MAPPER;
+ if (!(This->wfx = heap_alloc(sizeof(*This->wfx)))) + { + heap_free(This); + return E_OUTOFMEMORY; + } + This->wfx->wFormatTag = WAVE_FORMAT_PCM; + This->wfx->nChannels = 1; + This->wfx->nSamplesPerSec = 22050; + This->wfx->nAvgBytesPerSec = 22050 * 2; + This->wfx->nBlockAlign = 2; + This->wfx->wBitsPerSample = 16; + This->wfx->cbSize = 0; + InitializeCriticalSection(&This->cs);
hr = ISpMMSysAudio_QueryInterface(&This->ISpMMSysAudio_iface, iid, obj); diff --git a/dlls/sapi/tests/mmaudio.c b/dlls/sapi/tests/mmaudio.c index 3816c0caf9c..dc99cf53586 100644 --- a/dlls/sapi/tests/mmaudio.c +++ b/dlls/sapi/tests/mmaudio.c @@ -99,10 +99,66 @@ static void test_device_id(void) ISpMMSysAudio_Release(mmaudio); }
+static void test_formats(void) +{ + ISpMMSysAudio *mmaudio; + GUID fmtid; + WAVEFORMATEX *wfx; + WAVEFORMATEX wfx2; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_SpMMAudioOut, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpMMSysAudio, (void **)&mmaudio); + ok(hr == S_OK, "failed to create SpMMAudioOut instance: %#lx.\n", hr); + + wfx = NULL; + hr = ISpMMSysAudio_GetFormat(mmaudio, &fmtid, &wfx); + 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->nChannels == 1, "got %u.\n", wfx->nChannels); + ok(wfx->nSamplesPerSec == 22050, "got %lu.\n", wfx->nSamplesPerSec); + ok(wfx->nAvgBytesPerSec == 22050 * 2, "got %lu.\n", wfx->nAvgBytesPerSec); + ok(wfx->nBlockAlign == 2, "got %u.\n", wfx->nBlockAlign); + ok(wfx->wBitsPerSample == 16, "got %u.\n", wfx->wBitsPerSample); + ok(wfx->cbSize == 0, "got %u.\n", wfx->cbSize); + CoTaskMemFree(wfx); + + hr = ISpMMSysAudio_SetFormat(mmaudio, NULL, NULL); + ok(hr == E_INVALIDARG, "got %#lx.\n", hr); + + hr = ISpMMSysAudio_SetFormat(mmaudio, &SPDFID_Text, NULL); + ok(hr == E_INVALIDARG, "got %#lx.\n", hr); + + hr = ISpMMSysAudio_SetFormat(mmaudio, &SPDFID_WaveFormatEx, NULL); + ok(hr == E_INVALIDARG, "got %#lx.\n", hr); + + if (waveOutGetNumDevs() == 0) { + skip("no wave out devices.\n"); + ISpMMSysAudio_Release(mmaudio); + return; + } + + wfx2.wFormatTag = WAVE_FORMAT_PCM; + wfx2.nChannels = 2; + wfx2.nSamplesPerSec = 16000; + wfx2.nAvgBytesPerSec = 16000 * 2 * 2; + wfx2.nBlockAlign = 2 * 2; + wfx2.wBitsPerSample = 16; + wfx2.cbSize = 0; + + hr = ISpMMSysAudio_SetFormat(mmaudio, &SPDFID_WaveFormatEx, &wfx2); + ok(hr == S_OK, "got %#lx.\n", hr); + + ISpMMSysAudio_Release(mmaudio); +} + START_TEST(mmaudio) { CoInitialize(NULL); test_interfaces(); test_device_id(); + test_formats(); CoUninitialize(); }