2 * Copyright 2011 Andrew Eikum for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define NONAMELESSUNION
29 #include <sys/types.h>
31 #include <sys/ioctl.h>
35 #include <sys/soundcard.h>
41 #include "wine/debug.h"
42 #include "wine/unicode.h"
43 #include "wine/list.h"
46 #include "mmdeviceapi.h"
50 #include "endpointvolume.h"
53 #include "audiopolicy.h"
54 #include "audioclient.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(oss
);
58 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
60 static const REFERENCE_TIME DefaultPeriod
= 200000;
61 static const REFERENCE_TIME MinimumPeriod
= 100000;
64 typedef struct ACImpl ACImpl
;
66 typedef struct _AudioSession
{
76 CRITICAL_SECTION lock
;
81 typedef struct _AudioSessionWrapper
{
82 IAudioSessionControl2 IAudioSessionControl2_iface
;
83 IChannelAudioVolume IChannelAudioVolume_iface
;
84 ISimpleAudioVolume ISimpleAudioVolume_iface
;
89 AudioSession
*session
;
90 } AudioSessionWrapper
;
93 IAudioClient IAudioClient_iface
;
94 IAudioRenderClient IAudioRenderClient_iface
;
95 IAudioCaptureClient IAudioCaptureClient_iface
;
96 IAudioClock IAudioClock_iface
;
97 IAudioClock2 IAudioClock2_iface
;
98 IAudioStreamVolume IAudioStreamVolume_iface
;
108 AUDCLNT_SHAREMODE share
;
115 BOOL initted
, playing
;
116 UINT64 written_frames
, held_frames
, tmp_buffer_frames
, inbuf_frames
;
117 UINT32 period_us
, bufsize_frames
;
118 UINT32 lcl_offs_frames
; /* offs into local_buffer where valid data starts */
120 BYTE
*local_buffer
, *tmp_buffer
;
124 CRITICAL_SECTION lock
;
126 AudioSession
*session
;
127 AudioSessionWrapper
*session_wrapper
;
134 LOCKED_NORMAL
, /* public buffer piece is from local_buffer */
135 LOCKED_WRAPPED
/* public buffer piece is in tmp_buffer */
138 static HANDLE g_timer_q
;
140 static CRITICAL_SECTION g_sessions_lock
;
141 static struct list g_sessions
= LIST_INIT(g_sessions
);
143 static AudioSessionWrapper
*AudioSessionWrapper_Create(ACImpl
*client
);
144 static HRESULT
oss_setvol(ACImpl
*This
, UINT32 index
);
146 static const IAudioClientVtbl AudioClient_Vtbl
;
147 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl
;
148 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl
;
149 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl
;
150 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl
;
151 static const IAudioClockVtbl AudioClock_Vtbl
;
152 static const IAudioClock2Vtbl AudioClock2_Vtbl
;
153 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl
;
154 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl
;
156 static inline ACImpl
*impl_from_IAudioClient(IAudioClient
*iface
)
158 return CONTAINING_RECORD(iface
, ACImpl
, IAudioClient_iface
);
161 static inline ACImpl
*impl_from_IAudioRenderClient(IAudioRenderClient
*iface
)
163 return CONTAINING_RECORD(iface
, ACImpl
, IAudioRenderClient_iface
);
166 static inline ACImpl
*impl_from_IAudioCaptureClient(IAudioCaptureClient
*iface
)
168 return CONTAINING_RECORD(iface
, ACImpl
, IAudioCaptureClient_iface
);
171 static inline AudioSessionWrapper
*impl_from_IAudioSessionControl2(IAudioSessionControl2
*iface
)
173 return CONTAINING_RECORD(iface
, AudioSessionWrapper
, IAudioSessionControl2_iface
);
176 static inline AudioSessionWrapper
*impl_from_ISimpleAudioVolume(ISimpleAudioVolume
*iface
)
178 return CONTAINING_RECORD(iface
, AudioSessionWrapper
, ISimpleAudioVolume_iface
);
181 static inline AudioSessionWrapper
*impl_from_IChannelAudioVolume(IChannelAudioVolume
*iface
)
183 return CONTAINING_RECORD(iface
, AudioSessionWrapper
, IChannelAudioVolume_iface
);
186 static inline ACImpl
*impl_from_IAudioClock(IAudioClock
*iface
)
188 return CONTAINING_RECORD(iface
, ACImpl
, IAudioClock_iface
);
191 static inline ACImpl
*impl_from_IAudioClock2(IAudioClock2
*iface
)
193 return CONTAINING_RECORD(iface
, ACImpl
, IAudioClock2_iface
);
196 static inline ACImpl
*impl_from_IAudioStreamVolume(IAudioStreamVolume
*iface
)
198 return CONTAINING_RECORD(iface
, ACImpl
, IAudioStreamVolume_iface
);
201 BOOL WINAPI
DllMain(HINSTANCE dll
, DWORD reason
, void *reserved
)
203 if(reason
== DLL_PROCESS_ATTACH
){
204 g_timer_q
= CreateTimerQueue();
208 InitializeCriticalSection(&g_sessions_lock
);
214 HRESULT WINAPI
AUDDRV_GetEndpointIDs(EDataFlow flow
, WCHAR
***ids
, void ***keys
,
215 UINT
*num
, UINT
*def_index
)
219 static int print_once
= 0;
221 TRACE("%d %p %p %p\n", flow
, ids
, num
, def_index
);
223 mixer_fd
= open("/dev/mixer", O_RDONLY
, 0);
225 ERR("OSS /dev/mixer doesn't seem to exist\n");
226 return AUDCLNT_E_SERVICE_NOT_RUNNING
;
229 if(ioctl(mixer_fd
, SNDCTL_SYSINFO
, &sysinfo
) < 0){
233 ERR("OSS version too old, need at least OSSv4\n");
234 return AUDCLNT_E_SERVICE_NOT_RUNNING
;
237 ERR("Error getting SNDCTL_SYSINFO: %d (%s)\n", errno
, strerror(errno
));
242 TRACE("OSS sysinfo:\n");
243 TRACE("product: %s\n", sysinfo
.product
);
244 TRACE("version: %s\n", sysinfo
.version
);
245 TRACE("versionnum: %x\n", sysinfo
.versionnum
);
246 TRACE("numaudios: %d\n", sysinfo
.numaudios
);
247 TRACE("nummixers: %d\n", sysinfo
.nummixers
);
248 TRACE("numcards: %d\n", sysinfo
.numcards
);
249 TRACE("numaudioengines: %d\n", sysinfo
.numaudioengines
);
253 if(sysinfo
.numaudios
<= 0){
254 WARN("No audio devices!\n");
256 return AUDCLNT_E_SERVICE_NOT_RUNNING
;
259 *ids
= HeapAlloc(GetProcessHeap(), 0, sysinfo
.numaudios
* sizeof(WCHAR
*));
260 *keys
= HeapAlloc(GetProcessHeap(), 0, sysinfo
.numaudios
* sizeof(char *));
264 for(i
= 0; i
< sysinfo
.numaudios
; ++i
){
265 oss_audioinfo ai
= {0};
268 if(ioctl(mixer_fd
, SNDCTL_AUDIOINFO
, &ai
) < 0){
269 WARN("Error getting AUDIOINFO for dev %d: %d (%s)\n", i
, errno
,
274 if((flow
== eCapture
&& (ai
.caps
& PCM_CAP_INPUT
)) ||
275 (flow
== eRender
&& (ai
.caps
& PCM_CAP_OUTPUT
))){
278 (*keys
)[*num
] = HeapAlloc(GetProcessHeap(), 0,
279 strlen(ai
.devnode
) + 1);
281 for(i
= 0; i
< *num
; ++i
){
282 HeapFree(GetProcessHeap(), 0, (*ids
)[i
]);
283 HeapFree(GetProcessHeap(), 0, (*keys
)[i
]);
285 HeapFree(GetProcessHeap(), 0, *ids
);
286 HeapFree(GetProcessHeap(), 0, *keys
);
288 return E_OUTOFMEMORY
;
290 strcpy((*keys
)[*num
], ai
.devnode
);
292 len
= MultiByteToWideChar(CP_UNIXCP
, 0, ai
.name
, -1, NULL
, 0);
293 (*ids
)[*num
] = HeapAlloc(GetProcessHeap(), 0,
294 len
* sizeof(WCHAR
));
296 HeapFree(GetProcessHeap(), 0, (*keys
)[*num
]);
297 for(i
= 0; i
< *num
; ++i
){
298 HeapFree(GetProcessHeap(), 0, (*ids
)[i
]);
299 HeapFree(GetProcessHeap(), 0, (*keys
)[i
]);
301 HeapFree(GetProcessHeap(), 0, *ids
);
302 HeapFree(GetProcessHeap(), 0, *keys
);
304 return E_OUTOFMEMORY
;
306 MultiByteToWideChar(CP_UNIXCP
, 0, ai
.name
, -1,
309 if(ai
.caps
& PCM_CAP_DEFAULT
)
324 HRESULT WINAPI
AUDDRV_GetAudioEndpoint(char *devnode
, IMMDevice
*dev
,
325 EDataFlow dataflow
, IAudioClient
**out
)
329 TRACE("%s %p %d %p\n", devnode
, dev
, dataflow
, out
);
331 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ACImpl
));
333 return E_OUTOFMEMORY
;
335 if(dataflow
== eRender
)
336 This
->fd
= open(devnode
, O_WRONLY
, 0);
337 else if(dataflow
== eCapture
)
338 This
->fd
= open(devnode
, O_RDONLY
, 0);
340 HeapFree(GetProcessHeap(), 0, This
);
344 ERR("Unable to open device %s: %d (%s)\n", devnode
, errno
,
346 HeapFree(GetProcessHeap(), 0, This
);
347 return AUDCLNT_E_DEVICE_INVALIDATED
;
350 This
->dataflow
= dataflow
;
353 if(ioctl(This
->fd
, SNDCTL_ENGINEINFO
, &This
->ai
) < 0){
354 ERR("Unable to get audio info for device %s: %d (%s)\n", devnode
,
355 errno
, strerror(errno
));
357 HeapFree(GetProcessHeap(), 0, This
);
361 TRACE("OSS audioinfo:\n");
362 TRACE("devnode: %s\n", This
->ai
.devnode
);
363 TRACE("name: %s\n", This
->ai
.name
);
364 TRACE("busy: %x\n", This
->ai
.busy
);
365 TRACE("caps: %x\n", This
->ai
.caps
);
366 TRACE("iformats: %x\n", This
->ai
.iformats
);
367 TRACE("oformats: %x\n", This
->ai
.oformats
);
368 TRACE("enabled: %d\n", This
->ai
.enabled
);
369 TRACE("min_rate: %d\n", This
->ai
.min_rate
);
370 TRACE("max_rate: %d\n", This
->ai
.max_rate
);
371 TRACE("min_channels: %d\n", This
->ai
.min_channels
);
372 TRACE("max_channels: %d\n", This
->ai
.max_channels
);
374 This
->IAudioClient_iface
.lpVtbl
= &AudioClient_Vtbl
;
375 This
->IAudioRenderClient_iface
.lpVtbl
= &AudioRenderClient_Vtbl
;
376 This
->IAudioCaptureClient_iface
.lpVtbl
= &AudioCaptureClient_Vtbl
;
377 This
->IAudioClock_iface
.lpVtbl
= &AudioClock_Vtbl
;
378 This
->IAudioClock2_iface
.lpVtbl
= &AudioClock2_Vtbl
;
379 This
->IAudioStreamVolume_iface
.lpVtbl
= &AudioStreamVolume_Vtbl
;
381 InitializeCriticalSection(&This
->lock
);
384 IMMDevice_AddRef(This
->parent
);
386 IAudioClient_AddRef(&This
->IAudioClient_iface
);
388 *out
= &This
->IAudioClient_iface
;
393 static HRESULT WINAPI
AudioClient_QueryInterface(IAudioClient
*iface
,
394 REFIID riid
, void **ppv
)
396 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
401 if(IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IAudioClient
))
404 IUnknown_AddRef((IUnknown
*)*ppv
);
407 WARN("Unknown interface %s\n", debugstr_guid(riid
));
408 return E_NOINTERFACE
;
411 static ULONG WINAPI
AudioClient_AddRef(IAudioClient
*iface
)
413 ACImpl
*This
= impl_from_IAudioClient(iface
);
415 ref
= InterlockedIncrement(&This
->ref
);
416 TRACE("(%p) Refcount now %u\n", This
, ref
);
420 static ULONG WINAPI
AudioClient_Release(IAudioClient
*iface
)
422 ACImpl
*This
= impl_from_IAudioClient(iface
);
424 ref
= InterlockedDecrement(&This
->ref
);
425 TRACE("(%p) Refcount now %u\n", This
, ref
);
427 IAudioClient_Stop(iface
);
428 IMMDevice_Release(This
->parent
);
429 DeleteCriticalSection(&This
->lock
);
432 EnterCriticalSection(&g_sessions_lock
);
433 list_remove(&This
->entry
);
434 if(list_empty(&This
->session
->clients
)){
435 list_remove(&This
->session
->entry
);
436 DeleteCriticalSection(&This
->session
->lock
);
437 HeapFree(GetProcessHeap(), 0, This
->session
->channel_vols
);
438 HeapFree(GetProcessHeap(), 0, This
->session
);
440 LeaveCriticalSection(&g_sessions_lock
);
442 HeapFree(GetProcessHeap(), 0, This
->vols
);
443 HeapFree(GetProcessHeap(), 0, This
->local_buffer
);
444 HeapFree(GetProcessHeap(), 0, This
->tmp_buffer
);
445 CoTaskMemFree(This
->fmt
);
446 HeapFree(GetProcessHeap(), 0, This
);
451 static void dump_fmt(const WAVEFORMATEX
*fmt
)
453 TRACE("wFormatTag: 0x%x (", fmt
->wFormatTag
);
454 switch(fmt
->wFormatTag
){
455 case WAVE_FORMAT_PCM
:
456 TRACE("WAVE_FORMAT_PCM");
458 case WAVE_FORMAT_IEEE_FLOAT
:
459 TRACE("WAVE_FORMAT_IEEE_FLOAT");
461 case WAVE_FORMAT_EXTENSIBLE
:
462 TRACE("WAVE_FORMAT_EXTENSIBLE");
470 TRACE("nChannels: %u\n", fmt
->nChannels
);
471 TRACE("nSamplesPerSec: %u\n", fmt
->nSamplesPerSec
);
472 TRACE("nAvgBytesPerSec: %u\n", fmt
->nAvgBytesPerSec
);
473 TRACE("nBlockAlign: %u\n", fmt
->nBlockAlign
);
474 TRACE("wBitsPerSample: %u\n", fmt
->wBitsPerSample
);
475 TRACE("cbSize: %u\n", fmt
->cbSize
);
477 if(fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
){
478 WAVEFORMATEXTENSIBLE
*fmtex
= (void*)fmt
;
479 TRACE("dwChannelMask: %08x\n", fmtex
->dwChannelMask
);
480 TRACE("Samples: %04x\n", fmtex
->Samples
.wReserved
);
481 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex
->SubFormat
));
485 static DWORD
get_channel_mask(unsigned int channels
)
491 return SPEAKER_FRONT_CENTER
;
493 return SPEAKER_FRONT_LEFT
| SPEAKER_FRONT_RIGHT
;
495 return SPEAKER_FRONT_LEFT
| SPEAKER_FRONT_RIGHT
|
496 SPEAKER_LOW_FREQUENCY
;
498 return SPEAKER_FRONT_LEFT
| SPEAKER_FRONT_RIGHT
| SPEAKER_BACK_LEFT
|
501 return SPEAKER_FRONT_LEFT
| SPEAKER_FRONT_RIGHT
| SPEAKER_BACK_LEFT
|
502 SPEAKER_BACK_RIGHT
| SPEAKER_LOW_FREQUENCY
;
504 return SPEAKER_FRONT_LEFT
| SPEAKER_FRONT_RIGHT
| SPEAKER_BACK_LEFT
|
505 SPEAKER_BACK_RIGHT
| SPEAKER_LOW_FREQUENCY
| SPEAKER_FRONT_CENTER
;
507 return SPEAKER_FRONT_LEFT
| SPEAKER_FRONT_RIGHT
| SPEAKER_BACK_LEFT
|
508 SPEAKER_BACK_RIGHT
| SPEAKER_LOW_FREQUENCY
| SPEAKER_FRONT_CENTER
|
511 FIXME("Unknown speaker configuration: %u\n", channels
);
515 static int get_oss_format(const WAVEFORMATEX
*fmt
)
517 WAVEFORMATEXTENSIBLE
*fmtex
= (WAVEFORMATEXTENSIBLE
*)fmt
;
519 if(fmt
->wFormatTag
== WAVE_FORMAT_PCM
||
520 (fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
521 IsEqualGUID(&fmtex
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))){
522 switch(fmt
->wBitsPerSample
){
528 return AFMT_S24_PACKED
;
535 if(fmt
->wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
||
536 (fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
537 IsEqualGUID(&fmtex
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
))){
538 if(fmt
->wBitsPerSample
!= 32)
547 static WAVEFORMATEX
*clone_format(const WAVEFORMATEX
*fmt
)
552 if(fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
553 size
= sizeof(WAVEFORMATEXTENSIBLE
);
555 size
= sizeof(WAVEFORMATEX
);
557 ret
= CoTaskMemAlloc(size
);
561 memcpy(ret
, fmt
, size
);
563 ret
->cbSize
= size
- sizeof(WAVEFORMATEX
);
568 static HRESULT
setup_oss_device(ACImpl
*This
, const WAVEFORMATEX
*fmt
,
574 WAVEFORMATEXTENSIBLE
*fmtex
= (void*)fmt
;
575 WAVEFORMATEX
*closest
= NULL
;
577 tmp
= oss_format
= get_oss_format(fmt
);
579 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
580 if(ioctl(This
->fd
, SNDCTL_DSP_SETFMT
, &tmp
) < 0){
581 WARN("SETFMT failed: %d (%s)\n", errno
, strerror(errno
));
584 if(tmp
!= oss_format
){
585 TRACE("Format unsupported by this OSS version: %x\n", oss_format
);
586 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
589 closest
= clone_format(fmt
);
591 tmp
= fmt
->nSamplesPerSec
;
592 if(ioctl(This
->fd
, SNDCTL_DSP_SPEED
, &tmp
) < 0){
593 WARN("SPEED failed: %d (%s)\n", errno
, strerror(errno
));
594 CoTaskMemFree(closest
);
597 tenth
= fmt
->nSamplesPerSec
* 0.1;
598 if(tmp
> fmt
->nSamplesPerSec
+ tenth
|| tmp
< fmt
->nSamplesPerSec
- tenth
){
600 closest
->nSamplesPerSec
= tmp
;
603 tmp
= fmt
->nChannels
;
604 if(ioctl(This
->fd
, SNDCTL_DSP_CHANNELS
, &tmp
) < 0){
605 WARN("CHANNELS failed: %d (%s)\n", errno
, strerror(errno
));
606 CoTaskMemFree(closest
);
609 if(tmp
!= fmt
->nChannels
){
611 closest
->nChannels
= tmp
;
614 if(closest
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
){
615 DWORD mask
= get_channel_mask(closest
->nChannels
);
617 ((WAVEFORMATEXTENSIBLE
*)closest
)->dwChannelMask
= mask
;
619 if(fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
620 fmtex
->dwChannelMask
!= mask
)
624 if(ret
== S_OK
|| !out
){
625 CoTaskMemFree( closest
);
629 closest
->nBlockAlign
=
630 closest
->nChannels
* closest
->wBitsPerSample
/ 8;
631 closest
->nAvgBytesPerSec
=
632 closest
->nBlockAlign
* closest
->nSamplesPerSec
;
636 TRACE("returning: %08x\n", ret
);
640 static AudioSession
*create_session(const GUID
*guid
, EDataFlow flow
,
645 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(AudioSession
));
649 memcpy(&ret
->guid
, guid
, sizeof(GUID
));
651 ret
->dataflow
= flow
;
653 list_init(&ret
->clients
);
655 list_add_head(&g_sessions
, &ret
->entry
);
657 InitializeCriticalSection(&ret
->lock
);
659 ret
->channel_count
= num_channels
;
660 ret
->channel_vols
= HeapAlloc(GetProcessHeap(), 0,
661 sizeof(float) * num_channels
);
662 if(!ret
->channel_vols
){
663 HeapFree(GetProcessHeap(), 0, ret
);
667 for(; num_channels
> 0; --num_channels
)
668 ret
->channel_vols
[num_channels
- 1] = 1.f
;
670 ret
->master_vol
= 1.f
;
675 static HRESULT WINAPI
AudioClient_Initialize(IAudioClient
*iface
,
676 AUDCLNT_SHAREMODE mode
, DWORD flags
, REFERENCE_TIME duration
,
677 REFERENCE_TIME period
, const WAVEFORMATEX
*fmt
,
678 const GUID
*sessionguid
)
680 ACImpl
*This
= impl_from_IAudioClient(iface
);
684 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This
, mode
, flags
,
685 wine_dbgstr_longlong(duration
), wine_dbgstr_longlong(period
), fmt
, debugstr_guid(sessionguid
));
692 if(mode
!= AUDCLNT_SHAREMODE_SHARED
&& mode
!= AUDCLNT_SHAREMODE_EXCLUSIVE
)
693 return AUDCLNT_E_NOT_INITIALIZED
;
695 if(flags
& ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS
|
696 AUDCLNT_STREAMFLAGS_LOOPBACK
|
697 AUDCLNT_STREAMFLAGS_EVENTCALLBACK
|
698 AUDCLNT_STREAMFLAGS_NOPERSIST
|
699 AUDCLNT_STREAMFLAGS_RATEADJUST
|
700 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED
|
701 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE
|
702 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED
)){
703 TRACE("Unknown flags: %08x\n", flags
);
707 EnterCriticalSection(&This
->lock
);
710 LeaveCriticalSection(&This
->lock
);
711 return AUDCLNT_E_ALREADY_INITIALIZED
;
714 hr
= setup_oss_device(This
, fmt
, NULL
);
716 LeaveCriticalSection(&This
->lock
);
717 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
720 LeaveCriticalSection(&This
->lock
);
725 if(ioctl(This
->fd
, SNDCTL_DSP_SETTRIGGER
, &mask
) < 0){
726 LeaveCriticalSection(&This
->lock
);
727 WARN("SETTRIGGER failed: %d (%s)\n", errno
, strerror(errno
));
731 mask
= (100 << 8) | 100;
732 if(ioctl(This
->fd
, SNDCTL_DSP_SETPLAYVOL
, &mask
) < 0)
733 WARN("SETPLAYVOL failed: %d (%s)\n", errno
, strerror(errno
));
735 This
->fmt
= clone_format(fmt
);
737 LeaveCriticalSection(&This
->lock
);
738 return E_OUTOFMEMORY
;
742 This
->period_us
= period
/ 10;
744 This
->period_us
= DefaultPeriod
/ 10;
746 This
->bufsize_frames
= ceil(fmt
->nSamplesPerSec
* (duration
/ 10000000.));
747 This
->local_buffer
= HeapAlloc(GetProcessHeap(), 0,
748 This
->bufsize_frames
* fmt
->nBlockAlign
);
749 if(!This
->local_buffer
){
750 CoTaskMemFree(This
->fmt
);
752 LeaveCriticalSection(&This
->lock
);
753 return E_OUTOFMEMORY
;
756 This
->vols
= HeapAlloc(GetProcessHeap(), 0, fmt
->nChannels
* sizeof(float));
758 CoTaskMemFree(This
->fmt
);
760 LeaveCriticalSection(&This
->lock
);
761 return E_OUTOFMEMORY
;
764 for(i
= 0; i
< fmt
->nChannels
; ++i
)
770 EnterCriticalSection(&g_sessions_lock
);
772 if(!sessionguid
|| IsEqualGUID(sessionguid
, &GUID_NULL
)){
773 This
->session
= create_session(&GUID_NULL
, This
->dataflow
,
776 LeaveCriticalSection(&g_sessions_lock
);
777 HeapFree(GetProcessHeap(), 0, This
->vols
);
779 CoTaskMemFree(This
->fmt
);
781 LeaveCriticalSection(&This
->lock
);
782 return E_OUTOFMEMORY
;
785 AudioSession
*session
;
787 LIST_FOR_EACH_ENTRY(session
, &g_sessions
, AudioSession
, entry
){
788 if(IsEqualGUID(sessionguid
, &session
->guid
) &&
789 This
->dataflow
== session
->dataflow
){
790 if(session
->channel_count
!= fmt
->nChannels
){
791 LeaveCriticalSection(&g_sessions_lock
);
792 HeapFree(GetProcessHeap(), 0, This
->vols
);
794 CoTaskMemFree(This
->fmt
);
796 LeaveCriticalSection(&This
->lock
);
799 This
->session
= session
;
804 This
->session
= create_session(sessionguid
, This
->dataflow
,
807 LeaveCriticalSection(&g_sessions_lock
);
808 HeapFree(GetProcessHeap(), 0, This
->vols
);
810 CoTaskMemFree(This
->fmt
);
812 LeaveCriticalSection(&This
->lock
);
813 return E_OUTOFMEMORY
;
818 list_add_tail(&This
->session
->clients
, &This
->entry
);
820 LeaveCriticalSection(&g_sessions_lock
);
822 This
->initted
= TRUE
;
824 oss_setvol(This
, -1);
826 LeaveCriticalSection(&This
->lock
);
831 static HRESULT WINAPI
AudioClient_GetBufferSize(IAudioClient
*iface
,
834 ACImpl
*This
= impl_from_IAudioClient(iface
);
836 TRACE("(%p)->(%p)\n", This
, frames
);
841 EnterCriticalSection(&This
->lock
);
844 LeaveCriticalSection(&This
->lock
);
845 return AUDCLNT_E_NOT_INITIALIZED
;
848 *frames
= This
->bufsize_frames
;
850 LeaveCriticalSection(&This
->lock
);
855 static HRESULT WINAPI
AudioClient_GetStreamLatency(IAudioClient
*iface
,
856 REFERENCE_TIME
*latency
)
858 ACImpl
*This
= impl_from_IAudioClient(iface
);
860 TRACE("(%p)->(%p)\n", This
, latency
);
865 EnterCriticalSection(&This
->lock
);
868 LeaveCriticalSection(&This
->lock
);
869 return AUDCLNT_E_NOT_INITIALIZED
;
872 if(This
->dataflow
== eRender
){
876 if(ioctl(This
->fd
, SNDCTL_DSP_GETODELAY
, &delay_bytes
) < 0){
877 LeaveCriticalSection(&This
->lock
);
878 WARN("GETODELAY failed: %d (%s)\n", errno
, strerror(errno
));
882 delay_s
= delay_bytes
/ (double)(This
->fmt
->nSamplesPerSec
*
883 This
->fmt
->nBlockAlign
);
885 *latency
= delay_s
* 10000000;
887 *latency
= 10000; /* OSS doesn't provide input latency */
889 LeaveCriticalSection(&This
->lock
);
894 static HRESULT WINAPI
AudioClient_GetCurrentPadding(IAudioClient
*iface
,
897 ACImpl
*This
= impl_from_IAudioClient(iface
);
900 TRACE("(%p)->(%p)\n", This
, numpad
);
905 EnterCriticalSection(&This
->lock
);
908 LeaveCriticalSection(&This
->lock
);
909 return AUDCLNT_E_NOT_INITIALIZED
;
912 if(This
->dataflow
== eRender
){
913 if(ioctl(This
->fd
, SNDCTL_DSP_GETOSPACE
, &bi
) < 0){
914 LeaveCriticalSection(&This
->lock
);
915 WARN("GETOSPACE failed: %d (%s)\n", errno
, strerror(errno
));
919 *numpad
= (bi
.fragstotal
* bi
.fragsize
- bi
.bytes
) /
920 This
->fmt
->nBlockAlign
;
922 /* when the OSS buffer has less than one fragment of data, including
923 * no data, it often reports it as some non-zero portion of a
924 * fragment. when it has more than one fragment of data, it reports
925 * it as some multiple of that portion of the fragment size.
927 * so, we have to do some ugly workarounds to report the timing
928 * as accurately as possible */
929 if(*numpad
< bi
.fragsize
/ This
->fmt
->nBlockAlign
){
930 *numpad
= This
->inbuf_frames
;
931 This
->inbuf_frames
= 0;
933 if(*numpad
< This
->inbuf_frames
)
934 This
->inbuf_frames
= *numpad
;
936 *numpad
= This
->inbuf_frames
;
938 }else if(This
->dataflow
== eCapture
){
939 if(ioctl(This
->fd
, SNDCTL_DSP_GETISPACE
, &bi
) < 0){
940 LeaveCriticalSection(&This
->lock
);
941 WARN("GETISPACE failed: %d (%s)\n", errno
, strerror(errno
));
945 if(bi
.bytes
<= bi
.fragsize
)
948 *numpad
= bi
.bytes
/ This
->fmt
->nBlockAlign
;
950 LeaveCriticalSection(&This
->lock
);
954 *numpad
+= This
->held_frames
;
956 LeaveCriticalSection(&This
->lock
);
961 static HRESULT WINAPI
AudioClient_IsFormatSupported(IAudioClient
*iface
,
962 AUDCLNT_SHAREMODE mode
, const WAVEFORMATEX
*pwfx
,
963 WAVEFORMATEX
**outpwfx
)
965 ACImpl
*This
= impl_from_IAudioClient(iface
);
968 TRACE("(%p)->(%x, %p, %p)\n", This
, mode
, pwfx
, outpwfx
);
970 if(!pwfx
|| (mode
== AUDCLNT_SHAREMODE_SHARED
&& !outpwfx
))
973 if(mode
!= AUDCLNT_SHAREMODE_SHARED
&& mode
!= AUDCLNT_SHAREMODE_EXCLUSIVE
)
976 if(pwfx
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
977 pwfx
->cbSize
< sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
))
982 EnterCriticalSection(&This
->lock
);
984 ret
= setup_oss_device(This
, pwfx
, outpwfx
);
986 LeaveCriticalSection(&This
->lock
);
991 static HRESULT WINAPI
AudioClient_GetMixFormat(IAudioClient
*iface
,
994 ACImpl
*This
= impl_from_IAudioClient(iface
);
995 WAVEFORMATEXTENSIBLE
*fmt
;
998 TRACE("(%p)->(%p)\n", This
, pwfx
);
1003 *pwfx
= HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEXTENSIBLE
));
1005 return E_OUTOFMEMORY
;
1007 fmt
= (WAVEFORMATEXTENSIBLE
*)*pwfx
;
1009 if(This
->dataflow
== eRender
)
1010 formats
= This
->ai
.oformats
;
1011 else if(This
->dataflow
== eCapture
)
1012 formats
= This
->ai
.iformats
;
1014 return E_UNEXPECTED
;
1016 fmt
->Format
.wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
1017 if(formats
& AFMT_S16_LE
){
1018 fmt
->Format
.wBitsPerSample
= 16;
1019 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
1020 }else if(formats
& AFMT_FLOAT
){
1021 fmt
->Format
.wBitsPerSample
= 32;
1022 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
1023 }else if(formats
& AFMT_U8
){
1024 fmt
->Format
.wBitsPerSample
= 8;
1025 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
1026 }else if(formats
& AFMT_S32_LE
){
1027 fmt
->Format
.wBitsPerSample
= 32;
1028 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
1029 }else if(formats
& AFMT_S24_PACKED
){
1030 fmt
->Format
.wBitsPerSample
= 24;
1031 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
1033 ERR("Didn't recognize any available OSS formats: %x\n", formats
);
1037 fmt
->Format
.nChannels
= This
->ai
.max_channels
;
1038 fmt
->Format
.nSamplesPerSec
= This
->ai
.max_rate
;
1039 fmt
->dwChannelMask
= get_channel_mask(fmt
->Format
.nChannels
);
1041 fmt
->Format
.nBlockAlign
= (fmt
->Format
.wBitsPerSample
*
1042 fmt
->Format
.nChannels
) / 8;
1043 fmt
->Format
.nAvgBytesPerSec
= fmt
->Format
.nSamplesPerSec
*
1044 fmt
->Format
.nBlockAlign
;
1046 fmt
->Samples
.wValidBitsPerSample
= fmt
->Format
.wBitsPerSample
;
1047 fmt
->Format
.cbSize
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
1054 static HRESULT WINAPI
AudioClient_GetDevicePeriod(IAudioClient
*iface
,
1055 REFERENCE_TIME
*defperiod
, REFERENCE_TIME
*minperiod
)
1057 ACImpl
*This
= impl_from_IAudioClient(iface
);
1059 TRACE("(%p)->(%p, %p)\n", This
, defperiod
, minperiod
);
1061 if(!defperiod
&& !minperiod
)
1064 EnterCriticalSection(&This
->lock
);
1067 *defperiod
= DefaultPeriod
;
1069 *minperiod
= MinimumPeriod
;
1071 LeaveCriticalSection(&This
->lock
);
1076 static void oss_write_data(ACImpl
*This
)
1079 UINT32 written_frames
;
1082 This
->local_buffer
+ (This
->lcl_offs_frames
* This
->fmt
->nBlockAlign
);
1084 if(This
->lcl_offs_frames
+ This
->held_frames
> This
->bufsize_frames
)
1085 to_write
= This
->bufsize_frames
- This
->lcl_offs_frames
;
1087 to_write
= This
->held_frames
;
1089 written
= write(This
->fd
, buf
, to_write
* This
->fmt
->nBlockAlign
);
1091 WARN("write failed: %d (%s)\n", errno
, strerror(errno
));
1094 written_frames
= written
/ This
->fmt
->nBlockAlign
;
1096 This
->lcl_offs_frames
+= written_frames
;
1097 This
->lcl_offs_frames
%= This
->bufsize_frames
;
1098 This
->held_frames
-= written_frames
;
1099 This
->inbuf_frames
+= written_frames
;
1101 if(written_frames
< to_write
){
1102 /* OSS buffer probably full */
1106 if(This
->held_frames
){
1107 /* wrapped and have some data back at the start to write */
1108 written
= write(This
->fd
, This
->local_buffer
,
1109 This
->held_frames
* This
->fmt
->nBlockAlign
);
1111 WARN("write failed: %d (%s)\n", errno
, strerror(errno
));
1114 written_frames
= written
/ This
->fmt
->nBlockAlign
;
1116 This
->lcl_offs_frames
+= written_frames
;
1117 This
->lcl_offs_frames
%= This
->bufsize_frames
;
1118 This
->held_frames
-= written_frames
;
1119 This
->inbuf_frames
+= written_frames
;
1123 static void oss_read_data(ACImpl
*This
)
1125 UINT64 pos
, readable
;
1129 if(ioctl(This
->fd
, SNDCTL_DSP_GETISPACE
, &bi
) < 0){
1130 WARN("GETISPACE failed: %d (%s)\n", errno
, strerror(errno
));
1134 pos
= (This
->held_frames
+ This
->lcl_offs_frames
) % This
->bufsize_frames
;
1135 readable
= (This
->bufsize_frames
- pos
) * This
->fmt
->nBlockAlign
;
1137 if(bi
.bytes
< readable
)
1138 readable
= bi
.bytes
;
1140 nread
= read(This
->fd
, This
->local_buffer
+ pos
* This
->fmt
->nBlockAlign
,
1143 WARN("read failed: %d (%s)\n", errno
, strerror(errno
));
1147 This
->held_frames
+= nread
/ This
->fmt
->nBlockAlign
;
1149 if(This
->held_frames
> This
->bufsize_frames
){
1150 WARN("Overflow of unread data\n");
1151 This
->lcl_offs_frames
+= This
->held_frames
;
1152 This
->lcl_offs_frames
%= This
->bufsize_frames
;
1153 This
->held_frames
= This
->bufsize_frames
;
1157 static void CALLBACK
oss_period_callback(void *user
, BOOLEAN timer
)
1159 ACImpl
*This
= user
;
1161 EnterCriticalSection(&This
->lock
);
1163 if(This
->dataflow
== eRender
)
1164 oss_write_data(This
);
1165 else if(This
->dataflow
== eCapture
)
1166 oss_read_data(This
);
1169 SetEvent(This
->event
);
1171 LeaveCriticalSection(&This
->lock
);
1174 static HRESULT WINAPI
AudioClient_Start(IAudioClient
*iface
)
1176 ACImpl
*This
= impl_from_IAudioClient(iface
);
1179 TRACE("(%p)\n", This
);
1181 EnterCriticalSection(&This
->lock
);
1184 LeaveCriticalSection(&This
->lock
);
1185 return AUDCLNT_E_NOT_INITIALIZED
;
1188 if((This
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
) && !This
->event
){
1189 LeaveCriticalSection(&This
->lock
);
1190 return AUDCLNT_E_EVENTHANDLE_NOT_SET
;
1194 LeaveCriticalSection(&This
->lock
);
1195 return AUDCLNT_E_NOT_STOPPED
;
1198 if(This
->dataflow
== eRender
)
1199 mask
= PCM_ENABLE_OUTPUT
;
1200 else if(This
->dataflow
== eCapture
)
1201 mask
= PCM_ENABLE_INPUT
;
1203 LeaveCriticalSection(&This
->lock
);
1204 return E_UNEXPECTED
;
1207 if(ioctl(This
->fd
, SNDCTL_DSP_SETTRIGGER
, &mask
) < 0){
1208 LeaveCriticalSection(&This
->lock
);
1209 WARN("SETTRIGGER failed: %d (%s)\n", errno
, strerror(errno
));
1213 if(!CreateTimerQueueTimer(&This
->timer
, g_timer_q
,
1214 oss_period_callback
, This
, 0, This
->period_us
/ 1000,
1215 WT_EXECUTEINTIMERTHREAD
))
1216 ERR("Unable to create period timer: %u\n", GetLastError());
1218 This
->playing
= TRUE
;
1220 LeaveCriticalSection(&This
->lock
);
1225 static HRESULT WINAPI
AudioClient_Stop(IAudioClient
*iface
)
1227 ACImpl
*This
= impl_from_IAudioClient(iface
);
1230 TRACE("(%p)\n", This
);
1232 EnterCriticalSection(&This
->lock
);
1235 LeaveCriticalSection(&This
->lock
);
1236 return AUDCLNT_E_NOT_INITIALIZED
;
1240 LeaveCriticalSection(&This
->lock
);
1244 if(This
->timer
&& This
->timer
!= INVALID_HANDLE_VALUE
){
1245 DeleteTimerQueueTimer(g_timer_q
, This
->timer
,
1246 INVALID_HANDLE_VALUE
);
1250 if(ioctl(This
->fd
, SNDCTL_DSP_HALT
, NULL
) < 0){
1251 LeaveCriticalSection(&This
->lock
);
1252 WARN("HALT failed: %d (%s)\n", errno
, strerror(errno
));
1257 if(ioctl(This
->fd
, SNDCTL_DSP_SETTRIGGER
, &mask
) < 0){
1258 LeaveCriticalSection(&This
->lock
);
1259 WARN("SETTRIGGER failed: %d (%s)\n", errno
, strerror(errno
));
1263 This
->playing
= FALSE
;
1265 LeaveCriticalSection(&This
->lock
);
1270 static HRESULT WINAPI
AudioClient_Reset(IAudioClient
*iface
)
1272 ACImpl
*This
= impl_from_IAudioClient(iface
);
1274 TRACE("(%p)\n", This
);
1276 EnterCriticalSection(&This
->lock
);
1279 LeaveCriticalSection(&This
->lock
);
1280 return AUDCLNT_E_NOT_INITIALIZED
;
1284 LeaveCriticalSection(&This
->lock
);
1285 return AUDCLNT_E_NOT_STOPPED
;
1288 This
->written_frames
= 0;
1289 This
->inbuf_frames
= 0;
1290 This
->held_frames
= 0;
1292 if(ioctl(This
->fd
, SNDCTL_DSP_SKIP
, NULL
) < 0)
1293 WARN("SKIP failed: %d (%s)\n", errno
, strerror(errno
));
1295 LeaveCriticalSection(&This
->lock
);
1300 static HRESULT WINAPI
AudioClient_SetEventHandle(IAudioClient
*iface
,
1303 ACImpl
*This
= impl_from_IAudioClient(iface
);
1305 TRACE("(%p)->(%p)\n", This
, event
);
1308 return E_INVALIDARG
;
1310 EnterCriticalSection(&This
->lock
);
1313 LeaveCriticalSection(&This
->lock
);
1314 return AUDCLNT_E_NOT_INITIALIZED
;
1317 if(!(This
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
)){
1318 LeaveCriticalSection(&This
->lock
);
1319 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED
;
1322 This
->event
= event
;
1324 LeaveCriticalSection(&This
->lock
);
1329 static HRESULT WINAPI
AudioClient_GetService(IAudioClient
*iface
, REFIID riid
,
1332 ACImpl
*This
= impl_from_IAudioClient(iface
);
1334 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
1340 EnterCriticalSection(&This
->lock
);
1343 LeaveCriticalSection(&This
->lock
);
1344 return AUDCLNT_E_NOT_INITIALIZED
;
1347 if(IsEqualIID(riid
, &IID_IAudioRenderClient
)){
1348 if(This
->dataflow
!= eRender
){
1349 LeaveCriticalSection(&This
->lock
);
1350 return AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
1352 *ppv
= &This
->IAudioRenderClient_iface
;
1353 }else if(IsEqualIID(riid
, &IID_IAudioCaptureClient
)){
1354 if(This
->dataflow
!= eCapture
){
1355 LeaveCriticalSection(&This
->lock
);
1356 return AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
1358 *ppv
= &This
->IAudioCaptureClient_iface
;
1359 }else if(IsEqualIID(riid
, &IID_IAudioClock
)){
1360 *ppv
= &This
->IAudioClock_iface
;
1361 }else if(IsEqualIID(riid
, &IID_IAudioStreamVolume
)){
1362 *ppv
= &This
->IAudioStreamVolume_iface
;
1363 }else if(IsEqualIID(riid
, &IID_IAudioSessionControl
)){
1364 if(!This
->session_wrapper
){
1365 This
->session_wrapper
= AudioSessionWrapper_Create(This
);
1366 if(!This
->session_wrapper
){
1367 LeaveCriticalSection(&This
->lock
);
1368 return E_OUTOFMEMORY
;
1372 *ppv
= &This
->session_wrapper
->IAudioSessionControl2_iface
;
1373 }else if(IsEqualIID(riid
, &IID_IChannelAudioVolume
)){
1374 if(!This
->session_wrapper
){
1375 This
->session_wrapper
= AudioSessionWrapper_Create(This
);
1376 if(!This
->session_wrapper
){
1377 LeaveCriticalSection(&This
->lock
);
1378 return E_OUTOFMEMORY
;
1382 *ppv
= &This
->session_wrapper
->IChannelAudioVolume_iface
;
1383 }else if(IsEqualIID(riid
, &IID_ISimpleAudioVolume
)){
1384 if(!This
->session_wrapper
){
1385 This
->session_wrapper
= AudioSessionWrapper_Create(This
);
1386 if(!This
->session_wrapper
){
1387 LeaveCriticalSection(&This
->lock
);
1388 return E_OUTOFMEMORY
;
1392 *ppv
= &This
->session_wrapper
->ISimpleAudioVolume_iface
;
1396 IUnknown_AddRef((IUnknown
*)*ppv
);
1397 LeaveCriticalSection(&This
->lock
);
1401 LeaveCriticalSection(&This
->lock
);
1403 FIXME("stub %s\n", debugstr_guid(riid
));
1404 return E_NOINTERFACE
;
1407 static const IAudioClientVtbl AudioClient_Vtbl
=
1409 AudioClient_QueryInterface
,
1411 AudioClient_Release
,
1412 AudioClient_Initialize
,
1413 AudioClient_GetBufferSize
,
1414 AudioClient_GetStreamLatency
,
1415 AudioClient_GetCurrentPadding
,
1416 AudioClient_IsFormatSupported
,
1417 AudioClient_GetMixFormat
,
1418 AudioClient_GetDevicePeriod
,
1422 AudioClient_SetEventHandle
,
1423 AudioClient_GetService
1426 static HRESULT WINAPI
AudioRenderClient_QueryInterface(
1427 IAudioRenderClient
*iface
, REFIID riid
, void **ppv
)
1429 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1435 if(IsEqualIID(riid
, &IID_IUnknown
) ||
1436 IsEqualIID(riid
, &IID_IAudioRenderClient
))
1439 IUnknown_AddRef((IUnknown
*)*ppv
);
1443 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1444 return E_NOINTERFACE
;
1447 static ULONG WINAPI
AudioRenderClient_AddRef(IAudioRenderClient
*iface
)
1449 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1450 return AudioClient_AddRef(&This
->IAudioClient_iface
);
1453 static ULONG WINAPI
AudioRenderClient_Release(IAudioRenderClient
*iface
)
1455 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1456 return AudioClient_Release(&This
->IAudioClient_iface
);
1459 static HRESULT WINAPI
AudioRenderClient_GetBuffer(IAudioRenderClient
*iface
,
1460 UINT32 frames
, BYTE
**data
)
1462 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1463 UINT32 pad
, write_pos
;
1466 TRACE("(%p)->(%u, %p)\n", This
, frames
, data
);
1471 EnterCriticalSection(&This
->lock
);
1473 if(This
->buf_state
!= NOT_LOCKED
){
1474 LeaveCriticalSection(&This
->lock
);
1475 return AUDCLNT_E_OUT_OF_ORDER
;
1479 This
->buf_state
= LOCKED_NORMAL
;
1480 LeaveCriticalSection(&This
->lock
);
1484 hr
= IAudioClient_GetCurrentPadding(&This
->IAudioClient_iface
, &pad
);
1486 LeaveCriticalSection(&This
->lock
);
1490 if(pad
+ frames
> This
->bufsize_frames
){
1491 LeaveCriticalSection(&This
->lock
);
1492 return AUDCLNT_E_BUFFER_TOO_LARGE
;
1496 (This
->lcl_offs_frames
+ This
->held_frames
) % This
->bufsize_frames
;
1497 if(write_pos
+ frames
> This
->bufsize_frames
){
1498 if(This
->tmp_buffer_frames
< frames
){
1499 if(This
->tmp_buffer
)
1500 This
->tmp_buffer
= HeapReAlloc(GetProcessHeap(), 0,
1501 This
->tmp_buffer
, frames
* This
->fmt
->nBlockAlign
);
1503 This
->tmp_buffer
= HeapAlloc(GetProcessHeap(), 0,
1504 frames
* This
->fmt
->nBlockAlign
);
1505 if(!This
->tmp_buffer
){
1506 LeaveCriticalSection(&This
->lock
);
1507 return E_OUTOFMEMORY
;
1509 This
->tmp_buffer_frames
= frames
;
1511 *data
= This
->tmp_buffer
;
1512 This
->buf_state
= LOCKED_WRAPPED
;
1514 *data
= This
->local_buffer
+
1515 This
->lcl_offs_frames
* This
->fmt
->nBlockAlign
;
1516 This
->buf_state
= LOCKED_NORMAL
;
1519 LeaveCriticalSection(&This
->lock
);
1524 static void oss_wrap_buffer(ACImpl
*This
, BYTE
*buffer
, UINT32 written_bytes
)
1526 UINT32 write_offs_frames
=
1527 (This
->lcl_offs_frames
+ This
->held_frames
) % This
->bufsize_frames
;
1528 UINT32 write_offs_bytes
= write_offs_frames
* This
->fmt
->nBlockAlign
;
1529 UINT32 chunk_frames
= This
->bufsize_frames
- write_offs_frames
;
1530 UINT32 chunk_bytes
= chunk_frames
* This
->fmt
->nBlockAlign
;
1532 if(written_bytes
< chunk_bytes
){
1533 memcpy(This
->local_buffer
+ write_offs_bytes
, buffer
, written_bytes
);
1535 memcpy(This
->local_buffer
+ write_offs_bytes
, buffer
, chunk_bytes
);
1536 memcpy(This
->local_buffer
, buffer
+ chunk_bytes
,
1537 written_bytes
- chunk_bytes
);
1541 static HRESULT WINAPI
AudioRenderClient_ReleaseBuffer(
1542 IAudioRenderClient
*iface
, UINT32 written_frames
, DWORD flags
)
1544 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1546 UINT32 written_bytes
= written_frames
* This
->fmt
->nBlockAlign
;
1548 TRACE("(%p)->(%u, %x)\n", This
, written_frames
, flags
);
1550 EnterCriticalSection(&This
->lock
);
1552 if(This
->buf_state
== NOT_LOCKED
|| !written_frames
){
1553 This
->buf_state
= NOT_LOCKED
;
1554 LeaveCriticalSection(&This
->lock
);
1555 return written_frames
? AUDCLNT_E_OUT_OF_ORDER
: S_OK
;
1558 if(This
->buf_state
== LOCKED_NORMAL
)
1559 buffer
= This
->local_buffer
+
1560 This
->lcl_offs_frames
* This
->fmt
->nBlockAlign
;
1562 buffer
= This
->tmp_buffer
;
1564 if(flags
& AUDCLNT_BUFFERFLAGS_SILENT
){
1565 WAVEFORMATEXTENSIBLE
*fmtex
= (WAVEFORMATEXTENSIBLE
*)This
->fmt
;
1566 if((This
->fmt
->wFormatTag
== WAVE_FORMAT_PCM
||
1567 (This
->fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
1568 IsEqualGUID(&fmtex
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))) &&
1569 This
->fmt
->wBitsPerSample
== 8)
1570 memset(buffer
, 128, written_frames
* This
->fmt
->nBlockAlign
);
1572 memset(buffer
, 0, written_frames
* This
->fmt
->nBlockAlign
);
1575 if(This
->held_frames
){
1576 if(This
->buf_state
== LOCKED_WRAPPED
)
1577 oss_wrap_buffer(This
, buffer
, written_bytes
);
1579 This
->held_frames
+= written_frames
;
1584 w_bytes
= write(This
->fd
, buffer
,
1585 written_frames
* This
->fmt
->nBlockAlign
);
1587 LeaveCriticalSection(&This
->lock
);
1588 WARN("write failed: %d (%s)\n", errno
, strerror(errno
));
1591 w_frames
= w_bytes
/ This
->fmt
->nBlockAlign
;
1592 This
->inbuf_frames
+= w_frames
;
1594 if(w_frames
< written_frames
){
1595 if(This
->buf_state
== LOCKED_WRAPPED
)
1596 oss_wrap_buffer(This
, This
->tmp_buffer
+ w_bytes
,
1597 written_frames
- w_frames
);
1599 This
->held_frames
= written_frames
- w_frames
;
1603 This
->written_frames
+= written_frames
;
1604 This
->buf_state
= NOT_LOCKED
;
1606 LeaveCriticalSection(&This
->lock
);
1611 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl
= {
1612 AudioRenderClient_QueryInterface
,
1613 AudioRenderClient_AddRef
,
1614 AudioRenderClient_Release
,
1615 AudioRenderClient_GetBuffer
,
1616 AudioRenderClient_ReleaseBuffer
1619 static HRESULT WINAPI
AudioCaptureClient_QueryInterface(
1620 IAudioCaptureClient
*iface
, REFIID riid
, void **ppv
)
1622 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1628 if(IsEqualIID(riid
, &IID_IUnknown
) ||
1629 IsEqualIID(riid
, &IID_IAudioCaptureClient
))
1632 IUnknown_AddRef((IUnknown
*)*ppv
);
1636 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1637 return E_NOINTERFACE
;
1640 static ULONG WINAPI
AudioCaptureClient_AddRef(IAudioCaptureClient
*iface
)
1642 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1643 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
1646 static ULONG WINAPI
AudioCaptureClient_Release(IAudioCaptureClient
*iface
)
1648 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1649 return IAudioClient_Release(&This
->IAudioClient_iface
);
1652 static HRESULT WINAPI
AudioCaptureClient_GetBuffer(IAudioCaptureClient
*iface
,
1653 BYTE
**data
, UINT32
*frames
, DWORD
*flags
, UINT64
*devpos
,
1656 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1659 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This
, data
, frames
, flags
,
1662 if(!data
|| !frames
|| !flags
)
1665 EnterCriticalSection(&This
->lock
);
1667 if(This
->buf_state
!= NOT_LOCKED
){
1668 LeaveCriticalSection(&This
->lock
);
1669 return AUDCLNT_E_OUT_OF_ORDER
;
1672 hr
= IAudioCaptureClient_GetNextPacketSize(iface
, frames
);
1674 LeaveCriticalSection(&This
->lock
);
1680 if(This
->lcl_offs_frames
+ *frames
> This
->bufsize_frames
){
1681 UINT32 chunk_bytes
, offs_bytes
, frames_bytes
;
1682 if(This
->tmp_buffer_frames
< *frames
){
1683 if(This
->tmp_buffer
)
1684 This
->tmp_buffer
= HeapReAlloc(GetProcessHeap(), 0,
1685 This
->tmp_buffer
, *frames
* This
->fmt
->nBlockAlign
);
1687 This
->tmp_buffer
= HeapAlloc(GetProcessHeap(), 0,
1688 *frames
* This
->fmt
->nBlockAlign
);
1689 if(!This
->tmp_buffer
){
1690 LeaveCriticalSection(&This
->lock
);
1691 return E_OUTOFMEMORY
;
1693 This
->tmp_buffer_frames
= *frames
;
1696 *data
= This
->tmp_buffer
;
1697 chunk_bytes
= (This
->bufsize_frames
- This
->lcl_offs_frames
) *
1698 This
->fmt
->nBlockAlign
;
1699 offs_bytes
= This
->lcl_offs_frames
* This
->fmt
->nBlockAlign
;
1700 frames_bytes
= *frames
* This
->fmt
->nBlockAlign
;
1701 memcpy(This
->tmp_buffer
, This
->local_buffer
+ offs_bytes
, chunk_bytes
);
1702 memcpy(This
->tmp_buffer
, This
->local_buffer
,
1703 frames_bytes
- chunk_bytes
);
1705 *data
= This
->local_buffer
+
1706 This
->lcl_offs_frames
* This
->fmt
->nBlockAlign
;
1708 This
->buf_state
= LOCKED_NORMAL
;
1710 if(devpos
|| qpcpos
)
1711 IAudioClock_GetPosition(&This
->IAudioClock_iface
, devpos
, qpcpos
);
1713 LeaveCriticalSection(&This
->lock
);
1715 return *frames
? S_OK
: AUDCLNT_S_BUFFER_EMPTY
;
1718 static HRESULT WINAPI
AudioCaptureClient_ReleaseBuffer(
1719 IAudioCaptureClient
*iface
, UINT32 done
)
1721 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1723 TRACE("(%p)->(%u)\n", This
, done
);
1725 EnterCriticalSection(&This
->lock
);
1727 if(This
->buf_state
== NOT_LOCKED
){
1728 LeaveCriticalSection(&This
->lock
);
1729 return AUDCLNT_E_OUT_OF_ORDER
;
1732 This
->held_frames
-= done
;
1733 This
->lcl_offs_frames
+= done
;
1734 This
->lcl_offs_frames
%= This
->bufsize_frames
;
1736 This
->buf_state
= NOT_LOCKED
;
1738 LeaveCriticalSection(&This
->lock
);
1743 static HRESULT WINAPI
AudioCaptureClient_GetNextPacketSize(
1744 IAudioCaptureClient
*iface
, UINT32
*frames
)
1746 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1748 TRACE("(%p)->(%p)\n", This
, frames
);
1750 return AudioClient_GetCurrentPadding(&This
->IAudioClient_iface
, frames
);
1753 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl
=
1755 AudioCaptureClient_QueryInterface
,
1756 AudioCaptureClient_AddRef
,
1757 AudioCaptureClient_Release
,
1758 AudioCaptureClient_GetBuffer
,
1759 AudioCaptureClient_ReleaseBuffer
,
1760 AudioCaptureClient_GetNextPacketSize
1763 static HRESULT WINAPI
AudioClock_QueryInterface(IAudioClock
*iface
,
1764 REFIID riid
, void **ppv
)
1766 ACImpl
*This
= impl_from_IAudioClock(iface
);
1768 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1774 if(IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IAudioClock
))
1776 else if(IsEqualIID(riid
, &IID_IAudioClock2
))
1777 *ppv
= &This
->IAudioClock2_iface
;
1779 IUnknown_AddRef((IUnknown
*)*ppv
);
1783 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1784 return E_NOINTERFACE
;
1787 static ULONG WINAPI
AudioClock_AddRef(IAudioClock
*iface
)
1789 ACImpl
*This
= impl_from_IAudioClock(iface
);
1790 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
1793 static ULONG WINAPI
AudioClock_Release(IAudioClock
*iface
)
1795 ACImpl
*This
= impl_from_IAudioClock(iface
);
1796 return IAudioClient_Release(&This
->IAudioClient_iface
);
1799 static HRESULT WINAPI
AudioClock_GetFrequency(IAudioClock
*iface
, UINT64
*freq
)
1801 ACImpl
*This
= impl_from_IAudioClock(iface
);
1803 TRACE("(%p)->(%p)\n", This
, freq
);
1805 *freq
= This
->fmt
->nSamplesPerSec
;
1810 static HRESULT WINAPI
AudioClock_GetPosition(IAudioClock
*iface
, UINT64
*pos
,
1813 ACImpl
*This
= impl_from_IAudioClock(iface
);
1817 TRACE("(%p)->(%p, %p)\n", This
, pos
, qpctime
);
1822 EnterCriticalSection(&This
->lock
);
1824 hr
= IAudioClient_GetCurrentPadding(&This
->IAudioClient_iface
, &pad
);
1826 LeaveCriticalSection(&This
->lock
);
1830 if(This
->dataflow
== eRender
)
1831 *pos
= This
->written_frames
- pad
;
1832 else if(This
->dataflow
== eCapture
)
1833 *pos
= This
->written_frames
+ pad
;
1835 LeaveCriticalSection(&This
->lock
);
1838 LARGE_INTEGER stamp
, freq
;
1839 QueryPerformanceCounter(&stamp
);
1840 QueryPerformanceFrequency(&freq
);
1841 *qpctime
= (stamp
.QuadPart
* (INT64
)10000000) / freq
.QuadPart
;
1847 static HRESULT WINAPI
AudioClock_GetCharacteristics(IAudioClock
*iface
,
1850 ACImpl
*This
= impl_from_IAudioClock(iface
);
1852 TRACE("(%p)->(%p)\n", This
, chars
);
1857 *chars
= AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ
;
1862 static const IAudioClockVtbl AudioClock_Vtbl
=
1864 AudioClock_QueryInterface
,
1867 AudioClock_GetFrequency
,
1868 AudioClock_GetPosition
,
1869 AudioClock_GetCharacteristics
1872 static HRESULT WINAPI
AudioClock2_QueryInterface(IAudioClock2
*iface
,
1873 REFIID riid
, void **ppv
)
1875 ACImpl
*This
= impl_from_IAudioClock2(iface
);
1876 return IAudioClock_QueryInterface(&This
->IAudioClock_iface
, riid
, ppv
);
1879 static ULONG WINAPI
AudioClock2_AddRef(IAudioClock2
*iface
)
1881 ACImpl
*This
= impl_from_IAudioClock2(iface
);
1882 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
1885 static ULONG WINAPI
AudioClock2_Release(IAudioClock2
*iface
)
1887 ACImpl
*This
= impl_from_IAudioClock2(iface
);
1888 return IAudioClient_Release(&This
->IAudioClient_iface
);
1891 static HRESULT WINAPI
AudioClock2_GetDevicePosition(IAudioClock2
*iface
,
1892 UINT64
*pos
, UINT64
*qpctime
)
1894 ACImpl
*This
= impl_from_IAudioClock2(iface
);
1896 FIXME("(%p)->(%p, %p)\n", This
, pos
, qpctime
);
1901 static const IAudioClock2Vtbl AudioClock2_Vtbl
=
1903 AudioClock2_QueryInterface
,
1905 AudioClock2_Release
,
1906 AudioClock2_GetDevicePosition
1909 static AudioSessionWrapper
*AudioSessionWrapper_Create(ACImpl
*client
)
1911 AudioSessionWrapper
*ret
;
1913 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1914 sizeof(AudioSessionWrapper
));
1918 ret
->IAudioSessionControl2_iface
.lpVtbl
= &AudioSessionControl2_Vtbl
;
1919 ret
->ISimpleAudioVolume_iface
.lpVtbl
= &SimpleAudioVolume_Vtbl
;
1920 ret
->IChannelAudioVolume_iface
.lpVtbl
= &ChannelAudioVolume_Vtbl
;
1922 ret
->client
= client
;
1923 ret
->session
= client
->session
;
1924 AudioClient_AddRef(&client
->IAudioClient_iface
);
1929 static HRESULT WINAPI
AudioSessionControl_QueryInterface(
1930 IAudioSessionControl2
*iface
, REFIID riid
, void **ppv
)
1932 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1938 if(IsEqualIID(riid
, &IID_IUnknown
) ||
1939 IsEqualIID(riid
, &IID_IAudioSessionControl
) ||
1940 IsEqualIID(riid
, &IID_IAudioSessionControl2
))
1943 IUnknown_AddRef((IUnknown
*)*ppv
);
1947 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1948 return E_NOINTERFACE
;
1951 static ULONG WINAPI
AudioSessionControl_AddRef(IAudioSessionControl2
*iface
)
1953 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
1955 ref
= InterlockedIncrement(&This
->ref
);
1956 TRACE("(%p) Refcount now %u\n", This
, ref
);
1960 static ULONG WINAPI
AudioSessionControl_Release(IAudioSessionControl2
*iface
)
1962 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
1964 ref
= InterlockedDecrement(&This
->ref
);
1965 TRACE("(%p) Refcount now %u\n", This
, ref
);
1967 EnterCriticalSection(&This
->client
->lock
);
1968 This
->client
->session_wrapper
= NULL
;
1969 LeaveCriticalSection(&This
->client
->lock
);
1970 AudioClient_Release(&This
->client
->IAudioClient_iface
);
1971 HeapFree(GetProcessHeap(), 0, This
);
1976 static HRESULT WINAPI
AudioSessionControl_GetState(IAudioSessionControl2
*iface
,
1977 AudioSessionState
*state
)
1979 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
1982 TRACE("(%p)->(%p)\n", This
, state
);
1985 return NULL_PTR_ERR
;
1987 EnterCriticalSection(&g_sessions_lock
);
1989 if(list_empty(&This
->session
->clients
)){
1990 *state
= AudioSessionStateExpired
;
1991 LeaveCriticalSection(&g_sessions_lock
);
1995 LIST_FOR_EACH_ENTRY(client
, &This
->session
->clients
, ACImpl
, entry
){
1996 EnterCriticalSection(&client
->lock
);
1997 if(client
->playing
){
1998 *state
= AudioSessionStateActive
;
1999 LeaveCriticalSection(&client
->lock
);
2000 LeaveCriticalSection(&g_sessions_lock
);
2003 LeaveCriticalSection(&client
->lock
);
2006 LeaveCriticalSection(&g_sessions_lock
);
2008 *state
= AudioSessionStateInactive
;
2013 static HRESULT WINAPI
AudioSessionControl_GetDisplayName(
2014 IAudioSessionControl2
*iface
, WCHAR
**name
)
2016 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2018 FIXME("(%p)->(%p) - stub\n", This
, name
);
2023 static HRESULT WINAPI
AudioSessionControl_SetDisplayName(
2024 IAudioSessionControl2
*iface
, const WCHAR
*name
, const GUID
*session
)
2026 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2028 FIXME("(%p)->(%p, %s) - stub\n", This
, name
, debugstr_guid(session
));
2033 static HRESULT WINAPI
AudioSessionControl_GetIconPath(
2034 IAudioSessionControl2
*iface
, WCHAR
**path
)
2036 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2038 FIXME("(%p)->(%p) - stub\n", This
, path
);
2043 static HRESULT WINAPI
AudioSessionControl_SetIconPath(
2044 IAudioSessionControl2
*iface
, const WCHAR
*path
, const GUID
*session
)
2046 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2048 FIXME("(%p)->(%p, %s) - stub\n", This
, path
, debugstr_guid(session
));
2053 static HRESULT WINAPI
AudioSessionControl_GetGroupingParam(
2054 IAudioSessionControl2
*iface
, GUID
*group
)
2056 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2058 FIXME("(%p)->(%p) - stub\n", This
, group
);
2063 static HRESULT WINAPI
AudioSessionControl_SetGroupingParam(
2064 IAudioSessionControl2
*iface
, GUID
*group
, const GUID
*session
)
2066 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2068 FIXME("(%p)->(%s, %s) - stub\n", This
, debugstr_guid(group
),
2069 debugstr_guid(session
));
2074 static HRESULT WINAPI
AudioSessionControl_RegisterAudioSessionNotification(
2075 IAudioSessionControl2
*iface
, IAudioSessionEvents
*events
)
2077 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2079 FIXME("(%p)->(%p) - stub\n", This
, events
);
2084 static HRESULT WINAPI
AudioSessionControl_UnregisterAudioSessionNotification(
2085 IAudioSessionControl2
*iface
, IAudioSessionEvents
*events
)
2087 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2089 FIXME("(%p)->(%p) - stub\n", This
, events
);
2094 static HRESULT WINAPI
AudioSessionControl_GetSessionIdentifier(
2095 IAudioSessionControl2
*iface
, WCHAR
**id
)
2097 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2099 FIXME("(%p)->(%p) - stub\n", This
, id
);
2104 static HRESULT WINAPI
AudioSessionControl_GetSessionInstanceIdentifier(
2105 IAudioSessionControl2
*iface
, WCHAR
**id
)
2107 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2109 FIXME("(%p)->(%p) - stub\n", This
, id
);
2114 static HRESULT WINAPI
AudioSessionControl_GetProcessId(
2115 IAudioSessionControl2
*iface
, DWORD
*pid
)
2117 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2119 TRACE("(%p)->(%p)\n", This
, pid
);
2124 *pid
= GetCurrentProcessId();
2129 static HRESULT WINAPI
AudioSessionControl_IsSystemSoundsSession(
2130 IAudioSessionControl2
*iface
)
2132 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2134 TRACE("(%p)\n", This
);
2139 static HRESULT WINAPI
AudioSessionControl_SetDuckingPreference(
2140 IAudioSessionControl2
*iface
, BOOL optout
)
2142 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2144 TRACE("(%p)->(%d)\n", This
, optout
);
2149 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl
=
2151 AudioSessionControl_QueryInterface
,
2152 AudioSessionControl_AddRef
,
2153 AudioSessionControl_Release
,
2154 AudioSessionControl_GetState
,
2155 AudioSessionControl_GetDisplayName
,
2156 AudioSessionControl_SetDisplayName
,
2157 AudioSessionControl_GetIconPath
,
2158 AudioSessionControl_SetIconPath
,
2159 AudioSessionControl_GetGroupingParam
,
2160 AudioSessionControl_SetGroupingParam
,
2161 AudioSessionControl_RegisterAudioSessionNotification
,
2162 AudioSessionControl_UnregisterAudioSessionNotification
,
2163 AudioSessionControl_GetSessionIdentifier
,
2164 AudioSessionControl_GetSessionInstanceIdentifier
,
2165 AudioSessionControl_GetProcessId
,
2166 AudioSessionControl_IsSystemSoundsSession
,
2167 AudioSessionControl_SetDuckingPreference
2170 /* index == -1 means set all channels, otherwise sets only the given channel */
2171 static HRESULT
oss_setvol(ACImpl
*This
, UINT32 index
)
2178 if(index
== (UINT32
)-1){
2181 for(i
= 0; i
< This
->fmt
->nChannels
; ++i
){
2183 hr
= oss_setvol(This
, i
);
2191 /* OSS doesn't support volume control past the first two channels */
2194 if(This
->dataflow
== eRender
){
2195 setreq
= SNDCTL_DSP_SETPLAYVOL
;
2196 getreq
= SNDCTL_DSP_GETPLAYVOL
;
2197 }else if(This
->dataflow
== eCapture
){
2198 setreq
= SNDCTL_DSP_SETRECVOL
;
2199 getreq
= SNDCTL_DSP_GETRECVOL
;
2201 return E_UNEXPECTED
;
2203 if(ioctl(This
->fd
, getreq
, &vol
) < 0){
2205 /* device doesn't support this call */
2208 WARN("GET[REC|PLAY]VOL failed: %d (%s)\n", errno
, strerror(errno
));
2212 level
= This
->session
->master_vol
* This
->session
->channel_vols
[index
] *
2216 vol
= l
| (vol
& 0xFF00);
2218 vol
= (vol
& 0xFF) | (l
<< 8);
2220 if(ioctl(This
->fd
, setreq
, &vol
) < 0){
2222 /* device doesn't support this call */
2225 WARN("SET[REC|PLAY]VOL failed: %d (%s)\n", errno
, strerror(errno
));
2232 static HRESULT
oss_session_setvol(AudioSession
*session
, UINT32 index
)
2237 LIST_FOR_EACH_ENTRY(client
, &session
->clients
, ACImpl
, entry
){
2239 hr
= oss_setvol(client
, index
);
2247 static HRESULT WINAPI
SimpleAudioVolume_QueryInterface(
2248 ISimpleAudioVolume
*iface
, REFIID riid
, void **ppv
)
2250 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2256 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2257 IsEqualIID(riid
, &IID_ISimpleAudioVolume
))
2260 IUnknown_AddRef((IUnknown
*)*ppv
);
2264 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2265 return E_NOINTERFACE
;
2268 static ULONG WINAPI
SimpleAudioVolume_AddRef(ISimpleAudioVolume
*iface
)
2270 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2271 return AudioSessionControl_AddRef(&This
->IAudioSessionControl2_iface
);
2274 static ULONG WINAPI
SimpleAudioVolume_Release(ISimpleAudioVolume
*iface
)
2276 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2277 return AudioSessionControl_Release(&This
->IAudioSessionControl2_iface
);
2280 static HRESULT WINAPI
SimpleAudioVolume_SetMasterVolume(
2281 ISimpleAudioVolume
*iface
, float level
, const GUID
*context
)
2283 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2284 AudioSession
*session
= This
->session
;
2287 TRACE("(%p)->(%f, %s)\n", session
, level
, wine_dbgstr_guid(context
));
2289 if(level
< 0.f
|| level
> 1.f
)
2290 return E_INVALIDARG
;
2293 FIXME("Notifications not supported yet\n");
2295 EnterCriticalSection(&session
->lock
);
2297 session
->master_vol
= level
;
2299 ret
= oss_session_setvol(session
, -1);
2301 LeaveCriticalSection(&session
->lock
);
2306 static HRESULT WINAPI
SimpleAudioVolume_GetMasterVolume(
2307 ISimpleAudioVolume
*iface
, float *level
)
2309 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2310 AudioSession
*session
= This
->session
;
2312 TRACE("(%p)->(%p)\n", session
, level
);
2315 return NULL_PTR_ERR
;
2317 *level
= session
->master_vol
;
2322 static HRESULT WINAPI
SimpleAudioVolume_SetMute(ISimpleAudioVolume
*iface
,
2323 BOOL mute
, const GUID
*context
)
2325 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2326 AudioSession
*session
= This
->session
;
2328 FIXME("(%p)->(%u, %p) - stub\n", session
, mute
, context
);
2333 static HRESULT WINAPI
SimpleAudioVolume_GetMute(ISimpleAudioVolume
*iface
,
2336 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2337 AudioSession
*session
= This
->session
;
2339 FIXME("(%p)->(%p) - stub\n", session
, mute
);
2342 return NULL_PTR_ERR
;
2347 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl
=
2349 SimpleAudioVolume_QueryInterface
,
2350 SimpleAudioVolume_AddRef
,
2351 SimpleAudioVolume_Release
,
2352 SimpleAudioVolume_SetMasterVolume
,
2353 SimpleAudioVolume_GetMasterVolume
,
2354 SimpleAudioVolume_SetMute
,
2355 SimpleAudioVolume_GetMute
2358 static HRESULT WINAPI
AudioStreamVolume_QueryInterface(
2359 IAudioStreamVolume
*iface
, REFIID riid
, void **ppv
)
2361 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2367 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2368 IsEqualIID(riid
, &IID_IAudioStreamVolume
))
2371 IUnknown_AddRef((IUnknown
*)*ppv
);
2375 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2376 return E_NOINTERFACE
;
2379 static ULONG WINAPI
AudioStreamVolume_AddRef(IAudioStreamVolume
*iface
)
2381 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2382 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
2385 static ULONG WINAPI
AudioStreamVolume_Release(IAudioStreamVolume
*iface
)
2387 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2388 return IAudioClient_Release(&This
->IAudioClient_iface
);
2391 static HRESULT WINAPI
AudioStreamVolume_GetChannelCount(
2392 IAudioStreamVolume
*iface
, UINT32
*out
)
2394 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2396 TRACE("(%p)->(%p)\n", This
, out
);
2401 *out
= This
->fmt
->nChannels
;
2406 static HRESULT WINAPI
AudioStreamVolume_SetChannelVolume(
2407 IAudioStreamVolume
*iface
, UINT32 index
, float level
)
2409 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2412 TRACE("(%p)->(%d, %f)\n", This
, index
, level
);
2414 if(level
< 0.f
|| level
> 1.f
)
2415 return E_INVALIDARG
;
2417 if(index
>= This
->fmt
->nChannels
)
2418 return E_INVALIDARG
;
2420 EnterCriticalSection(&This
->lock
);
2422 This
->vols
[index
] = level
;
2424 ret
= oss_setvol(This
, index
);
2426 LeaveCriticalSection(&This
->lock
);
2431 static HRESULT WINAPI
AudioStreamVolume_GetChannelVolume(
2432 IAudioStreamVolume
*iface
, UINT32 index
, float *level
)
2434 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2436 TRACE("(%p)->(%d, %p)\n", This
, index
, level
);
2441 if(index
>= This
->fmt
->nChannels
)
2442 return E_INVALIDARG
;
2444 *level
= This
->vols
[index
];
2449 static HRESULT WINAPI
AudioStreamVolume_SetAllVolumes(
2450 IAudioStreamVolume
*iface
, UINT32 count
, const float *levels
)
2452 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2456 TRACE("(%p)->(%d, %p)\n", This
, count
, levels
);
2461 if(count
!= This
->fmt
->nChannels
)
2462 return E_INVALIDARG
;
2464 EnterCriticalSection(&This
->lock
);
2466 for(i
= 0; i
< count
; ++i
)
2467 This
->vols
[i
] = levels
[i
];
2469 ret
= oss_setvol(This
, -1);
2471 LeaveCriticalSection(&This
->lock
);
2476 static HRESULT WINAPI
AudioStreamVolume_GetAllVolumes(
2477 IAudioStreamVolume
*iface
, UINT32 count
, float *levels
)
2479 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2482 TRACE("(%p)->(%d, %p)\n", This
, count
, levels
);
2487 if(count
!= This
->fmt
->nChannels
)
2488 return E_INVALIDARG
;
2490 EnterCriticalSection(&This
->lock
);
2492 for(i
= 0; i
< count
; ++i
)
2493 levels
[i
] = This
->vols
[i
];
2495 LeaveCriticalSection(&This
->lock
);
2500 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl
=
2502 AudioStreamVolume_QueryInterface
,
2503 AudioStreamVolume_AddRef
,
2504 AudioStreamVolume_Release
,
2505 AudioStreamVolume_GetChannelCount
,
2506 AudioStreamVolume_SetChannelVolume
,
2507 AudioStreamVolume_GetChannelVolume
,
2508 AudioStreamVolume_SetAllVolumes
,
2509 AudioStreamVolume_GetAllVolumes
2512 static HRESULT WINAPI
ChannelAudioVolume_QueryInterface(
2513 IChannelAudioVolume
*iface
, REFIID riid
, void **ppv
)
2515 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2521 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2522 IsEqualIID(riid
, &IID_IChannelAudioVolume
))
2525 IUnknown_AddRef((IUnknown
*)*ppv
);
2529 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2530 return E_NOINTERFACE
;
2533 static ULONG WINAPI
ChannelAudioVolume_AddRef(IChannelAudioVolume
*iface
)
2535 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2536 return AudioSessionControl_AddRef(&This
->IAudioSessionControl2_iface
);
2539 static ULONG WINAPI
ChannelAudioVolume_Release(IChannelAudioVolume
*iface
)
2541 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2542 return AudioSessionControl_Release(&This
->IAudioSessionControl2_iface
);
2545 static HRESULT WINAPI
ChannelAudioVolume_GetChannelCount(
2546 IChannelAudioVolume
*iface
, UINT32
*out
)
2548 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2549 AudioSession
*session
= This
->session
;
2551 TRACE("(%p)->(%p)\n", session
, out
);
2554 return NULL_PTR_ERR
;
2556 *out
= session
->channel_count
;
2561 static HRESULT WINAPI
ChannelAudioVolume_SetChannelVolume(
2562 IChannelAudioVolume
*iface
, UINT32 index
, float level
,
2563 const GUID
*context
)
2565 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2566 AudioSession
*session
= This
->session
;
2569 TRACE("(%p)->(%d, %f, %s)\n", session
, index
, level
,
2570 wine_dbgstr_guid(context
));
2572 if(level
< 0.f
|| level
> 1.f
)
2573 return E_INVALIDARG
;
2575 if(index
>= session
->channel_count
)
2576 return E_INVALIDARG
;
2579 FIXME("Notifications not supported yet\n");
2581 EnterCriticalSection(&session
->lock
);
2583 session
->channel_vols
[index
] = level
;
2585 ret
= oss_session_setvol(session
, index
);
2587 LeaveCriticalSection(&session
->lock
);
2592 static HRESULT WINAPI
ChannelAudioVolume_GetChannelVolume(
2593 IChannelAudioVolume
*iface
, UINT32 index
, float *level
)
2595 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2596 AudioSession
*session
= This
->session
;
2598 TRACE("(%p)->(%d, %p)\n", session
, index
, level
);
2601 return NULL_PTR_ERR
;
2603 if(index
>= session
->channel_count
)
2604 return E_INVALIDARG
;
2606 *level
= session
->channel_vols
[index
];
2611 static HRESULT WINAPI
ChannelAudioVolume_SetAllVolumes(
2612 IChannelAudioVolume
*iface
, UINT32 count
, const float *levels
,
2613 const GUID
*context
)
2615 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2616 AudioSession
*session
= This
->session
;
2620 TRACE("(%p)->(%d, %p, %s)\n", session
, count
, levels
,
2621 wine_dbgstr_guid(context
));
2624 return NULL_PTR_ERR
;
2626 if(count
!= session
->channel_count
)
2627 return E_INVALIDARG
;
2630 FIXME("Notifications not supported yet\n");
2632 EnterCriticalSection(&session
->lock
);
2634 for(i
= 0; i
< count
; ++i
)
2635 session
->channel_vols
[i
] = levels
[i
];
2637 ret
= oss_session_setvol(session
, -1);
2639 LeaveCriticalSection(&session
->lock
);
2644 static HRESULT WINAPI
ChannelAudioVolume_GetAllVolumes(
2645 IChannelAudioVolume
*iface
, UINT32 count
, float *levels
)
2647 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2648 AudioSession
*session
= This
->session
;
2651 TRACE("(%p)->(%d, %p)\n", session
, count
, levels
);
2654 return NULL_PTR_ERR
;
2656 if(count
!= session
->channel_count
)
2657 return E_INVALIDARG
;
2659 for(i
= 0; i
< count
; ++i
)
2660 levels
[i
] = session
->channel_vols
[i
];
2665 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl
=
2667 ChannelAudioVolume_QueryInterface
,
2668 ChannelAudioVolume_AddRef
,
2669 ChannelAudioVolume_Release
,
2670 ChannelAudioVolume_GetChannelCount
,
2671 ChannelAudioVolume_SetChannelVolume
,
2672 ChannelAudioVolume_GetChannelVolume
,
2673 ChannelAudioVolume_SetAllVolumes
,
2674 ChannelAudioVolume_GetAllVolumes