windows.networking.hostname/tests: Add IHostNameFactory::CreateHostName() tests.
[wine.git] / dlls / sapi / mmaudio.c
blobd99bcb1367255ad077b86f0b14740410030306f0
1 /*
2 * Speech API (SAPI) winmm audio implementation.
4 * Copyright 2023 Shaun Ren for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "objbase.h"
29 #include "sapiddk.h"
30 #include "sperror.h"
32 #include "initguid.h"
34 #include "wine/debug.h"
36 #include "sapi_private.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(sapi);
40 DEFINE_GUID(SPDFID_Text, 0x7ceef9f9, 0x3d13, 0x11d2, 0x9e, 0xe7, 0x00, 0xc0, 0x4f, 0x79, 0x73, 0x96);
41 DEFINE_GUID(SPDFID_WaveFormatEx, 0xc31adbae, 0x527f, 0x4ff5, 0xa2, 0x30, 0xf6, 0x2b, 0xb6, 0x1f, 0xf7, 0x0c);
43 enum flow_type { FLOW_IN, FLOW_OUT };
45 struct mmaudio
47 ISpEventSource ISpEventSource_iface;
48 ISpEventSink ISpEventSink_iface;
49 ISpObjectWithToken ISpObjectWithToken_iface;
50 ISpMMSysAudio ISpMMSysAudio_iface;
51 LONG ref;
53 enum flow_type flow;
54 ISpObjectToken *token;
55 UINT device_id;
56 SPAUDIOSTATE state;
57 WAVEFORMATEX *wfx;
58 union
60 HWAVEIN in;
61 HWAVEOUT out;
62 } hwave;
63 HANDLE event;
64 struct async_queue queue;
65 CRITICAL_SECTION cs;
67 size_t pending_buf_count;
68 CRITICAL_SECTION pending_cs;
71 static inline struct mmaudio *impl_from_ISpEventSource(ISpEventSource *iface)
73 return CONTAINING_RECORD(iface, struct mmaudio, ISpEventSource_iface);
76 static inline struct mmaudio *impl_from_ISpEventSink(ISpEventSink *iface)
78 return CONTAINING_RECORD(iface, struct mmaudio, ISpEventSink_iface);
81 static inline struct mmaudio *impl_from_ISpObjectWithToken(ISpObjectWithToken *iface)
83 return CONTAINING_RECORD(iface, struct mmaudio, ISpObjectWithToken_iface);
86 static inline struct mmaudio *impl_from_ISpMMSysAudio(ISpMMSysAudio *iface)
88 return CONTAINING_RECORD(iface, struct mmaudio, ISpMMSysAudio_iface);
91 static HRESULT WINAPI event_source_QueryInterface(ISpEventSource *iface, REFIID iid, void **obj)
93 struct mmaudio *This = impl_from_ISpEventSource(iface);
95 TRACE("(%p, %s, %p).\n", iface, debugstr_guid(iid), obj);
97 return ISpMMSysAudio_QueryInterface(&This->ISpMMSysAudio_iface, iid, obj);
100 static ULONG WINAPI event_source_AddRef(ISpEventSource *iface)
102 struct mmaudio *This = impl_from_ISpEventSource(iface);
104 TRACE("(%p).\n", iface);
106 return ISpMMSysAudio_AddRef(&This->ISpMMSysAudio_iface);
109 static ULONG WINAPI event_source_Release(ISpEventSource *iface)
111 struct mmaudio *This = impl_from_ISpEventSource(iface);
113 TRACE("(%p).\n", iface);
115 return ISpMMSysAudio_Release(&This->ISpMMSysAudio_iface);
118 static HRESULT WINAPI event_source_SetNotifySink(ISpEventSource *iface, ISpNotifySink *sink)
120 FIXME("(%p, %p): stub.\n", iface, sink);
122 return E_NOTIMPL;
125 static HRESULT WINAPI event_source_SetNotifyWindowMessage(ISpEventSource *iface, HWND hwnd,
126 UINT msg, WPARAM wparam, LPARAM lparam)
128 FIXME("(%p, %p, %u, %Ix, %Ix): stub.\n", iface, hwnd, msg, wparam, lparam);
130 return E_NOTIMPL;
133 static HRESULT WINAPI event_source_SetNotifyCallbackFunction(ISpEventSource *iface, SPNOTIFYCALLBACK *callback,
134 WPARAM wparam, LPARAM lparam)
136 FIXME("(%p, %p, %Ix, %Ix): stub.\n", iface, callback, wparam, lparam);
138 return E_NOTIMPL;
141 static HRESULT WINAPI event_source_SetNotifyCallbackInterface(ISpEventSource *iface, ISpNotifyCallback *callback,
142 WPARAM wparam, LPARAM lparam)
144 FIXME("(%p, %p, %Ix, %Ix): stub.\n", iface, callback, wparam, lparam);
146 return E_NOTIMPL;
149 static HRESULT WINAPI event_source_SetNotifyWin32Event(ISpEventSource *iface)
151 FIXME("(%p): stub.\n", iface);
153 return E_NOTIMPL;
156 static HRESULT WINAPI event_source_WaitForNotifyEvent(ISpEventSource *iface, DWORD milliseconds)
158 FIXME("(%p, %ld): stub.\n", iface, milliseconds);
160 return E_NOTIMPL;
163 static HANDLE WINAPI event_source_GetNotifyEventHandle(ISpEventSource *iface)
165 FIXME("(%p): stub.\n", iface);
167 return NULL;
170 static HRESULT WINAPI event_source_SetInterest(ISpEventSource *iface, ULONGLONG event, ULONGLONG queued)
172 FIXME("(%p, %s, %s): stub.\n", iface, wine_dbgstr_longlong(event), wine_dbgstr_longlong(queued));
174 return E_NOTIMPL;
177 static HRESULT WINAPI event_source_GetEvents(ISpEventSource *iface, ULONG count, SPEVENT *array, ULONG *fetched)
179 FIXME("(%p, %lu, %p, %p): stub.\n", iface, count, array, fetched);
181 return E_NOTIMPL;
184 static HRESULT WINAPI event_source_GetInfo(ISpEventSource *iface, SPEVENTSOURCEINFO *info)
186 FIXME("(%p, %p): stub.\n", iface, info);
188 return E_NOTIMPL;
191 static const ISpEventSourceVtbl event_source_vtbl =
193 event_source_QueryInterface,
194 event_source_AddRef,
195 event_source_Release,
196 event_source_SetNotifySink,
197 event_source_SetNotifyWindowMessage,
198 event_source_SetNotifyCallbackFunction,
199 event_source_SetNotifyCallbackInterface,
200 event_source_SetNotifyWin32Event,
201 event_source_WaitForNotifyEvent,
202 event_source_GetNotifyEventHandle,
203 event_source_SetInterest,
204 event_source_GetEvents,
205 event_source_GetInfo
208 static HRESULT WINAPI event_sink_QueryInterface(ISpEventSink *iface, REFIID iid, void **obj)
210 struct mmaudio *This = impl_from_ISpEventSink(iface);
212 TRACE("(%p, %s, %p).\n", iface, debugstr_guid(iid), obj);
214 return ISpMMSysAudio_QueryInterface(&This->ISpMMSysAudio_iface, iid, obj);
217 static ULONG WINAPI event_sink_AddRef(ISpEventSink *iface)
219 struct mmaudio *This = impl_from_ISpEventSink(iface);
221 TRACE("(%p).\n", iface);
223 return ISpMMSysAudio_AddRef(&This->ISpMMSysAudio_iface);
226 static ULONG WINAPI event_sink_Release(ISpEventSink *iface)
228 struct mmaudio *This = impl_from_ISpEventSink(iface);
230 TRACE("(%p).\n", iface);
232 return ISpMMSysAudio_Release(&This->ISpMMSysAudio_iface);
235 static HRESULT WINAPI event_sink_AddEvents(ISpEventSink *iface, const SPEVENT *events, ULONG count)
237 FIXME("(%p, %p, %lu).\n", iface, events, count);
239 return E_NOTIMPL;
242 static HRESULT WINAPI event_sink_GetEventInterest(ISpEventSink *iface, ULONGLONG *interest)
244 FIXME("(%p, %p).\n", iface, interest);
246 return E_NOTIMPL;
249 static const ISpEventSinkVtbl event_sink_vtbl =
251 event_sink_QueryInterface,
252 event_sink_AddRef,
253 event_sink_Release,
254 event_sink_AddEvents,
255 event_sink_GetEventInterest
258 static HRESULT WINAPI objwithtoken_QueryInterface(ISpObjectWithToken *iface, REFIID iid, void **obj)
260 struct mmaudio *This = impl_from_ISpObjectWithToken(iface);
262 TRACE("(%p, %s, %p).\n", iface, debugstr_guid(iid), obj);
264 return ISpMMSysAudio_QueryInterface(&This->ISpMMSysAudio_iface, iid, obj);
267 static ULONG WINAPI objwithtoken_AddRef(ISpObjectWithToken *iface)
269 struct mmaudio *This = impl_from_ISpObjectWithToken(iface);
271 TRACE("(%p).\n", iface);
273 return ISpMMSysAudio_AddRef(&This->ISpMMSysAudio_iface);
276 static ULONG WINAPI objwithtoken_Release(ISpObjectWithToken *iface)
278 struct mmaudio *This = impl_from_ISpObjectWithToken(iface);
280 TRACE("(%p).\n", iface);
282 return ISpMMSysAudio_Release(&This->ISpMMSysAudio_iface);
285 static HRESULT WINAPI objwithtoken_SetObjectToken(ISpObjectWithToken *iface, ISpObjectToken *token)
287 struct mmaudio *This = impl_from_ISpObjectWithToken(iface);
289 FIXME("(%p, %p): semi-stub.\n", iface, token);
291 if (!token)
292 return E_INVALIDARG;
293 if (This->token)
294 return SPERR_ALREADY_INITIALIZED;
296 This->token = token;
297 return S_OK;
300 static HRESULT WINAPI objwithtoken_GetObjectToken(ISpObjectWithToken *iface, ISpObjectToken **token)
302 struct mmaudio *This = impl_from_ISpObjectWithToken(iface);
304 TRACE("(%p, %p).\n", iface, token);
306 if (!token)
307 return E_POINTER;
309 *token = This->token;
310 if (*token)
312 ISpObjectToken_AddRef(*token);
313 return S_OK;
315 else
316 return S_FALSE;
319 static const ISpObjectWithTokenVtbl objwithtoken_vtbl =
321 objwithtoken_QueryInterface,
322 objwithtoken_AddRef,
323 objwithtoken_Release,
324 objwithtoken_SetObjectToken,
325 objwithtoken_GetObjectToken
328 static HRESULT WINAPI mmsysaudio_QueryInterface(ISpMMSysAudio *iface, REFIID iid, void **obj)
330 struct mmaudio *This = impl_from_ISpMMSysAudio(iface);
332 TRACE("(%p, %s, %p).\n", iface, debugstr_guid(iid), obj);
334 if (IsEqualIID(iid, &IID_IUnknown) ||
335 IsEqualIID(iid, &IID_ISequentialStream) ||
336 IsEqualIID(iid, &IID_IStream) ||
337 IsEqualIID(iid, &IID_ISpStreamFormat) ||
338 IsEqualIID(iid, &IID_ISpAudio) ||
339 IsEqualIID(iid, &IID_ISpMMSysAudio))
340 *obj = &This->ISpMMSysAudio_iface;
341 else if (IsEqualIID(iid, &IID_ISpEventSource))
342 *obj = &This->ISpEventSource_iface;
343 else if (IsEqualIID(iid, &IID_ISpEventSink))
344 *obj = &This->ISpEventSink_iface;
345 else if (IsEqualIID(iid, &IID_ISpObjectWithToken))
346 *obj = &This->ISpObjectWithToken_iface;
347 else
349 *obj = NULL;
350 FIXME("interface %s not implemented.\n", debugstr_guid(iid));
351 return E_NOINTERFACE;
354 IUnknown_AddRef((IUnknown *)*obj);
355 return S_OK;
358 static ULONG WINAPI mmsysaudio_AddRef(ISpMMSysAudio *iface)
360 struct mmaudio *This = impl_from_ISpMMSysAudio(iface);
361 ULONG ref = InterlockedIncrement(&This->ref);
363 TRACE("(%p): ref=%lu\n", iface, ref);
365 return ref;
368 static ULONG WINAPI mmsysaudio_Release(ISpMMSysAudio *iface)
370 struct mmaudio *This = impl_from_ISpMMSysAudio(iface);
371 ULONG ref = InterlockedDecrement(&This->ref);
373 TRACE("(%p): ref=%lu\n", iface, ref);
375 if (!ref)
377 ISpMMSysAudio_SetState(iface, SPAS_CLOSED, 0);
379 async_wait_queue_empty(&This->queue, INFINITE);
380 async_cancel_queue(&This->queue);
382 if (This->token) ISpObjectToken_Release(This->token);
383 heap_free(This->wfx);
384 CloseHandle(This->event);
385 DeleteCriticalSection(&This->pending_cs);
386 DeleteCriticalSection(&This->cs);
388 heap_free(This);
391 return ref;
394 static HRESULT WINAPI mmsysaudio_Read(ISpMMSysAudio *iface, void *pv, ULONG cb, ULONG *cb_read)
396 FIXME("(%p, %p, %lu, %p): stub.\n", iface, pv, cb, cb_read);
398 return E_NOTIMPL;
401 static HRESULT WINAPI mmsysaudio_Write(ISpMMSysAudio *iface, const void *pv, ULONG cb, ULONG *cb_written)
403 struct mmaudio *This = impl_from_ISpMMSysAudio(iface);
404 HRESULT hr = S_OK;
405 WAVEHDR *buf;
407 TRACE("(%p, %p, %lu, %p).\n", iface, pv, cb, cb_written);
409 if (This->flow != FLOW_OUT)
410 return STG_E_ACCESSDENIED;
412 if (cb_written)
413 *cb_written = 0;
415 EnterCriticalSection(&This->cs);
417 if (This->state == SPAS_CLOSED || This->state == SPAS_STOP)
419 LeaveCriticalSection(&This->cs);
420 return SP_AUDIO_STOPPED;
423 if (!(buf = heap_alloc(sizeof(WAVEHDR) + cb)))
425 LeaveCriticalSection(&This->cs);
426 return E_OUTOFMEMORY;
428 memcpy((char *)(buf + 1), pv, cb);
429 buf->lpData = (char *)(buf + 1);
430 buf->dwBufferLength = cb;
431 buf->dwFlags = 0;
433 if (waveOutPrepareHeader(This->hwave.out, buf, sizeof(WAVEHDR)) != MMSYSERR_NOERROR)
435 LeaveCriticalSection(&This->cs);
436 heap_free(buf);
437 return E_FAIL;
440 waveOutWrite(This->hwave.out, buf, sizeof(WAVEHDR));
442 EnterCriticalSection(&This->pending_cs);
443 ++This->pending_buf_count;
444 TRACE("pending_buf_count = %Iu\n", This->pending_buf_count);
445 LeaveCriticalSection(&This->pending_cs);
447 ResetEvent(This->event);
449 LeaveCriticalSection(&This->cs);
451 if (cb_written)
452 *cb_written = cb;
454 return hr;
457 static HRESULT WINAPI mmsysaudio_Seek(ISpMMSysAudio *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER *new_pos)
459 FIXME("(%p, %s, %lu, %p): stub.\n", iface, wine_dbgstr_longlong(move.QuadPart), origin, new_pos);
461 return E_NOTIMPL;
464 static HRESULT WINAPI mmsysaudio_SetSize(ISpMMSysAudio *iface, ULARGE_INTEGER new_size)
466 FIXME("(%p, %s): stub.\n", iface, wine_dbgstr_longlong(new_size.QuadPart));
468 return E_NOTIMPL;
471 static HRESULT WINAPI mmsysaudio_CopyTo(ISpMMSysAudio *iface, IStream *stream, ULARGE_INTEGER cb,
472 ULARGE_INTEGER *cb_read, ULARGE_INTEGER *cb_written)
474 FIXME("(%p, %p, %s, %p, %p): stub.\n", iface, stream, wine_dbgstr_longlong(cb.QuadPart), cb_read, cb_written);
476 return E_NOTIMPL;
479 static HRESULT WINAPI mmsysaudio_Commit(ISpMMSysAudio *iface, DWORD flags)
481 FIXME("(%p, %#lx): stub.\n", iface, flags);
483 return E_NOTIMPL;
486 static HRESULT WINAPI mmsysaudio_Revert(ISpMMSysAudio *iface)
488 FIXME("(%p).\n", iface);
490 return E_NOTIMPL;
493 static HRESULT WINAPI mmsysaudio_LockRegion(ISpMMSysAudio *iface, ULARGE_INTEGER offset, ULARGE_INTEGER cb,
494 DWORD lock_type)
496 FIXME("(%p, %s, %s, %#lx): stub.\n", iface, wine_dbgstr_longlong(offset.QuadPart),
497 wine_dbgstr_longlong(cb.QuadPart), lock_type);
499 return E_NOTIMPL;
502 static HRESULT WINAPI mmsysaudio_UnlockRegion(ISpMMSysAudio *iface, ULARGE_INTEGER offset, ULARGE_INTEGER cb,
503 DWORD lock_type)
505 FIXME("(%p, %s, %s, %#lx): stub.\n", iface, wine_dbgstr_longlong(offset.QuadPart),
506 wine_dbgstr_longlong(cb.QuadPart), lock_type);
508 return E_NOTIMPL;
511 static HRESULT WINAPI mmsysaudio_Stat(ISpMMSysAudio *iface, STATSTG *statstg, DWORD flags)
513 FIXME("(%p, %p, %#lx): stub.\n", iface, statstg, flags);
515 return E_NOTIMPL;
518 static HRESULT WINAPI mmsysaudio_Clone(ISpMMSysAudio *iface, IStream **stream)
520 FIXME("(%p, %p): stub.\n", iface, stream);
522 return E_NOTIMPL;
525 static HRESULT WINAPI mmsysaudio_GetFormat(ISpMMSysAudio *iface, GUID *format, WAVEFORMATEX **wfx)
527 struct mmaudio *This = impl_from_ISpMMSysAudio(iface);
529 TRACE("(%p, %p, %p).\n", iface, format, wfx);
531 if (!format || !wfx)
532 return E_POINTER;
534 EnterCriticalSection(&This->cs);
536 if (!(*wfx = CoTaskMemAlloc(sizeof(WAVEFORMATEX) + This->wfx->cbSize)))
538 LeaveCriticalSection(&This->cs);
539 return E_OUTOFMEMORY;
541 *format = SPDFID_WaveFormatEx;
542 memcpy(*wfx, This->wfx, sizeof(WAVEFORMATEX) + This->wfx->cbSize);
544 LeaveCriticalSection(&This->cs);
546 return S_OK;
549 struct free_buf_task
551 struct async_task task;
552 struct mmaudio *audio;
553 WAVEHDR *buf;
556 static void free_out_buf_proc(struct async_task *task)
558 struct free_buf_task *fbt = (struct free_buf_task *)task;
559 size_t buf_count;
561 TRACE("(%p).\n", task);
563 waveOutUnprepareHeader(fbt->audio->hwave.out, fbt->buf, sizeof(WAVEHDR));
564 heap_free(fbt->buf);
566 EnterCriticalSection(&fbt->audio->pending_cs);
567 buf_count = --fbt->audio->pending_buf_count;
568 LeaveCriticalSection(&fbt->audio->pending_cs);
569 if (!buf_count)
570 SetEvent(fbt->audio->event);
571 TRACE("pending_buf_count = %Iu.\n", buf_count);
574 static void CALLBACK wave_out_proc(HWAVEOUT hwo, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2)
576 struct mmaudio *This = (struct mmaudio *)instance;
577 struct free_buf_task *task;
579 TRACE("(%p, %#x, %08Ix, %08Ix, %08Ix).\n", hwo, msg, instance, param1, param2);
581 switch (msg)
583 case WOM_DONE:
584 if (!(task = heap_alloc(sizeof(*task))))
586 ERR("failed to allocate free_buf_task.\n");
587 break;
589 task->task.proc = free_out_buf_proc;
590 task->audio = This;
591 task->buf = (WAVEHDR *)param1;
592 async_queue_task(&This->queue, (struct async_task *)task);
593 break;
595 default:
596 break;
600 static HRESULT WINAPI mmsysaudio_SetState(ISpMMSysAudio *iface, SPAUDIOSTATE state, ULONGLONG reserved)
602 struct mmaudio *This = impl_from_ISpMMSysAudio(iface);
603 HRESULT hr = S_OK;
605 TRACE("(%p, %u, %s).\n", iface, state, wine_dbgstr_longlong(reserved));
607 if (state != SPAS_CLOSED && state != SPAS_RUN)
609 FIXME("state %#x not implemented.\n", state);
610 return E_NOTIMPL;
613 EnterCriticalSection(&This->cs);
615 if (This->state == state)
616 goto done;
618 if (This->state == SPAS_CLOSED)
620 if (FAILED(hr = async_start_queue(&This->queue)))
622 ERR("Failed to start async queue: %#lx.\n", hr);
623 goto done;
626 if (waveOutOpen(&This->hwave.out, This->device_id, This->wfx, (DWORD_PTR)wave_out_proc,
627 (DWORD_PTR)This, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
629 hr = SPERR_GENERIC_MMSYS_ERROR;
630 goto done;
634 if (state == SPAS_CLOSED && This->state != SPAS_CLOSED)
636 waveOutReset(This->hwave.out);
637 /* Wait until all buffers are freed. */
638 WaitForSingleObject(This->event, INFINITE);
640 if (waveOutClose(This->hwave.out) != MMSYSERR_NOERROR)
642 hr = SPERR_GENERIC_MMSYS_ERROR;
643 goto done;
647 This->state = state;
649 done:
650 LeaveCriticalSection(&This->cs);
651 return hr;
654 static HRESULT WINAPI mmsysaudio_SetFormat(ISpMMSysAudio *iface, const GUID *guid, const WAVEFORMATEX *wfx)
656 struct mmaudio *This = impl_from_ISpMMSysAudio(iface);
657 MMRESULT res;
658 WAVEFORMATEX *new_wfx;
660 TRACE("(%p, %s, %p).\n", iface, debugstr_guid(guid), wfx);
662 if (!guid || !wfx || !IsEqualGUID(guid, &SPDFID_WaveFormatEx))
663 return E_INVALIDARG;
665 EnterCriticalSection(&This->cs);
667 if (!memcmp(wfx, This->wfx, sizeof(*wfx)) && !memcmp(wfx + 1, This->wfx + 1, wfx->cbSize))
669 LeaveCriticalSection(&This->cs);
670 return S_OK;
673 if (This->state != SPAS_CLOSED)
675 LeaveCriticalSection(&This->cs);
676 return SPERR_DEVICE_BUSY;
679 /* Determine whether the device supports the requested format. */
680 res = waveOutOpen(NULL, This->device_id, wfx, 0, 0, WAVE_FORMAT_QUERY);
681 if (res != MMSYSERR_NOERROR)
683 LeaveCriticalSection(&This->cs);
684 return res == WAVERR_BADFORMAT ? SPERR_UNSUPPORTED_FORMAT : SPERR_GENERIC_MMSYS_ERROR;
687 if (!(new_wfx = heap_alloc(sizeof(*wfx) + wfx->cbSize)))
689 LeaveCriticalSection(&This->cs);
690 return E_OUTOFMEMORY;
692 memcpy(new_wfx, wfx, sizeof(*wfx) + wfx->cbSize);
693 heap_free(This->wfx);
694 This->wfx = new_wfx;
696 LeaveCriticalSection(&This->cs);
698 return S_OK;
701 static HRESULT WINAPI mmsysaudio_GetStatus(ISpMMSysAudio *iface, SPAUDIOSTATUS *status)
703 FIXME("(%p, %p): stub.\n", iface, status);
705 return E_NOTIMPL;
708 static HRESULT WINAPI mmsysaudio_SetBufferInfo(ISpMMSysAudio *iface, const SPAUDIOBUFFERINFO *info)
710 FIXME("(%p, %p): stub.\n", iface, info);
712 return E_NOTIMPL;
715 static HRESULT WINAPI mmsysaudio_GetBufferInfo(ISpMMSysAudio *iface, SPAUDIOBUFFERINFO *info)
717 FIXME("(%p, %p): stub.\n", iface, info);
719 return E_NOTIMPL;
722 static HRESULT WINAPI mmsysaudio_GetDefaultFormat(ISpMMSysAudio *iface, GUID *guid, WAVEFORMATEX **wfx)
724 FIXME("(%p, %p, %p): stub.\n", iface, guid, wfx);
726 return E_NOTIMPL;
729 static HANDLE WINAPI mmsysaudio_EventHandle(ISpMMSysAudio *iface)
731 struct mmaudio *This = impl_from_ISpMMSysAudio(iface);
733 TRACE("(%p).\n", iface);
735 return This->event;
738 static HRESULT WINAPI mmsysaudio_GetVolumeLevel(ISpMMSysAudio *iface, ULONG *level)
740 FIXME("(%p, %p): stub.\n", iface, level);
742 return E_NOTIMPL;
745 static HRESULT WINAPI mmsysaudio_SetVolumeLevel(ISpMMSysAudio *iface, ULONG level)
747 FIXME("(%p, %lu): stub.\n", iface, level);
749 return E_NOTIMPL;
752 static HRESULT WINAPI mmsysaudio_GetBufferNotifySize(ISpMMSysAudio *iface, ULONG *size)
754 FIXME("(%p, %p): stub.\n", iface, size);
756 return E_NOTIMPL;
759 static HRESULT WINAPI mmsysaudio_SetBufferNotifySize(ISpMMSysAudio *iface, ULONG size)
761 FIXME("(%p, %lu): stub.\n", iface, size);
763 return E_NOTIMPL;
766 static HRESULT WINAPI mmsysaudio_GetDeviceId(ISpMMSysAudio *iface, UINT *id)
768 struct mmaudio *This = impl_from_ISpMMSysAudio(iface);
770 TRACE("(%p, %p).\n", iface, id);
772 if (!id) return E_POINTER;
774 EnterCriticalSection(&This->cs);
775 *id = This->device_id;
776 LeaveCriticalSection(&This->cs);
778 return S_OK;
781 static HRESULT WINAPI mmsysaudio_SetDeviceId(ISpMMSysAudio *iface, UINT id)
783 struct mmaudio *This = impl_from_ISpMMSysAudio(iface);
785 TRACE("(%p, %u).\n", iface, id);
787 if (id != WAVE_MAPPER && id >= waveOutGetNumDevs())
788 return E_INVALIDARG;
790 EnterCriticalSection(&This->cs);
792 if (id == This->device_id)
794 LeaveCriticalSection(&This->cs);
795 return S_OK;
797 if (This->state != SPAS_CLOSED)
799 LeaveCriticalSection(&This->cs);
800 return SPERR_DEVICE_BUSY;
802 This->device_id = id;
804 LeaveCriticalSection(&This->cs);
806 return S_OK;
809 static HRESULT WINAPI mmsysaudio_GetMMHandle(ISpMMSysAudio *iface, void **handle)
811 FIXME("(%p, %p): stub.\n", iface, handle);
813 return E_NOTIMPL;
816 static HRESULT WINAPI mmsysaudio_GetLineId(ISpMMSysAudio *iface, UINT *id)
818 FIXME("(%p, %p): stub.\n", iface, id);
820 return E_NOTIMPL;
823 static HRESULT WINAPI mmsysaudio_SetLineId(ISpMMSysAudio *iface, UINT id)
825 FIXME("(%p, %u): stub.\n", iface, id);
827 return E_NOTIMPL;
830 static const ISpMMSysAudioVtbl mmsysaudio_vtbl =
832 mmsysaudio_QueryInterface,
833 mmsysaudio_AddRef,
834 mmsysaudio_Release,
835 mmsysaudio_Read,
836 mmsysaudio_Write,
837 mmsysaudio_Seek,
838 mmsysaudio_SetSize,
839 mmsysaudio_CopyTo,
840 mmsysaudio_Commit,
841 mmsysaudio_Revert,
842 mmsysaudio_LockRegion,
843 mmsysaudio_UnlockRegion,
844 mmsysaudio_Stat,
845 mmsysaudio_Clone,
846 mmsysaudio_GetFormat,
847 mmsysaudio_SetState,
848 mmsysaudio_SetFormat,
849 mmsysaudio_GetStatus,
850 mmsysaudio_SetBufferInfo,
851 mmsysaudio_GetBufferInfo,
852 mmsysaudio_GetDefaultFormat,
853 mmsysaudio_EventHandle,
854 mmsysaudio_GetVolumeLevel,
855 mmsysaudio_SetVolumeLevel,
856 mmsysaudio_GetBufferNotifySize,
857 mmsysaudio_SetBufferNotifySize,
858 mmsysaudio_GetDeviceId,
859 mmsysaudio_SetDeviceId,
860 mmsysaudio_GetMMHandle,
861 mmsysaudio_GetLineId,
862 mmsysaudio_SetLineId
865 static HRESULT mmaudio_create(IUnknown *outer, REFIID iid, void **obj, enum flow_type flow)
867 struct mmaudio *This;
868 HRESULT hr;
870 if (flow != FLOW_OUT)
872 FIXME("flow %d not implemented.\n", flow);
873 return E_NOTIMPL;
876 if (!(This = heap_alloc_zero(sizeof(*This))))
877 return E_OUTOFMEMORY;
878 This->ISpEventSource_iface.lpVtbl = &event_source_vtbl;
879 This->ISpEventSink_iface.lpVtbl = &event_sink_vtbl;
880 This->ISpObjectWithToken_iface.lpVtbl = &objwithtoken_vtbl;
881 This->ISpMMSysAudio_iface.lpVtbl = &mmsysaudio_vtbl;
882 This->ref = 1;
884 This->flow = flow;
885 This->token = NULL;
886 This->device_id = WAVE_MAPPER;
887 This->state = SPAS_CLOSED;
889 if (!(This->wfx = heap_alloc(sizeof(*This->wfx))))
891 heap_free(This);
892 return E_OUTOFMEMORY;
894 This->wfx->wFormatTag = WAVE_FORMAT_PCM;
895 This->wfx->nChannels = 1;
896 This->wfx->nSamplesPerSec = 22050;
897 This->wfx->nAvgBytesPerSec = 22050 * 2;
898 This->wfx->nBlockAlign = 2;
899 This->wfx->wBitsPerSample = 16;
900 This->wfx->cbSize = 0;
902 This->pending_buf_count = 0;
903 This->event = CreateEventW(NULL, TRUE, TRUE, NULL);
905 InitializeCriticalSection(&This->cs);
906 InitializeCriticalSection(&This->pending_cs);
908 hr = ISpMMSysAudio_QueryInterface(&This->ISpMMSysAudio_iface, iid, obj);
909 ISpMMSysAudio_Release(&This->ISpMMSysAudio_iface);
910 return hr;
913 HRESULT mmaudio_out_create(IUnknown *outer, REFIID iid, void **obj)
915 return mmaudio_create(outer, iid, obj, FLOW_OUT);