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
32 #include "wine/debug.h"
34 #include "sapi_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(sapi
);
38 enum flow_type
{ FLOW_IN
, FLOW_OUT
};
42 ISpEventSource ISpEventSource_iface
;
43 ISpEventSink ISpEventSink_iface
;
44 ISpObjectWithToken ISpObjectWithToken_iface
;
45 ISpMMSysAudio ISpMMSysAudio_iface
;
49 ISpObjectToken
*token
;
52 static inline struct mmaudio
*impl_from_ISpEventSource(ISpEventSource
*iface
)
54 return CONTAINING_RECORD(iface
, struct mmaudio
, ISpEventSource_iface
);
57 static inline struct mmaudio
*impl_from_ISpEventSink(ISpEventSink
*iface
)
59 return CONTAINING_RECORD(iface
, struct mmaudio
, ISpEventSink_iface
);
62 static inline struct mmaudio
*impl_from_ISpObjectWithToken(ISpObjectWithToken
*iface
)
64 return CONTAINING_RECORD(iface
, struct mmaudio
, ISpObjectWithToken_iface
);
67 static inline struct mmaudio
*impl_from_ISpMMSysAudio(ISpMMSysAudio
*iface
)
69 return CONTAINING_RECORD(iface
, struct mmaudio
, ISpMMSysAudio_iface
);
72 static HRESULT WINAPI
event_source_QueryInterface(ISpEventSource
*iface
, REFIID iid
, void **obj
)
74 struct mmaudio
*This
= impl_from_ISpEventSource(iface
);
76 TRACE("(%p, %s, %p).\n", iface
, debugstr_guid(iid
), obj
);
78 return ISpMMSysAudio_QueryInterface(&This
->ISpMMSysAudio_iface
, iid
, obj
);
81 static ULONG WINAPI
event_source_AddRef(ISpEventSource
*iface
)
83 struct mmaudio
*This
= impl_from_ISpEventSource(iface
);
85 TRACE("(%p).\n", iface
);
87 return ISpMMSysAudio_AddRef(&This
->ISpMMSysAudio_iface
);
90 static ULONG WINAPI
event_source_Release(ISpEventSource
*iface
)
92 struct mmaudio
*This
= impl_from_ISpEventSource(iface
);
94 TRACE("(%p).\n", iface
);
96 return ISpMMSysAudio_Release(&This
->ISpMMSysAudio_iface
);
99 static HRESULT WINAPI
event_source_SetNotifySink(ISpEventSource
*iface
, ISpNotifySink
*sink
)
101 FIXME("(%p, %p): stub.\n", iface
, sink
);
106 static HRESULT WINAPI
event_source_SetNotifyWindowMessage(ISpEventSource
*iface
, HWND hwnd
,
107 UINT msg
, WPARAM wparam
, LPARAM lparam
)
109 FIXME("(%p, %p, %u, %Ix, %Ix): stub.\n", iface
, hwnd
, msg
, wparam
, lparam
);
114 static HRESULT WINAPI
event_source_SetNotifyCallbackFunction(ISpEventSource
*iface
, SPNOTIFYCALLBACK
*callback
,
115 WPARAM wparam
, LPARAM lparam
)
117 FIXME("(%p, %p, %Ix, %Ix): stub.\n", iface
, callback
, wparam
, lparam
);
122 static HRESULT WINAPI
event_source_SetNotifyCallbackInterface(ISpEventSource
*iface
, ISpNotifyCallback
*callback
,
123 WPARAM wparam
, LPARAM lparam
)
125 FIXME("(%p, %p, %Ix, %Ix): stub.\n", iface
, callback
, wparam
, lparam
);
130 static HRESULT WINAPI
event_source_SetNotifyWin32Event(ISpEventSource
*iface
)
132 FIXME("(%p): stub.\n", iface
);
137 static HRESULT WINAPI
event_source_WaitForNotifyEvent(ISpEventSource
*iface
, DWORD milliseconds
)
139 FIXME("(%p, %ld): stub.\n", iface
, milliseconds
);
144 static HANDLE WINAPI
event_source_GetNotifyEventHandle(ISpEventSource
*iface
)
146 FIXME("(%p): stub.\n", iface
);
151 static HRESULT WINAPI
event_source_SetInterest(ISpEventSource
*iface
, ULONGLONG event
, ULONGLONG queued
)
153 FIXME("(%p, %s, %s): stub.\n", iface
, wine_dbgstr_longlong(event
), wine_dbgstr_longlong(queued
));
158 static HRESULT WINAPI
event_source_GetEvents(ISpEventSource
*iface
, ULONG count
, SPEVENT
*array
, ULONG
*fetched
)
160 FIXME("(%p, %lu, %p, %p): stub.\n", iface
, count
, array
, fetched
);
165 static HRESULT WINAPI
event_source_GetInfo(ISpEventSource
*iface
, SPEVENTSOURCEINFO
*info
)
167 FIXME("(%p, %p): stub.\n", iface
, info
);
172 static const ISpEventSourceVtbl event_source_vtbl
=
174 event_source_QueryInterface
,
176 event_source_Release
,
177 event_source_SetNotifySink
,
178 event_source_SetNotifyWindowMessage
,
179 event_source_SetNotifyCallbackFunction
,
180 event_source_SetNotifyCallbackInterface
,
181 event_source_SetNotifyWin32Event
,
182 event_source_WaitForNotifyEvent
,
183 event_source_GetNotifyEventHandle
,
184 event_source_SetInterest
,
185 event_source_GetEvents
,
189 static HRESULT WINAPI
event_sink_QueryInterface(ISpEventSink
*iface
, REFIID iid
, void **obj
)
191 struct mmaudio
*This
= impl_from_ISpEventSink(iface
);
193 TRACE("(%p, %s, %p).\n", iface
, debugstr_guid(iid
), obj
);
195 return ISpMMSysAudio_QueryInterface(&This
->ISpMMSysAudio_iface
, iid
, obj
);
198 static ULONG WINAPI
event_sink_AddRef(ISpEventSink
*iface
)
200 struct mmaudio
*This
= impl_from_ISpEventSink(iface
);
202 TRACE("(%p).\n", iface
);
204 return ISpMMSysAudio_AddRef(&This
->ISpMMSysAudio_iface
);
207 static ULONG WINAPI
event_sink_Release(ISpEventSink
*iface
)
209 struct mmaudio
*This
= impl_from_ISpEventSink(iface
);
211 TRACE("(%p).\n", iface
);
213 return ISpMMSysAudio_Release(&This
->ISpMMSysAudio_iface
);
216 static HRESULT WINAPI
event_sink_AddEvents(ISpEventSink
*iface
, const SPEVENT
*events
, ULONG count
)
218 FIXME("(%p, %p, %lu).\n", iface
, events
, count
);
223 static HRESULT WINAPI
event_sink_GetEventInterest(ISpEventSink
*iface
, ULONGLONG
*interest
)
225 FIXME("(%p, %p).\n", iface
, interest
);
230 static const ISpEventSinkVtbl event_sink_vtbl
=
232 event_sink_QueryInterface
,
235 event_sink_AddEvents
,
236 event_sink_GetEventInterest
239 static HRESULT WINAPI
objwithtoken_QueryInterface(ISpObjectWithToken
*iface
, REFIID iid
, void **obj
)
241 struct mmaudio
*This
= impl_from_ISpObjectWithToken(iface
);
243 TRACE("(%p, %s, %p).\n", iface
, debugstr_guid(iid
), obj
);
245 return ISpMMSysAudio_QueryInterface(&This
->ISpMMSysAudio_iface
, iid
, obj
);
248 static ULONG WINAPI
objwithtoken_AddRef(ISpObjectWithToken
*iface
)
250 struct mmaudio
*This
= impl_from_ISpObjectWithToken(iface
);
252 TRACE("(%p).\n", iface
);
254 return ISpMMSysAudio_AddRef(&This
->ISpMMSysAudio_iface
);
257 static ULONG WINAPI
objwithtoken_Release(ISpObjectWithToken
*iface
)
259 struct mmaudio
*This
= impl_from_ISpObjectWithToken(iface
);
261 TRACE("(%p).\n", iface
);
263 return ISpMMSysAudio_Release(&This
->ISpMMSysAudio_iface
);
266 static HRESULT WINAPI
objwithtoken_SetObjectToken(ISpObjectWithToken
*iface
, ISpObjectToken
*token
)
268 struct mmaudio
*This
= impl_from_ISpObjectWithToken(iface
);
270 FIXME("(%p, %p): semi-stub.\n", iface
, token
);
275 return SPERR_ALREADY_INITIALIZED
;
281 static HRESULT WINAPI
objwithtoken_GetObjectToken(ISpObjectWithToken
*iface
, ISpObjectToken
**token
)
283 struct mmaudio
*This
= impl_from_ISpObjectWithToken(iface
);
285 TRACE("(%p, %p).\n", iface
, token
);
290 *token
= This
->token
;
293 ISpObjectToken_AddRef(*token
);
300 static const ISpObjectWithTokenVtbl objwithtoken_vtbl
=
302 objwithtoken_QueryInterface
,
304 objwithtoken_Release
,
305 objwithtoken_SetObjectToken
,
306 objwithtoken_GetObjectToken
309 static HRESULT WINAPI
mmsysaudio_QueryInterface(ISpMMSysAudio
*iface
, REFIID iid
, void **obj
)
311 struct mmaudio
*This
= impl_from_ISpMMSysAudio(iface
);
313 TRACE("(%p, %s, %p).\n", iface
, debugstr_guid(iid
), obj
);
315 if (IsEqualIID(iid
, &IID_IUnknown
) ||
316 IsEqualIID(iid
, &IID_ISequentialStream
) ||
317 IsEqualIID(iid
, &IID_IStream
) ||
318 IsEqualIID(iid
, &IID_ISpStreamFormat
) ||
319 IsEqualIID(iid
, &IID_ISpAudio
) ||
320 IsEqualIID(iid
, &IID_ISpMMSysAudio
))
321 *obj
= &This
->ISpMMSysAudio_iface
;
322 else if (IsEqualIID(iid
, &IID_ISpEventSource
))
323 *obj
= &This
->ISpEventSource_iface
;
324 else if (IsEqualIID(iid
, &IID_ISpEventSink
))
325 *obj
= &This
->ISpEventSink_iface
;
326 else if (IsEqualIID(iid
, &IID_ISpObjectWithToken
))
327 *obj
= &This
->ISpObjectWithToken_iface
;
331 FIXME("interface %s not implemented.\n", debugstr_guid(iid
));
332 return E_NOINTERFACE
;
335 IUnknown_AddRef((IUnknown
*)*obj
);
339 static ULONG WINAPI
mmsysaudio_AddRef(ISpMMSysAudio
*iface
)
341 struct mmaudio
*This
= impl_from_ISpMMSysAudio(iface
);
342 ULONG ref
= InterlockedIncrement(&This
->ref
);
344 TRACE("(%p): ref=%lu\n", iface
, ref
);
349 static ULONG WINAPI
mmsysaudio_Release(ISpMMSysAudio
*iface
)
351 struct mmaudio
*This
= impl_from_ISpMMSysAudio(iface
);
352 ULONG ref
= InterlockedDecrement(&This
->ref
);
354 TRACE("(%p): ref=%lu\n", iface
, ref
);
358 if (This
->token
) ISpObjectToken_Release(This
->token
);
366 static HRESULT WINAPI
mmsysaudio_Read(ISpMMSysAudio
*iface
, void *pv
, ULONG cb
, ULONG
*cb_read
)
368 FIXME("(%p, %p, %lu, %p): stub.\n", iface
, pv
, cb
, cb_read
);
373 static HRESULT WINAPI
mmsysaudio_Write(ISpMMSysAudio
*iface
, const void *pv
, ULONG cb
, ULONG
*cb_written
)
375 FIXME("(%p, %p, %lu, %p): stub.\n", iface
, pv
, cb
, cb_written
);
380 static HRESULT WINAPI
mmsysaudio_Seek(ISpMMSysAudio
*iface
, LARGE_INTEGER move
, DWORD origin
, ULARGE_INTEGER
*new_pos
)
382 FIXME("(%p, %s, %lu, %p): stub.\n", iface
, wine_dbgstr_longlong(move
.QuadPart
), origin
, new_pos
);
387 static HRESULT WINAPI
mmsysaudio_SetSize(ISpMMSysAudio
*iface
, ULARGE_INTEGER new_size
)
389 FIXME("(%p, %s): stub.\n", iface
, wine_dbgstr_longlong(new_size
.QuadPart
));
394 static HRESULT WINAPI
mmsysaudio_CopyTo(ISpMMSysAudio
*iface
, IStream
*stream
, ULARGE_INTEGER cb
,
395 ULARGE_INTEGER
*cb_read
, ULARGE_INTEGER
*cb_written
)
397 FIXME("(%p, %p, %s, %p, %p): stub.\n", iface
, stream
, wine_dbgstr_longlong(cb
.QuadPart
), cb_read
, cb_written
);
402 static HRESULT WINAPI
mmsysaudio_Commit(ISpMMSysAudio
*iface
, DWORD flags
)
404 FIXME("(%p, %#lx): stub.\n", iface
, flags
);
409 static HRESULT WINAPI
mmsysaudio_Revert(ISpMMSysAudio
*iface
)
411 FIXME("(%p).\n", iface
);
416 static HRESULT WINAPI
mmsysaudio_LockRegion(ISpMMSysAudio
*iface
, ULARGE_INTEGER offset
, ULARGE_INTEGER cb
,
419 FIXME("(%p, %s, %s, %#lx): stub.\n", iface
, wine_dbgstr_longlong(offset
.QuadPart
),
420 wine_dbgstr_longlong(cb
.QuadPart
), lock_type
);
425 static HRESULT WINAPI
mmsysaudio_UnlockRegion(ISpMMSysAudio
*iface
, ULARGE_INTEGER offset
, ULARGE_INTEGER cb
,
428 FIXME("(%p, %s, %s, %#lx): stub.\n", iface
, wine_dbgstr_longlong(offset
.QuadPart
),
429 wine_dbgstr_longlong(cb
.QuadPart
), lock_type
);
434 static HRESULT WINAPI
mmsysaudio_Stat(ISpMMSysAudio
*iface
, STATSTG
*statstg
, DWORD flags
)
436 FIXME("(%p, %p, %#lx): stub.\n", iface
, statstg
, flags
);
441 static HRESULT WINAPI
mmsysaudio_Clone(ISpMMSysAudio
*iface
, IStream
**stream
)
443 FIXME("(%p, %p): stub.\n", iface
, stream
);
448 static HRESULT WINAPI
mmsysaudio_GetFormat(ISpMMSysAudio
*iface
, GUID
*format
, WAVEFORMATEX
**wfx
)
450 FIXME("(%p, %p, %p): stub.\n", iface
, format
, wfx
);
455 static HRESULT WINAPI
mmsysaudio_SetState(ISpMMSysAudio
*iface
, SPAUDIOSTATE state
, ULONGLONG reserved
)
457 FIXME("(%p, %u, %s): stub.\n", iface
, state
, wine_dbgstr_longlong(reserved
));
462 static HRESULT WINAPI
mmsysaudio_SetFormat(ISpMMSysAudio
*iface
, const GUID
*guid
, const WAVEFORMATEX
*wfx
)
464 FIXME("(%p, %s, %p): stub.\n", iface
, debugstr_guid(guid
), wfx
);
469 static HRESULT WINAPI
mmsysaudio_GetStatus(ISpMMSysAudio
*iface
, SPAUDIOSTATUS
*status
)
471 FIXME("(%p, %p): stub.\n", iface
, status
);
476 static HRESULT WINAPI
mmsysaudio_SetBufferInfo(ISpMMSysAudio
*iface
, const SPAUDIOBUFFERINFO
*info
)
478 FIXME("(%p, %p): stub.\n", iface
, info
);
483 static HRESULT WINAPI
mmsysaudio_GetBufferInfo(ISpMMSysAudio
*iface
, SPAUDIOBUFFERINFO
*info
)
485 FIXME("(%p, %p): stub.\n", iface
, info
);
490 static HRESULT WINAPI
mmsysaudio_GetDefaultFormat(ISpMMSysAudio
*iface
, GUID
*guid
, WAVEFORMATEX
**wfx
)
492 FIXME("(%p, %p, %p): stub.\n", iface
, guid
, wfx
);
497 static HANDLE WINAPI
mmsysaudio_EventHandle(ISpMMSysAudio
*iface
)
499 FIXME("(%p): stub.\n", iface
);
504 static HRESULT WINAPI
mmsysaudio_GetVolumeLevel(ISpMMSysAudio
*iface
, ULONG
*level
)
506 FIXME("(%p, %p): stub.\n", iface
, level
);
511 static HRESULT WINAPI
mmsysaudio_SetVolumeLevel(ISpMMSysAudio
*iface
, ULONG level
)
513 FIXME("(%p, %lu): stub.\n", iface
, level
);
518 static HRESULT WINAPI
mmsysaudio_GetBufferNotifySize(ISpMMSysAudio
*iface
, ULONG
*size
)
520 FIXME("(%p, %p): stub.\n", iface
, size
);
525 static HRESULT WINAPI
mmsysaudio_SetBufferNotifySize(ISpMMSysAudio
*iface
, ULONG size
)
527 FIXME("(%p, %lu): stub.\n", iface
, size
);
532 static HRESULT WINAPI
mmsysaudio_GetDeviceId(ISpMMSysAudio
*iface
, UINT
*id
)
534 FIXME("(%p, %p): stub.\n", iface
, id
);
539 static HRESULT WINAPI
mmsysaudio_SetDeviceId(ISpMMSysAudio
*iface
, UINT id
)
541 FIXME("(%p, %u): stub.\n", iface
, id
);
546 static HRESULT WINAPI
mmsysaudio_GetMMHandle(ISpMMSysAudio
*iface
, void **handle
)
548 FIXME("(%p, %p): stub.\n", iface
, handle
);
553 static HRESULT WINAPI
mmsysaudio_GetLineId(ISpMMSysAudio
*iface
, UINT
*id
)
555 FIXME("(%p, %p): stub.\n", iface
, id
);
560 static HRESULT WINAPI
mmsysaudio_SetLineId(ISpMMSysAudio
*iface
, UINT id
)
562 FIXME("(%p, %u): stub.\n", iface
, id
);
567 static const ISpMMSysAudioVtbl mmsysaudio_vtbl
=
569 mmsysaudio_QueryInterface
,
579 mmsysaudio_LockRegion
,
580 mmsysaudio_UnlockRegion
,
583 mmsysaudio_GetFormat
,
585 mmsysaudio_SetFormat
,
586 mmsysaudio_GetStatus
,
587 mmsysaudio_SetBufferInfo
,
588 mmsysaudio_GetBufferInfo
,
589 mmsysaudio_GetDefaultFormat
,
590 mmsysaudio_EventHandle
,
591 mmsysaudio_GetVolumeLevel
,
592 mmsysaudio_SetVolumeLevel
,
593 mmsysaudio_GetBufferNotifySize
,
594 mmsysaudio_SetBufferNotifySize
,
595 mmsysaudio_GetDeviceId
,
596 mmsysaudio_SetDeviceId
,
597 mmsysaudio_GetMMHandle
,
598 mmsysaudio_GetLineId
,
602 static HRESULT
mmaudio_create(IUnknown
*outer
, REFIID iid
, void **obj
, enum flow_type flow
)
604 struct mmaudio
*This
;
607 if (flow
!= FLOW_OUT
)
609 FIXME("flow %d not implemented.\n", flow
);
613 if (!(This
= heap_alloc_zero(sizeof(*This
))))
614 return E_OUTOFMEMORY
;
615 This
->ISpEventSource_iface
.lpVtbl
= &event_source_vtbl
;
616 This
->ISpEventSink_iface
.lpVtbl
= &event_sink_vtbl
;
617 This
->ISpObjectWithToken_iface
.lpVtbl
= &objwithtoken_vtbl
;
618 This
->ISpMMSysAudio_iface
.lpVtbl
= &mmsysaudio_vtbl
;
624 hr
= ISpMMSysAudio_QueryInterface(&This
->ISpMMSysAudio_iface
, iid
, obj
);
626 ISpMMSysAudio_Release(&This
->ISpMMSysAudio_iface
);
630 HRESULT
mmaudio_out_create(IUnknown
*outer
, REFIID iid
, void **obj
)
632 return mmaudio_create(outer
, iid
, obj
, FLOW_OUT
);