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"
52 #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 {
77 CRITICAL_SECTION lock;
82 typedef struct _AudioSessionWrapper {
83 IAudioSessionControl2 IAudioSessionControl2_iface;
84 IChannelAudioVolume IChannelAudioVolume_iface;
85 ISimpleAudioVolume ISimpleAudioVolume_iface;
90 AudioSession *session;
91 } AudioSessionWrapper;
94 IAudioClient IAudioClient_iface;
95 IAudioRenderClient IAudioRenderClient_iface;
96 IAudioCaptureClient IAudioCaptureClient_iface;
97 IAudioClock IAudioClock_iface;
98 IAudioClock2 IAudioClock2_iface;
99 IAudioStreamVolume IAudioStreamVolume_iface;
109 AUDCLNT_SHAREMODE share;
115 char devnode[OSS_DEVNODE_SIZE];
117 BOOL initted, playing;
118 UINT64 written_frames, last_pos_frames;
119 UINT32 period_us, period_frames, bufsize_frames, held_frames, tmp_buffer_frames;
120 UINT32 oss_bufsize_bytes, lcl_offs_frames; /* offs into local_buffer where valid data starts */
122 BYTE *local_buffer, *tmp_buffer;
123 LONG32 getbuf_last; /* <0 when using tmp_buffer */
126 CRITICAL_SECTION lock;
128 AudioSession *session;
129 AudioSessionWrapper *session_wrapper;
134 typedef struct _SessionMgr {
135 IAudioSessionManager2 IAudioSessionManager2_iface;
142 typedef struct _OSSDevice {
144 char devnode[OSS_DEVNODE_SIZE];
150 static struct list g_devices = LIST_INIT(g_devices);
152 static const WCHAR drv_keyW[] = {'S','o','f','t','w','a','r','e','\\',
153 'W','i','n','e','\\','D','r','i','v','e','r','s','\\',
154 'w','i','n','e','o','s','s','.','d','r','v',0};
155 static const WCHAR drv_key_devicesW[] = {'S','o','f','t','w','a','r','e','\\',
156 'W','i','n','e','\\','D','r','i','v','e','r','s','\\',
157 'w','i','n','e','o','s','s','.','d','r','v','\\','d','e','v','i','c','e','s',0};
158 static const WCHAR guidW[] = {'g','u','i','d',0};
160 static HANDLE g_timer_q;
162 static CRITICAL_SECTION g_sessions_lock;
163 static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
165 0, 0, &g_sessions_lock,
166 { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList },
167 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") }
169 static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 };
170 static struct list g_sessions = LIST_INIT(g_sessions);
172 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
174 static const IAudioClientVtbl AudioClient_Vtbl;
175 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
176 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
177 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
178 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
179 static const IAudioClockVtbl AudioClock_Vtbl;
180 static const IAudioClock2Vtbl AudioClock2_Vtbl;
181 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
182 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
183 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
185 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
187 return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
190 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
192 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
195 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
197 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
200 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
202 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
205 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
207 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
210 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
212 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
215 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
217 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
220 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
222 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
225 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
227 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
230 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
232 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
235 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
239 case DLL_PROCESS_ATTACH:
240 g_timer_q = CreateTimerQueue();
245 case DLL_PROCESS_DETACH:
247 OSSDevice *iter, *iter2;
249 DeleteCriticalSection(&g_sessions_lock);
251 LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &g_devices, OSSDevice, entry){
252 HeapFree(GetProcessHeap(), 0, iter);
261 /* From <dlls/mmdevapi/mmdevapi.h> */
262 enum DriverPriority {
263 Priority_Unavailable = 0,
269 int WINAPI AUDDRV_GetPriority(void)
274 /* Attempt to determine if we are running on OSS or ALSA's OSS
275 * compatibility layer. There is no official way to do that, so just check
276 * for validity as best as possible, without rejecting valid OSS
277 * implementations. */
279 mixer_fd = open("/dev/mixer", O_RDONLY, 0);
281 TRACE("Priority_Unavailable: open failed\n");
282 return Priority_Unavailable;
285 sysinfo.version[0] = 0xFF;
286 sysinfo.versionnum = ~0;
287 if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){
288 TRACE("Priority_Unavailable: ioctl failed\n");
290 return Priority_Unavailable;
295 if(sysinfo.version[0] < '4' || sysinfo.version[0] > '9'){
296 TRACE("Priority_Low: sysinfo.version[0]: %x\n", sysinfo.version[0]);
299 if(sysinfo.versionnum & 0x80000000){
300 TRACE("Priority_Low: sysinfo.versionnum: %x\n", sysinfo.versionnum);
304 TRACE("Priority_Preferred: Seems like valid OSS!\n");
306 return Priority_Preferred;
309 static void set_device_guid(EDataFlow flow, HKEY drv_key, const WCHAR *key_name,
317 lr = RegCreateKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, NULL, 0, KEY_WRITE,
318 NULL, &drv_key, NULL);
319 if(lr != ERROR_SUCCESS){
320 ERR("RegCreateKeyEx(drv_key) failed: %u\n", lr);
326 lr = RegCreateKeyExW(drv_key, key_name, 0, NULL, 0, KEY_WRITE,
328 if(lr != ERROR_SUCCESS){
329 ERR("RegCreateKeyEx(%s) failed: %u\n", wine_dbgstr_w(key_name), lr);
333 lr = RegSetValueExW(key, guidW, 0, REG_BINARY, (BYTE*)guid,
335 if(lr != ERROR_SUCCESS)
336 ERR("RegSetValueEx(%s\\guid) failed: %u\n", wine_dbgstr_w(key_name), lr);
341 RegCloseKey(drv_key);
344 static void get_device_guid(EDataFlow flow, const char *device, GUID *guid)
346 HKEY key = NULL, dev_key;
347 DWORD type, size = sizeof(*guid);
355 MultiByteToWideChar(CP_UNIXCP, 0, device, -1, key_name + 2,
356 (sizeof(key_name) / sizeof(*key_name)) - 2);
358 if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_WRITE|KEY_READ, &key) == ERROR_SUCCESS){
359 if(RegOpenKeyExW(key, key_name, 0, KEY_READ, &dev_key) == ERROR_SUCCESS){
360 if(RegQueryValueExW(dev_key, guidW, 0, &type,
361 (BYTE*)guid, &size) == ERROR_SUCCESS){
362 if(type == REG_BINARY){
363 RegCloseKey(dev_key);
367 ERR("Invalid type for device %s GUID: %u; ignoring and overwriting\n",
368 wine_dbgstr_w(key_name), type);
370 RegCloseKey(dev_key);
376 set_device_guid(flow, key, key_name, guid);
382 static const char *oss_clean_devnode(const char *devnode)
384 static char ret[OSS_DEVNODE_SIZE];
386 const char *dot, *slash;
389 dot = strrchr(devnode, '.');
393 slash = strrchr(devnode, '/');
394 if(slash && dot < slash)
399 memcpy(ret, devnode, len);
405 static UINT get_default_index(EDataFlow flow)
414 fd = open("/dev/dsp", O_WRONLY | O_NONBLOCK);
416 fd = open("/dev/dsp", O_RDONLY | O_NONBLOCK);
419 WARN("Couldn't open default device!\n");
424 if((err = ioctl(fd, SNDCTL_ENGINEINFO, &ai)) < 0){
425 WARN("SNDCTL_ENGINEINFO failed: %d (%s)\n", err, strerror(errno));
432 TRACE("Default devnode: %s\n", ai.devnode);
433 devnode = oss_clean_devnode(ai.devnode);
435 LIST_FOR_EACH_ENTRY(dev_item, &g_devices, OSSDevice, entry){
436 if(dev_item->flow == flow){
437 if(!strcmp(devnode, dev_item->devnode))
443 WARN("Couldn't find default device! Choosing first.\n");
447 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, GUID **guids,
448 UINT *num, UINT *def_index)
452 static int print_once = 0;
454 static const WCHAR outW[] = {'O','u','t',':',' ',0};
455 static const WCHAR inW[] = {'I','n',':',' ',0};
457 TRACE("%d %p %p %p %p\n", flow, ids, guids, num, def_index);
459 mixer_fd = open("/dev/mixer", O_RDONLY, 0);
461 ERR("OSS /dev/mixer doesn't seem to exist\n");
462 return AUDCLNT_E_SERVICE_NOT_RUNNING;
465 if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){
469 ERR("OSS version too old, need at least OSSv4\n");
470 return AUDCLNT_E_SERVICE_NOT_RUNNING;
473 ERR("Error getting SNDCTL_SYSINFO: %d (%s)\n", errno, strerror(errno));
478 TRACE("OSS sysinfo:\n");
479 TRACE("product: %s\n", sysinfo.product);
480 TRACE("version: %s\n", sysinfo.version);
481 TRACE("versionnum: %x\n", sysinfo.versionnum);
482 TRACE("numaudios: %d\n", sysinfo.numaudios);
483 TRACE("nummixers: %d\n", sysinfo.nummixers);
484 TRACE("numcards: %d\n", sysinfo.numcards);
485 TRACE("numaudioengines: %d\n", sysinfo.numaudioengines);
489 if(sysinfo.numaudios <= 0){
490 WARN("No audio devices!\n");
492 return AUDCLNT_E_SERVICE_NOT_RUNNING;
495 *ids = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(WCHAR *));
496 *guids = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(GUID));
499 for(i = 0; i < sysinfo.numaudios; ++i){
500 oss_audioinfo ai = {0};
506 if(ioctl(mixer_fd, SNDCTL_AUDIOINFO, &ai) < 0){
507 WARN("Error getting AUDIOINFO for dev %d: %d (%s)\n", i, errno,
512 devnode = oss_clean_devnode(ai.devnode);
514 /* check for duplicates */
515 LIST_FOR_EACH_ENTRY(dev_item, &g_devices, OSSDevice, entry){
516 if(dev_item->flow == flow && !strcmp(devnode, dev_item->devnode))
519 if(&dev_item->entry != &g_devices)
523 fd = open(devnode, O_WRONLY | O_NONBLOCK, 0);
525 fd = open(devnode, O_RDONLY | O_NONBLOCK, 0);
527 WARN("Opening device \"%s\" failed, pretending it doesn't exist: %d (%s)\n",
528 devnode, errno, strerror(errno));
533 if((flow == eCapture && (ai.caps & PCM_CAP_INPUT)) ||
534 (flow == eRender && (ai.caps & PCM_CAP_OUTPUT))){
535 size_t len, prefix_len;
538 dev_item = HeapAlloc(GetProcessHeap(), 0, sizeof(*dev_item));
540 dev_item->flow = flow;
541 get_device_guid(flow, devnode, &dev_item->guid);
542 strcpy(dev_item->devnode, devnode);
544 (*guids)[*num] = dev_item->guid;
546 len = MultiByteToWideChar(CP_UNIXCP, 0, ai.name, -1, NULL, 0);
549 prefix_len = (sizeof(outW) / sizeof(*outW)) - 1;
553 prefix_len = (sizeof(inW) / sizeof(*inW)) - 1;
556 (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0,
557 len * sizeof(WCHAR));
559 for(i = 0; i < *num; ++i)
560 HeapFree(GetProcessHeap(), 0, (*ids)[i]);
561 HeapFree(GetProcessHeap(), 0, *ids);
562 HeapFree(GetProcessHeap(), 0, *guids);
563 HeapFree(GetProcessHeap(), 0, dev_item);
565 return E_OUTOFMEMORY;
567 memcpy((*ids)[*num], prefix, prefix_len * sizeof(WCHAR));
568 MultiByteToWideChar(CP_UNIXCP, 0, ai.name, -1,
569 (*ids)[*num] + prefix_len, len - prefix_len);
571 list_add_tail(&g_devices, &dev_item->entry);
579 *def_index = get_default_index(flow);
584 static const OSSDevice *get_ossdevice_from_guid(const GUID *guid)
587 LIST_FOR_EACH_ENTRY(dev_item, &g_devices, OSSDevice, entry)
588 if(IsEqualGUID(guid, &dev_item->guid))
593 HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev,
597 const OSSDevice *oss_dev;
599 TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
601 oss_dev = get_ossdevice_from_guid(guid);
603 WARN("Unknown GUID: %s\n", debugstr_guid(guid));
604 return AUDCLNT_E_DEVICE_INVALIDATED;
607 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
609 return E_OUTOFMEMORY;
611 if(oss_dev->flow == eRender)
612 This->fd = open(oss_dev->devnode, O_WRONLY | O_NONBLOCK, 0);
613 else if(oss_dev->flow == eCapture)
614 This->fd = open(oss_dev->devnode, O_RDONLY | O_NONBLOCK, 0);
616 HeapFree(GetProcessHeap(), 0, This);
620 WARN("Unable to open device %s: %d (%s)\n", oss_dev->devnode, errno,
622 HeapFree(GetProcessHeap(), 0, This);
623 return AUDCLNT_E_DEVICE_INVALIDATED;
626 This->dataflow = oss_dev->flow;
629 if(ioctl(This->fd, SNDCTL_ENGINEINFO, &This->ai) < 0){
630 WARN("Unable to get audio info for device %s: %d (%s)\n", oss_dev->devnode,
631 errno, strerror(errno));
633 HeapFree(GetProcessHeap(), 0, This);
637 strcpy(This->devnode, oss_dev->devnode);
639 TRACE("OSS audioinfo:\n");
640 TRACE("devnode: %s\n", This->ai.devnode);
641 TRACE("name: %s\n", This->ai.name);
642 TRACE("busy: %x\n", This->ai.busy);
643 TRACE("caps: %x\n", This->ai.caps);
644 TRACE("iformats: %x\n", This->ai.iformats);
645 TRACE("oformats: %x\n", This->ai.oformats);
646 TRACE("enabled: %d\n", This->ai.enabled);
647 TRACE("min_rate: %d\n", This->ai.min_rate);
648 TRACE("max_rate: %d\n", This->ai.max_rate);
649 TRACE("min_channels: %d\n", This->ai.min_channels);
650 TRACE("max_channels: %d\n", This->ai.max_channels);
652 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
653 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
654 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
655 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
656 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
657 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
659 InitializeCriticalSection(&This->lock);
660 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ACImpl.lock");
663 IMMDevice_AddRef(This->parent);
665 IAudioClient_AddRef(&This->IAudioClient_iface);
667 *out = &This->IAudioClient_iface;
672 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
673 REFIID riid, void **ppv)
675 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
680 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
683 IUnknown_AddRef((IUnknown*)*ppv);
686 WARN("Unknown interface %s\n", debugstr_guid(riid));
687 return E_NOINTERFACE;
690 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
692 ACImpl *This = impl_from_IAudioClient(iface);
694 ref = InterlockedIncrement(&This->ref);
695 TRACE("(%p) Refcount now %u\n", This, ref);
699 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
701 ACImpl *This = impl_from_IAudioClient(iface);
703 ref = InterlockedDecrement(&This->ref);
704 TRACE("(%p) Refcount now %u\n", This, ref);
706 IAudioClient_Stop(iface);
707 IMMDevice_Release(This->parent);
708 This->lock.DebugInfo->Spare[0] = 0;
709 DeleteCriticalSection(&This->lock);
712 EnterCriticalSection(&g_sessions_lock);
713 list_remove(&This->entry);
714 LeaveCriticalSection(&g_sessions_lock);
716 HeapFree(GetProcessHeap(), 0, This->vols);
717 HeapFree(GetProcessHeap(), 0, This->local_buffer);
718 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
719 CoTaskMemFree(This->fmt);
720 HeapFree(GetProcessHeap(), 0, This);
725 static void dump_fmt(const WAVEFORMATEX *fmt)
727 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
728 switch(fmt->wFormatTag){
729 case WAVE_FORMAT_PCM:
730 TRACE("WAVE_FORMAT_PCM");
732 case WAVE_FORMAT_IEEE_FLOAT:
733 TRACE("WAVE_FORMAT_IEEE_FLOAT");
735 case WAVE_FORMAT_EXTENSIBLE:
736 TRACE("WAVE_FORMAT_EXTENSIBLE");
744 TRACE("nChannels: %u\n", fmt->nChannels);
745 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
746 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
747 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
748 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
749 TRACE("cbSize: %u\n", fmt->cbSize);
751 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
752 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
753 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
754 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
755 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
759 static DWORD get_channel_mask(unsigned int channels)
765 return KSAUDIO_SPEAKER_MONO;
767 return KSAUDIO_SPEAKER_STEREO;
769 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
771 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
773 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
775 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
777 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
779 return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
781 FIXME("Unknown speaker configuration: %u\n", channels);
785 static int get_oss_format(const WAVEFORMATEX *fmt)
787 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)fmt;
789 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
790 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
791 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
792 switch(fmt->wBitsPerSample){
806 if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
807 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
808 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
809 if(fmt->wBitsPerSample != 32)
819 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
824 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
825 size = sizeof(WAVEFORMATEXTENSIBLE);
827 size = sizeof(WAVEFORMATEX);
829 ret = CoTaskMemAlloc(size);
833 memcpy(ret, fmt, size);
835 ret->cbSize = size - sizeof(WAVEFORMATEX);
840 static HRESULT setup_oss_device(AUDCLNT_SHAREMODE mode, int fd,
841 const WAVEFORMATEX *fmt, WAVEFORMATEX **out)
846 WAVEFORMATEX *closest = NULL;
848 tmp = oss_format = get_oss_format(fmt);
850 return AUDCLNT_E_UNSUPPORTED_FORMAT;
851 if(ioctl(fd, SNDCTL_DSP_SETFMT, &tmp) < 0){
852 WARN("SETFMT failed: %d (%s)\n", errno, strerror(errno));
855 if(tmp != oss_format){
856 TRACE("Format unsupported by this OSS version: %x\n", oss_format);
857 return AUDCLNT_E_UNSUPPORTED_FORMAT;
860 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
861 (fmt->nAvgBytesPerSec == 0 ||
862 fmt->nBlockAlign == 0 ||
863 ((WAVEFORMATEXTENSIBLE*)fmt)->Samples.wValidBitsPerSample > fmt->wBitsPerSample))
866 if(fmt->nChannels == 0)
867 return AUDCLNT_E_UNSUPPORTED_FORMAT;
869 closest = clone_format(fmt);
871 return E_OUTOFMEMORY;
873 tmp = fmt->nSamplesPerSec;
874 if(ioctl(fd, SNDCTL_DSP_SPEED, &tmp) < 0){
875 WARN("SPEED failed: %d (%s)\n", errno, strerror(errno));
876 CoTaskMemFree(closest);
879 tenth = fmt->nSamplesPerSec * 0.1;
880 if(tmp > fmt->nSamplesPerSec + tenth || tmp < fmt->nSamplesPerSec - tenth){
882 closest->nSamplesPerSec = tmp;
885 tmp = fmt->nChannels;
886 if(ioctl(fd, SNDCTL_DSP_CHANNELS, &tmp) < 0){
887 WARN("CHANNELS failed: %d (%s)\n", errno, strerror(errno));
888 CoTaskMemFree(closest);
891 if(tmp != fmt->nChannels){
893 closest->nChannels = tmp;
896 if(closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
897 ((WAVEFORMATEXTENSIBLE*)closest)->dwChannelMask = get_channel_mask(closest->nChannels);
899 if(fmt->nBlockAlign != fmt->nChannels * fmt->wBitsPerSample / 8 ||
900 fmt->nAvgBytesPerSec != fmt->nBlockAlign * fmt->nSamplesPerSec ||
901 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
902 ((WAVEFORMATEXTENSIBLE*)fmt)->Samples.wValidBitsPerSample < fmt->wBitsPerSample))
905 if(mode == AUDCLNT_SHAREMODE_EXCLUSIVE &&
906 fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
907 if(((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask == 0 ||
908 ((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask & SPEAKER_RESERVED)
912 if(ret == S_FALSE && !out)
913 ret = AUDCLNT_E_UNSUPPORTED_FORMAT;
915 if(ret == S_FALSE && out){
916 closest->nBlockAlign =
917 closest->nChannels * closest->wBitsPerSample / 8;
918 closest->nAvgBytesPerSec =
919 closest->nBlockAlign * closest->nSamplesPerSec;
920 if(closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
921 ((WAVEFORMATEXTENSIBLE*)closest)->Samples.wValidBitsPerSample = closest->wBitsPerSample;
924 CoTaskMemFree(closest);
926 TRACE("returning: %08x\n", ret);
930 static void session_init_vols(AudioSession *session, UINT channels)
932 if(session->channel_count < channels){
935 if(session->channel_vols)
936 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
937 session->channel_vols, sizeof(float) * channels);
939 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
940 sizeof(float) * channels);
941 if(!session->channel_vols)
944 for(i = session->channel_count; i < channels; ++i)
945 session->channel_vols[i] = 1.f;
947 session->channel_count = channels;
951 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
956 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
960 memcpy(&ret->guid, guid, sizeof(GUID));
962 ret->device = device;
964 list_init(&ret->clients);
966 list_add_head(&g_sessions, &ret->entry);
968 InitializeCriticalSection(&ret->lock);
969 ret->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": AudioSession.lock");
971 session_init_vols(ret, num_channels);
973 ret->master_vol = 1.f;
978 /* if channels == 0, then this will return or create a session with
979 * matching dataflow and GUID. otherwise, channels must also match */
980 static HRESULT get_audio_session(const GUID *sessionguid,
981 IMMDevice *device, UINT channels, AudioSession **out)
983 AudioSession *session;
985 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
986 *out = create_session(&GUID_NULL, device, channels);
988 return E_OUTOFMEMORY;
994 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
995 if(session->device == device &&
996 IsEqualGUID(sessionguid, &session->guid)){
997 session_init_vols(session, channels);
1004 *out = create_session(sessionguid, device, channels);
1006 return E_OUTOFMEMORY;
1012 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
1013 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
1014 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
1015 const GUID *sessionguid)
1017 ACImpl *This = impl_from_IAudioClient(iface);
1021 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
1022 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
1029 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1030 return AUDCLNT_E_NOT_INITIALIZED;
1032 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
1033 AUDCLNT_STREAMFLAGS_LOOPBACK |
1034 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
1035 AUDCLNT_STREAMFLAGS_NOPERSIST |
1036 AUDCLNT_STREAMFLAGS_RATEADJUST |
1037 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
1038 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
1039 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
1040 TRACE("Unknown flags: %08x\n", flags);
1041 return E_INVALIDARG;
1044 if(mode == AUDCLNT_SHAREMODE_SHARED){
1045 period = DefaultPeriod;
1046 if( duration < 3 * period)
1047 duration = 3 * period;
1050 period = DefaultPeriod; /* not minimum */
1051 if(period < MinimumPeriod || period > 5000000)
1052 return AUDCLNT_E_INVALID_DEVICE_PERIOD;
1053 if(duration > 20000000) /* the smaller the period, the lower this limit */
1054 return AUDCLNT_E_BUFFER_SIZE_ERROR;
1055 if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){
1056 if(duration != period)
1057 return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
1058 FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
1059 return AUDCLNT_E_DEVICE_IN_USE;
1061 if( duration < 8 * period)
1062 duration = 8 * period; /* may grow above 2s */
1066 EnterCriticalSection(&This->lock);
1069 LeaveCriticalSection(&This->lock);
1070 return AUDCLNT_E_ALREADY_INITIALIZED;
1073 hr = setup_oss_device(mode, This->fd, fmt, NULL);
1075 LeaveCriticalSection(&This->lock);
1079 This->fmt = clone_format(fmt);
1081 LeaveCriticalSection(&This->lock);
1082 return E_OUTOFMEMORY;
1085 This->period_us = period / 10;
1086 This->period_frames = MulDiv(fmt->nSamplesPerSec, period, 10000000);
1088 This->bufsize_frames = MulDiv(duration, fmt->nSamplesPerSec, 10000000);
1089 This->local_buffer = HeapAlloc(GetProcessHeap(), 0,
1090 This->bufsize_frames * fmt->nBlockAlign);
1091 if(!This->local_buffer){
1092 CoTaskMemFree(This->fmt);
1094 LeaveCriticalSection(&This->lock);
1095 return E_OUTOFMEMORY;
1098 This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
1100 CoTaskMemFree(This->fmt);
1102 LeaveCriticalSection(&This->lock);
1103 return E_OUTOFMEMORY;
1106 for(i = 0; i < fmt->nChannels; ++i)
1107 This->vols[i] = 1.f;
1110 This->flags = flags;
1111 This->oss_bufsize_bytes = 0;
1113 EnterCriticalSection(&g_sessions_lock);
1115 hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
1118 LeaveCriticalSection(&g_sessions_lock);
1119 HeapFree(GetProcessHeap(), 0, This->vols);
1121 CoTaskMemFree(This->fmt);
1123 LeaveCriticalSection(&This->lock);
1127 list_add_tail(&This->session->clients, &This->entry);
1129 LeaveCriticalSection(&g_sessions_lock);
1131 This->initted = TRUE;
1133 LeaveCriticalSection(&This->lock);
1138 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
1141 ACImpl *This = impl_from_IAudioClient(iface);
1143 TRACE("(%p)->(%p)\n", This, frames);
1148 EnterCriticalSection(&This->lock);
1151 LeaveCriticalSection(&This->lock);
1152 return AUDCLNT_E_NOT_INITIALIZED;
1155 *frames = This->bufsize_frames;
1157 TRACE("buffer size: %u\n", *frames);
1159 LeaveCriticalSection(&This->lock);
1164 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
1165 REFERENCE_TIME *latency)
1167 ACImpl *This = impl_from_IAudioClient(iface);
1169 TRACE("(%p)->(%p)\n", This, latency);
1174 EnterCriticalSection(&This->lock);
1177 LeaveCriticalSection(&This->lock);
1178 return AUDCLNT_E_NOT_INITIALIZED;
1181 /* pretend we process audio in Period chunks, so max latency includes
1182 * the period time. Some native machines add .6666ms in shared mode. */
1183 *latency = This->period_us * 10 + 6666;
1185 LeaveCriticalSection(&This->lock);
1190 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1193 ACImpl *This = impl_from_IAudioClient(iface);
1195 TRACE("(%p)->(%p)\n", This, numpad);
1200 EnterCriticalSection(&This->lock);
1203 LeaveCriticalSection(&This->lock);
1204 return AUDCLNT_E_NOT_INITIALIZED;
1207 *numpad = This->held_frames;
1209 TRACE("padding: %u\n", *numpad);
1211 LeaveCriticalSection(&This->lock);
1216 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1217 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1218 WAVEFORMATEX **outpwfx)
1220 ACImpl *This = impl_from_IAudioClient(iface);
1224 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1226 if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1229 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1230 return E_INVALIDARG;
1232 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1233 pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1234 return E_INVALIDARG;
1240 if(mode != AUDCLNT_SHAREMODE_SHARED)
1244 if(This->dataflow == eRender)
1245 fd = open(This->devnode, O_WRONLY | O_NONBLOCK, 0);
1246 else if(This->dataflow == eCapture)
1247 fd = open(This->devnode, O_RDONLY | O_NONBLOCK, 0);
1250 WARN("Unable to open device %s: %d (%s)\n", This->devnode, errno,
1252 return AUDCLNT_E_DEVICE_INVALIDATED;
1255 ret = setup_oss_device(mode, fd, pwfx, outpwfx);
1262 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1263 WAVEFORMATEX **pwfx)
1265 ACImpl *This = impl_from_IAudioClient(iface);
1266 WAVEFORMATEXTENSIBLE *fmt;
1269 TRACE("(%p)->(%p)\n", This, pwfx);
1275 if(This->dataflow == eRender)
1276 formats = This->ai.oformats;
1277 else if(This->dataflow == eCapture)
1278 formats = This->ai.iformats;
1280 return E_UNEXPECTED;
1282 fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1284 return E_OUTOFMEMORY;
1286 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1287 if(formats & AFMT_S16_LE){
1288 fmt->Format.wBitsPerSample = 16;
1289 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1291 }else if(formats & AFMT_FLOAT){
1292 fmt->Format.wBitsPerSample = 32;
1293 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1295 }else if(formats & AFMT_U8){
1296 fmt->Format.wBitsPerSample = 8;
1297 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1298 }else if(formats & AFMT_S32_LE){
1299 fmt->Format.wBitsPerSample = 32;
1300 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1301 }else if(formats & AFMT_S24_LE){
1302 fmt->Format.wBitsPerSample = 24;
1303 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1305 WARN("Didn't recognize any available OSS formats: %x\n", formats);
1310 /* some OSS drivers are buggy, so set reasonable defaults if
1311 * the reported values seem wacky */
1312 fmt->Format.nChannels = max(This->ai.max_channels, This->ai.min_channels);
1313 if(fmt->Format.nChannels == 0 || fmt->Format.nChannels > 8)
1314 fmt->Format.nChannels = 2;
1316 if(This->ai.max_rate == 0)
1317 fmt->Format.nSamplesPerSec = 44100;
1319 fmt->Format.nSamplesPerSec = min(This->ai.max_rate, 44100);
1320 if(fmt->Format.nSamplesPerSec < This->ai.min_rate)
1321 fmt->Format.nSamplesPerSec = This->ai.min_rate;
1323 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1325 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1326 fmt->Format.nChannels) / 8;
1327 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1328 fmt->Format.nBlockAlign;
1330 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1331 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1333 *pwfx = (WAVEFORMATEX*)fmt;
1339 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1340 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1342 ACImpl *This = impl_from_IAudioClient(iface);
1344 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1346 if(!defperiod && !minperiod)
1350 *defperiod = DefaultPeriod;
1352 *minperiod = MinimumPeriod;
1357 static void oss_silence_buffer(ACImpl *This, BYTE *buf, UINT32 frames)
1359 if(This->fmt->wBitsPerSample == 8)
1360 memset(buf, 128, frames * This->fmt->nBlockAlign);
1362 memset(buf, 0, frames * This->fmt->nBlockAlign);
1365 static void oss_write_data(ACImpl *This)
1367 ssize_t written_bytes;
1368 UINT32 written_frames, in_oss_frames, write_limit, max_period;
1369 size_t to_write_frames, to_write_bytes;
1372 This->local_buffer + (This->lcl_offs_frames * This->fmt->nBlockAlign);
1374 if(This->held_frames == 0)
1377 if(This->lcl_offs_frames + This->held_frames > This->bufsize_frames)
1378 to_write_frames = This->bufsize_frames - This->lcl_offs_frames;
1380 to_write_frames = This->held_frames;
1382 if(ioctl(This->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0){
1383 WARN("GETOSPACE failed: %d (%s)\n", errno, strerror(errno));
1387 max_period = max(bi.fragsize / This->fmt->nBlockAlign, This->period_frames);
1389 if(bi.bytes > This->oss_bufsize_bytes){
1390 TRACE("New buffer size (%u) is larger than old buffer size (%u)\n",
1391 bi.bytes, This->oss_bufsize_bytes);
1392 This->oss_bufsize_bytes = bi.bytes;
1394 }else if(This->oss_bufsize_bytes - bi.bytes <= bi.fragsize)
1397 in_oss_frames = (This->oss_bufsize_bytes - bi.bytes) / This->fmt->nBlockAlign;
1400 while(write_limit + in_oss_frames < max_period * 3)
1401 write_limit += max_period;
1402 if(write_limit == 0)
1405 to_write_frames = min(to_write_frames, write_limit);
1406 to_write_bytes = to_write_frames * This->fmt->nBlockAlign;
1408 if(This->session->mute)
1409 oss_silence_buffer(This, buf, to_write_frames);
1411 written_bytes = write(This->fd, buf, to_write_bytes);
1412 if(written_bytes < 0){
1413 /* EAGAIN is OSS buffer full, log that too */
1414 WARN("write failed: %d (%s)\n", errno, strerror(errno));
1417 written_frames = written_bytes / This->fmt->nBlockAlign;
1419 This->lcl_offs_frames += written_frames;
1420 This->lcl_offs_frames %= This->bufsize_frames;
1421 This->held_frames -= written_frames;
1423 if(written_frames < to_write_frames){
1424 /* OSS buffer probably full */
1428 if(This->held_frames && written_frames < write_limit){
1429 /* wrapped and have some data back at the start to write */
1431 to_write_frames = min(write_limit - written_frames, This->held_frames);
1432 to_write_bytes = to_write_frames * This->fmt->nBlockAlign;
1434 if(This->session->mute)
1435 oss_silence_buffer(This, This->local_buffer, to_write_frames);
1437 written_bytes = write(This->fd, This->local_buffer, to_write_bytes);
1438 if(written_bytes < 0){
1439 WARN("write failed: %d (%s)\n", errno, strerror(errno));
1442 written_frames = written_bytes / This->fmt->nBlockAlign;
1444 This->lcl_offs_frames += written_frames;
1445 This->lcl_offs_frames %= This->bufsize_frames;
1446 This->held_frames -= written_frames;
1450 static void oss_read_data(ACImpl *This)
1452 UINT64 pos, readable;
1456 if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
1457 WARN("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
1461 pos = (This->held_frames + This->lcl_offs_frames) % This->bufsize_frames;
1462 readable = (This->bufsize_frames - pos) * This->fmt->nBlockAlign;
1464 if(bi.bytes < readable)
1465 readable = bi.bytes;
1467 nread = read(This->fd, This->local_buffer + pos * This->fmt->nBlockAlign,
1470 WARN("read failed: %d (%s)\n", errno, strerror(errno));
1474 This->held_frames += nread / This->fmt->nBlockAlign;
1476 if(This->held_frames > This->bufsize_frames){
1477 WARN("Overflow of unread data\n");
1478 This->lcl_offs_frames += This->held_frames;
1479 This->lcl_offs_frames %= This->bufsize_frames;
1480 This->held_frames = This->bufsize_frames;
1484 static void CALLBACK oss_period_callback(void *user, BOOLEAN timer)
1486 ACImpl *This = user;
1488 EnterCriticalSection(&This->lock);
1491 if(This->dataflow == eRender && This->held_frames)
1492 oss_write_data(This);
1493 else if(This->dataflow == eCapture)
1494 oss_read_data(This);
1497 LeaveCriticalSection(&This->lock);
1500 SetEvent(This->event);
1503 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1505 ACImpl *This = impl_from_IAudioClient(iface);
1507 TRACE("(%p)\n", This);
1509 EnterCriticalSection(&This->lock);
1512 LeaveCriticalSection(&This->lock);
1513 return AUDCLNT_E_NOT_INITIALIZED;
1516 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1517 LeaveCriticalSection(&This->lock);
1518 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1522 LeaveCriticalSection(&This->lock);
1523 return AUDCLNT_E_NOT_STOPPED;
1526 if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1527 oss_period_callback, This, 0, This->period_us / 1000,
1528 WT_EXECUTEINTIMERTHREAD))
1529 ERR("Unable to create period timer: %u\n", GetLastError());
1531 This->playing = TRUE;
1533 LeaveCriticalSection(&This->lock);
1538 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1540 ACImpl *This = impl_from_IAudioClient(iface);
1544 TRACE("(%p)\n", This);
1546 EnterCriticalSection(&This->lock);
1549 LeaveCriticalSection(&This->lock);
1550 return AUDCLNT_E_NOT_INITIALIZED;
1554 LeaveCriticalSection(&This->lock);
1558 event = CreateEventW(NULL, TRUE, FALSE, NULL);
1559 wait = !DeleteTimerQueueTimer(g_timer_q, This->timer, event);
1561 WARN("DeleteTimerQueueTimer error %u\n", GetLastError());
1562 wait = wait && GetLastError() == ERROR_IO_PENDING;
1564 This->playing = FALSE;
1566 LeaveCriticalSection(&This->lock);
1569 WaitForSingleObject(event, INFINITE);
1575 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1577 ACImpl *This = impl_from_IAudioClient(iface);
1579 TRACE("(%p)\n", This);
1581 EnterCriticalSection(&This->lock);
1584 LeaveCriticalSection(&This->lock);
1585 return AUDCLNT_E_NOT_INITIALIZED;
1589 LeaveCriticalSection(&This->lock);
1590 return AUDCLNT_E_NOT_STOPPED;
1593 if(This->getbuf_last){
1594 LeaveCriticalSection(&This->lock);
1595 return AUDCLNT_E_BUFFER_OPERATION_PENDING;
1598 if(This->dataflow == eRender){
1599 This->written_frames = 0;
1600 This->last_pos_frames = 0;
1602 This->written_frames += This->held_frames;
1604 This->held_frames = 0;
1605 This->lcl_offs_frames = 0;
1607 LeaveCriticalSection(&This->lock);
1612 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1615 ACImpl *This = impl_from_IAudioClient(iface);
1617 TRACE("(%p)->(%p)\n", This, event);
1620 return E_INVALIDARG;
1622 EnterCriticalSection(&This->lock);
1625 LeaveCriticalSection(&This->lock);
1626 return AUDCLNT_E_NOT_INITIALIZED;
1629 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1630 LeaveCriticalSection(&This->lock);
1631 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1635 LeaveCriticalSection(&This->lock);
1636 FIXME("called twice\n");
1637 return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
1640 This->event = event;
1642 LeaveCriticalSection(&This->lock);
1647 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1650 ACImpl *This = impl_from_IAudioClient(iface);
1652 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1658 EnterCriticalSection(&This->lock);
1661 LeaveCriticalSection(&This->lock);
1662 return AUDCLNT_E_NOT_INITIALIZED;
1665 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1666 if(This->dataflow != eRender){
1667 LeaveCriticalSection(&This->lock);
1668 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1670 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1671 *ppv = &This->IAudioRenderClient_iface;
1672 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1673 if(This->dataflow != eCapture){
1674 LeaveCriticalSection(&This->lock);
1675 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1677 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1678 *ppv = &This->IAudioCaptureClient_iface;
1679 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1680 IAudioClock_AddRef(&This->IAudioClock_iface);
1681 *ppv = &This->IAudioClock_iface;
1682 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1683 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1684 *ppv = &This->IAudioStreamVolume_iface;
1685 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1686 if(!This->session_wrapper){
1687 This->session_wrapper = AudioSessionWrapper_Create(This);
1688 if(!This->session_wrapper){
1689 LeaveCriticalSection(&This->lock);
1690 return E_OUTOFMEMORY;
1693 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1695 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1696 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1697 if(!This->session_wrapper){
1698 This->session_wrapper = AudioSessionWrapper_Create(This);
1699 if(!This->session_wrapper){
1700 LeaveCriticalSection(&This->lock);
1701 return E_OUTOFMEMORY;
1704 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1706 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1707 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1708 if(!This->session_wrapper){
1709 This->session_wrapper = AudioSessionWrapper_Create(This);
1710 if(!This->session_wrapper){
1711 LeaveCriticalSection(&This->lock);
1712 return E_OUTOFMEMORY;
1715 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1717 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1721 LeaveCriticalSection(&This->lock);
1725 LeaveCriticalSection(&This->lock);
1727 FIXME("stub %s\n", debugstr_guid(riid));
1728 return E_NOINTERFACE;
1731 static const IAudioClientVtbl AudioClient_Vtbl =
1733 AudioClient_QueryInterface,
1735 AudioClient_Release,
1736 AudioClient_Initialize,
1737 AudioClient_GetBufferSize,
1738 AudioClient_GetStreamLatency,
1739 AudioClient_GetCurrentPadding,
1740 AudioClient_IsFormatSupported,
1741 AudioClient_GetMixFormat,
1742 AudioClient_GetDevicePeriod,
1746 AudioClient_SetEventHandle,
1747 AudioClient_GetService
1750 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1751 IAudioRenderClient *iface, REFIID riid, void **ppv)
1753 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1759 if(IsEqualIID(riid, &IID_IUnknown) ||
1760 IsEqualIID(riid, &IID_IAudioRenderClient))
1763 IUnknown_AddRef((IUnknown*)*ppv);
1767 WARN("Unknown interface %s\n", debugstr_guid(riid));
1768 return E_NOINTERFACE;
1771 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1773 ACImpl *This = impl_from_IAudioRenderClient(iface);
1774 return AudioClient_AddRef(&This->IAudioClient_iface);
1777 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1779 ACImpl *This = impl_from_IAudioRenderClient(iface);
1780 return AudioClient_Release(&This->IAudioClient_iface);
1783 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1784 UINT32 frames, BYTE **data)
1786 ACImpl *This = impl_from_IAudioRenderClient(iface);
1789 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1796 EnterCriticalSection(&This->lock);
1798 if(This->getbuf_last){
1799 LeaveCriticalSection(&This->lock);
1800 return AUDCLNT_E_OUT_OF_ORDER;
1804 LeaveCriticalSection(&This->lock);
1808 if(This->held_frames + frames > This->bufsize_frames){
1809 LeaveCriticalSection(&This->lock);
1810 return AUDCLNT_E_BUFFER_TOO_LARGE;
1814 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1815 if(write_pos + frames > This->bufsize_frames){
1816 if(This->tmp_buffer_frames < frames){
1817 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1818 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1819 frames * This->fmt->nBlockAlign);
1820 if(!This->tmp_buffer){
1821 LeaveCriticalSection(&This->lock);
1822 return E_OUTOFMEMORY;
1824 This->tmp_buffer_frames = frames;
1826 *data = This->tmp_buffer;
1827 This->getbuf_last = -frames;
1829 *data = This->local_buffer + write_pos * This->fmt->nBlockAlign;
1830 This->getbuf_last = frames;
1833 LeaveCriticalSection(&This->lock);
1838 static void oss_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_frames)
1840 UINT32 write_offs_frames =
1841 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1842 UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
1843 UINT32 chunk_frames = This->bufsize_frames - write_offs_frames;
1844 UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
1845 UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
1847 if(written_bytes <= chunk_bytes){
1848 memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
1850 memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
1851 memcpy(This->local_buffer, buffer + chunk_bytes,
1852 written_bytes - chunk_bytes);
1856 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1857 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1859 ACImpl *This = impl_from_IAudioRenderClient(iface);
1862 TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1864 EnterCriticalSection(&This->lock);
1866 if(!written_frames){
1867 This->getbuf_last = 0;
1868 LeaveCriticalSection(&This->lock);
1872 if(!This->getbuf_last){
1873 LeaveCriticalSection(&This->lock);
1874 return AUDCLNT_E_OUT_OF_ORDER;
1877 if(written_frames > (This->getbuf_last >= 0 ? This->getbuf_last : -This->getbuf_last)){
1878 LeaveCriticalSection(&This->lock);
1879 return AUDCLNT_E_INVALID_SIZE;
1882 if(This->getbuf_last >= 0)
1883 buffer = This->local_buffer + This->fmt->nBlockAlign *
1884 ((This->lcl_offs_frames + This->held_frames) % This->bufsize_frames);
1886 buffer = This->tmp_buffer;
1888 if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
1889 oss_silence_buffer(This, buffer, written_frames);
1891 if(This->getbuf_last < 0)
1892 oss_wrap_buffer(This, buffer, written_frames);
1894 This->held_frames += written_frames;
1895 This->written_frames += written_frames;
1896 This->getbuf_last = 0;
1898 LeaveCriticalSection(&This->lock);
1903 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1904 AudioRenderClient_QueryInterface,
1905 AudioRenderClient_AddRef,
1906 AudioRenderClient_Release,
1907 AudioRenderClient_GetBuffer,
1908 AudioRenderClient_ReleaseBuffer
1911 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1912 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1914 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1920 if(IsEqualIID(riid, &IID_IUnknown) ||
1921 IsEqualIID(riid, &IID_IAudioCaptureClient))
1924 IUnknown_AddRef((IUnknown*)*ppv);
1928 WARN("Unknown interface %s\n", debugstr_guid(riid));
1929 return E_NOINTERFACE;
1932 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1934 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1935 return IAudioClient_AddRef(&This->IAudioClient_iface);
1938 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1940 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1941 return IAudioClient_Release(&This->IAudioClient_iface);
1944 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1945 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1948 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1950 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1953 if(!data || !frames || !flags)
1956 EnterCriticalSection(&This->lock);
1958 if(This->getbuf_last){
1959 LeaveCriticalSection(&This->lock);
1960 return AUDCLNT_E_OUT_OF_ORDER;
1963 if(This->held_frames < This->period_frames){
1965 LeaveCriticalSection(&This->lock);
1966 return AUDCLNT_S_BUFFER_EMPTY;
1971 *frames = This->period_frames;
1973 if(This->lcl_offs_frames + *frames > This->bufsize_frames){
1974 UINT32 chunk_bytes, offs_bytes, frames_bytes;
1975 if(This->tmp_buffer_frames < *frames){
1976 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1977 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1978 *frames * This->fmt->nBlockAlign);
1979 if(!This->tmp_buffer){
1980 LeaveCriticalSection(&This->lock);
1981 return E_OUTOFMEMORY;
1983 This->tmp_buffer_frames = *frames;
1986 *data = This->tmp_buffer;
1987 chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
1988 This->fmt->nBlockAlign;
1989 offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
1990 frames_bytes = *frames * This->fmt->nBlockAlign;
1991 memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
1992 memcpy(This->tmp_buffer + chunk_bytes, This->local_buffer,
1993 frames_bytes - chunk_bytes);
1995 *data = This->local_buffer +
1996 This->lcl_offs_frames * This->fmt->nBlockAlign;
1998 This->getbuf_last = *frames;
2001 *devpos = This->written_frames;
2003 LARGE_INTEGER stamp, freq;
2004 QueryPerformanceCounter(&stamp);
2005 QueryPerformanceFrequency(&freq);
2006 *qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2009 LeaveCriticalSection(&This->lock);
2011 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
2014 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
2015 IAudioCaptureClient *iface, UINT32 done)
2017 ACImpl *This = impl_from_IAudioCaptureClient(iface);
2019 TRACE("(%p)->(%u)\n", This, done);
2021 EnterCriticalSection(&This->lock);
2024 This->getbuf_last = 0;
2025 LeaveCriticalSection(&This->lock);
2029 if(!This->getbuf_last){
2030 LeaveCriticalSection(&This->lock);
2031 return AUDCLNT_E_OUT_OF_ORDER;
2034 if(This->getbuf_last != done){
2035 LeaveCriticalSection(&This->lock);
2036 return AUDCLNT_E_INVALID_SIZE;
2039 This->written_frames += done;
2040 This->held_frames -= done;
2041 This->lcl_offs_frames += done;
2042 This->lcl_offs_frames %= This->bufsize_frames;
2043 This->getbuf_last = 0;
2045 LeaveCriticalSection(&This->lock);
2050 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
2051 IAudioCaptureClient *iface, UINT32 *frames)
2053 ACImpl *This = impl_from_IAudioCaptureClient(iface);
2055 TRACE("(%p)->(%p)\n", This, frames);
2060 EnterCriticalSection(&This->lock);
2062 *frames = This->held_frames < This->period_frames ? 0 : This->period_frames;
2064 LeaveCriticalSection(&This->lock);
2069 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
2071 AudioCaptureClient_QueryInterface,
2072 AudioCaptureClient_AddRef,
2073 AudioCaptureClient_Release,
2074 AudioCaptureClient_GetBuffer,
2075 AudioCaptureClient_ReleaseBuffer,
2076 AudioCaptureClient_GetNextPacketSize
2079 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
2080 REFIID riid, void **ppv)
2082 ACImpl *This = impl_from_IAudioClock(iface);
2084 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2090 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
2092 else if(IsEqualIID(riid, &IID_IAudioClock2))
2093 *ppv = &This->IAudioClock2_iface;
2095 IUnknown_AddRef((IUnknown*)*ppv);
2099 WARN("Unknown interface %s\n", debugstr_guid(riid));
2100 return E_NOINTERFACE;
2103 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
2105 ACImpl *This = impl_from_IAudioClock(iface);
2106 return IAudioClient_AddRef(&This->IAudioClient_iface);
2109 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
2111 ACImpl *This = impl_from_IAudioClock(iface);
2112 return IAudioClient_Release(&This->IAudioClient_iface);
2115 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
2117 ACImpl *This = impl_from_IAudioClock(iface);
2119 TRACE("(%p)->(%p)\n", This, freq);
2121 *freq = This->fmt->nSamplesPerSec;
2126 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
2129 ACImpl *This = impl_from_IAudioClock(iface);
2132 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
2137 EnterCriticalSection(&This->lock);
2139 if(This->dataflow == eRender){
2140 if(!This->playing || !This->held_frames ||
2141 ioctl(This->fd, SNDCTL_DSP_GETODELAY, &delay) < 0)
2144 delay /= This->fmt->nBlockAlign;
2145 if(This->held_frames + delay >= This->written_frames)
2146 *pos = This->last_pos_frames;
2148 *pos = This->written_frames - This->held_frames - delay;
2149 if(*pos < This->last_pos_frames)
2150 *pos = This->last_pos_frames;
2152 }else if(This->dataflow == eCapture){
2156 if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
2157 TRACE("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
2160 if(bi.bytes <= bi.fragsize)
2163 held = bi.bytes / This->fmt->nBlockAlign;
2166 *pos = This->written_frames + held;
2169 This->last_pos_frames = *pos;
2171 LeaveCriticalSection(&This->lock);
2174 LARGE_INTEGER stamp, freq;
2175 QueryPerformanceCounter(&stamp);
2176 QueryPerformanceFrequency(&freq);
2177 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2183 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2186 ACImpl *This = impl_from_IAudioClock(iface);
2188 TRACE("(%p)->(%p)\n", This, chars);
2193 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2198 static const IAudioClockVtbl AudioClock_Vtbl =
2200 AudioClock_QueryInterface,
2203 AudioClock_GetFrequency,
2204 AudioClock_GetPosition,
2205 AudioClock_GetCharacteristics
2208 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2209 REFIID riid, void **ppv)
2211 ACImpl *This = impl_from_IAudioClock2(iface);
2212 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2215 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2217 ACImpl *This = impl_from_IAudioClock2(iface);
2218 return IAudioClient_AddRef(&This->IAudioClient_iface);
2221 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2223 ACImpl *This = impl_from_IAudioClock2(iface);
2224 return IAudioClient_Release(&This->IAudioClient_iface);
2227 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2228 UINT64 *pos, UINT64 *qpctime)
2230 ACImpl *This = impl_from_IAudioClock2(iface);
2232 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2237 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2239 AudioClock2_QueryInterface,
2241 AudioClock2_Release,
2242 AudioClock2_GetDevicePosition
2245 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2247 AudioSessionWrapper *ret;
2249 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2250 sizeof(AudioSessionWrapper));
2254 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2255 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2256 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2260 ret->client = client;
2262 ret->session = client->session;
2263 AudioClient_AddRef(&client->IAudioClient_iface);
2269 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2270 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2272 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2278 if(IsEqualIID(riid, &IID_IUnknown) ||
2279 IsEqualIID(riid, &IID_IAudioSessionControl) ||
2280 IsEqualIID(riid, &IID_IAudioSessionControl2))
2283 IUnknown_AddRef((IUnknown*)*ppv);
2287 WARN("Unknown interface %s\n", debugstr_guid(riid));
2288 return E_NOINTERFACE;
2291 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2293 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2295 ref = InterlockedIncrement(&This->ref);
2296 TRACE("(%p) Refcount now %u\n", This, ref);
2300 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2302 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2304 ref = InterlockedDecrement(&This->ref);
2305 TRACE("(%p) Refcount now %u\n", This, ref);
2308 EnterCriticalSection(&This->client->lock);
2309 This->client->session_wrapper = NULL;
2310 LeaveCriticalSection(&This->client->lock);
2311 AudioClient_Release(&This->client->IAudioClient_iface);
2313 HeapFree(GetProcessHeap(), 0, This);
2318 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2319 AudioSessionState *state)
2321 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2324 TRACE("(%p)->(%p)\n", This, state);
2327 return NULL_PTR_ERR;
2329 EnterCriticalSection(&g_sessions_lock);
2331 if(list_empty(&This->session->clients)){
2332 *state = AudioSessionStateExpired;
2333 LeaveCriticalSection(&g_sessions_lock);
2337 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2338 EnterCriticalSection(&client->lock);
2339 if(client->playing){
2340 *state = AudioSessionStateActive;
2341 LeaveCriticalSection(&client->lock);
2342 LeaveCriticalSection(&g_sessions_lock);
2345 LeaveCriticalSection(&client->lock);
2348 LeaveCriticalSection(&g_sessions_lock);
2350 *state = AudioSessionStateInactive;
2355 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2356 IAudioSessionControl2 *iface, WCHAR **name)
2358 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2360 FIXME("(%p)->(%p) - stub\n", This, name);
2365 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2366 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2368 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2370 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2375 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2376 IAudioSessionControl2 *iface, WCHAR **path)
2378 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2380 FIXME("(%p)->(%p) - stub\n", This, path);
2385 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2386 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2388 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2390 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2395 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2396 IAudioSessionControl2 *iface, GUID *group)
2398 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2400 FIXME("(%p)->(%p) - stub\n", This, group);
2405 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2406 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2408 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2410 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2411 debugstr_guid(session));
2416 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2417 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2419 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2421 FIXME("(%p)->(%p) - stub\n", This, events);
2426 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2427 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2429 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2431 FIXME("(%p)->(%p) - stub\n", This, events);
2436 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2437 IAudioSessionControl2 *iface, WCHAR **id)
2439 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2441 FIXME("(%p)->(%p) - stub\n", This, id);
2446 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2447 IAudioSessionControl2 *iface, WCHAR **id)
2449 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2451 FIXME("(%p)->(%p) - stub\n", This, id);
2456 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2457 IAudioSessionControl2 *iface, DWORD *pid)
2459 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2461 TRACE("(%p)->(%p)\n", This, pid);
2466 *pid = GetCurrentProcessId();
2471 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2472 IAudioSessionControl2 *iface)
2474 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2476 TRACE("(%p)\n", This);
2481 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2482 IAudioSessionControl2 *iface, BOOL optout)
2484 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2486 TRACE("(%p)->(%d)\n", This, optout);
2491 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2493 AudioSessionControl_QueryInterface,
2494 AudioSessionControl_AddRef,
2495 AudioSessionControl_Release,
2496 AudioSessionControl_GetState,
2497 AudioSessionControl_GetDisplayName,
2498 AudioSessionControl_SetDisplayName,
2499 AudioSessionControl_GetIconPath,
2500 AudioSessionControl_SetIconPath,
2501 AudioSessionControl_GetGroupingParam,
2502 AudioSessionControl_SetGroupingParam,
2503 AudioSessionControl_RegisterAudioSessionNotification,
2504 AudioSessionControl_UnregisterAudioSessionNotification,
2505 AudioSessionControl_GetSessionIdentifier,
2506 AudioSessionControl_GetSessionInstanceIdentifier,
2507 AudioSessionControl_GetProcessId,
2508 AudioSessionControl_IsSystemSoundsSession,
2509 AudioSessionControl_SetDuckingPreference
2512 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2513 ISimpleAudioVolume *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_ISimpleAudioVolume))
2525 IUnknown_AddRef((IUnknown*)*ppv);
2529 WARN("Unknown interface %s\n", debugstr_guid(riid));
2530 return E_NOINTERFACE;
2533 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2535 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2536 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2539 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2541 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2542 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2545 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2546 ISimpleAudioVolume *iface, float level, const GUID *context)
2548 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2549 AudioSession *session = This->session;
2551 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2553 if(level < 0.f || level > 1.f)
2554 return E_INVALIDARG;
2557 FIXME("Notifications not supported yet\n");
2559 EnterCriticalSection(&session->lock);
2561 session->master_vol = level;
2563 TRACE("OSS doesn't support setting volume\n");
2565 LeaveCriticalSection(&session->lock);
2570 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2571 ISimpleAudioVolume *iface, float *level)
2573 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2574 AudioSession *session = This->session;
2576 TRACE("(%p)->(%p)\n", session, level);
2579 return NULL_PTR_ERR;
2581 *level = session->master_vol;
2586 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2587 BOOL mute, const GUID *context)
2589 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2590 AudioSession *session = This->session;
2592 TRACE("(%p)->(%u, %p)\n", session, mute, context);
2594 EnterCriticalSection(&session->lock);
2596 session->mute = mute;
2598 LeaveCriticalSection(&session->lock);
2603 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2606 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2607 AudioSession *session = This->session;
2609 TRACE("(%p)->(%p)\n", session, mute);
2612 return NULL_PTR_ERR;
2614 *mute = This->session->mute;
2619 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2621 SimpleAudioVolume_QueryInterface,
2622 SimpleAudioVolume_AddRef,
2623 SimpleAudioVolume_Release,
2624 SimpleAudioVolume_SetMasterVolume,
2625 SimpleAudioVolume_GetMasterVolume,
2626 SimpleAudioVolume_SetMute,
2627 SimpleAudioVolume_GetMute
2630 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2631 IAudioStreamVolume *iface, REFIID riid, void **ppv)
2633 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2639 if(IsEqualIID(riid, &IID_IUnknown) ||
2640 IsEqualIID(riid, &IID_IAudioStreamVolume))
2643 IUnknown_AddRef((IUnknown*)*ppv);
2647 WARN("Unknown interface %s\n", debugstr_guid(riid));
2648 return E_NOINTERFACE;
2651 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2653 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2654 return IAudioClient_AddRef(&This->IAudioClient_iface);
2657 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2659 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2660 return IAudioClient_Release(&This->IAudioClient_iface);
2663 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2664 IAudioStreamVolume *iface, UINT32 *out)
2666 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2668 TRACE("(%p)->(%p)\n", This, out);
2673 *out = This->fmt->nChannels;
2678 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2679 IAudioStreamVolume *iface, UINT32 index, float level)
2681 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2683 TRACE("(%p)->(%d, %f)\n", This, index, level);
2685 if(level < 0.f || level > 1.f)
2686 return E_INVALIDARG;
2688 if(index >= This->fmt->nChannels)
2689 return E_INVALIDARG;
2691 EnterCriticalSection(&This->lock);
2693 This->vols[index] = level;
2695 TRACE("OSS doesn't support setting volume\n");
2697 LeaveCriticalSection(&This->lock);
2702 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2703 IAudioStreamVolume *iface, UINT32 index, float *level)
2705 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2707 TRACE("(%p)->(%d, %p)\n", This, index, level);
2712 if(index >= This->fmt->nChannels)
2713 return E_INVALIDARG;
2715 *level = This->vols[index];
2720 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2721 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2723 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2726 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2731 if(count != This->fmt->nChannels)
2732 return E_INVALIDARG;
2734 EnterCriticalSection(&This->lock);
2736 for(i = 0; i < count; ++i)
2737 This->vols[i] = levels[i];
2739 TRACE("OSS doesn't support setting volume\n");
2741 LeaveCriticalSection(&This->lock);
2746 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2747 IAudioStreamVolume *iface, UINT32 count, float *levels)
2749 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2752 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2757 if(count != This->fmt->nChannels)
2758 return E_INVALIDARG;
2760 EnterCriticalSection(&This->lock);
2762 for(i = 0; i < count; ++i)
2763 levels[i] = This->vols[i];
2765 LeaveCriticalSection(&This->lock);
2770 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2772 AudioStreamVolume_QueryInterface,
2773 AudioStreamVolume_AddRef,
2774 AudioStreamVolume_Release,
2775 AudioStreamVolume_GetChannelCount,
2776 AudioStreamVolume_SetChannelVolume,
2777 AudioStreamVolume_GetChannelVolume,
2778 AudioStreamVolume_SetAllVolumes,
2779 AudioStreamVolume_GetAllVolumes
2782 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2783 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2785 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2791 if(IsEqualIID(riid, &IID_IUnknown) ||
2792 IsEqualIID(riid, &IID_IChannelAudioVolume))
2795 IUnknown_AddRef((IUnknown*)*ppv);
2799 WARN("Unknown interface %s\n", debugstr_guid(riid));
2800 return E_NOINTERFACE;
2803 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2805 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2806 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2809 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2811 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2812 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2815 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2816 IChannelAudioVolume *iface, UINT32 *out)
2818 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2819 AudioSession *session = This->session;
2821 TRACE("(%p)->(%p)\n", session, out);
2824 return NULL_PTR_ERR;
2826 *out = session->channel_count;
2831 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2832 IChannelAudioVolume *iface, UINT32 index, float level,
2833 const GUID *context)
2835 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2836 AudioSession *session = This->session;
2838 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2839 wine_dbgstr_guid(context));
2841 if(level < 0.f || level > 1.f)
2842 return E_INVALIDARG;
2844 if(index >= session->channel_count)
2845 return E_INVALIDARG;
2848 FIXME("Notifications not supported yet\n");
2850 EnterCriticalSection(&session->lock);
2852 session->channel_vols[index] = level;
2854 TRACE("OSS doesn't support setting volume\n");
2856 LeaveCriticalSection(&session->lock);
2861 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2862 IChannelAudioVolume *iface, UINT32 index, float *level)
2864 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2865 AudioSession *session = This->session;
2867 TRACE("(%p)->(%d, %p)\n", session, index, level);
2870 return NULL_PTR_ERR;
2872 if(index >= session->channel_count)
2873 return E_INVALIDARG;
2875 *level = session->channel_vols[index];
2880 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2881 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2882 const GUID *context)
2884 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2885 AudioSession *session = This->session;
2888 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2889 wine_dbgstr_guid(context));
2892 return NULL_PTR_ERR;
2894 if(count != session->channel_count)
2895 return E_INVALIDARG;
2898 FIXME("Notifications not supported yet\n");
2900 EnterCriticalSection(&session->lock);
2902 for(i = 0; i < count; ++i)
2903 session->channel_vols[i] = levels[i];
2905 TRACE("OSS doesn't support setting volume\n");
2907 LeaveCriticalSection(&session->lock);
2912 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2913 IChannelAudioVolume *iface, UINT32 count, float *levels)
2915 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2916 AudioSession *session = This->session;
2919 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2922 return NULL_PTR_ERR;
2924 if(count != session->channel_count)
2925 return E_INVALIDARG;
2927 for(i = 0; i < count; ++i)
2928 levels[i] = session->channel_vols[i];
2933 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2935 ChannelAudioVolume_QueryInterface,
2936 ChannelAudioVolume_AddRef,
2937 ChannelAudioVolume_Release,
2938 ChannelAudioVolume_GetChannelCount,
2939 ChannelAudioVolume_SetChannelVolume,
2940 ChannelAudioVolume_GetChannelVolume,
2941 ChannelAudioVolume_SetAllVolumes,
2942 ChannelAudioVolume_GetAllVolumes
2945 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2946 REFIID riid, void **ppv)
2948 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2954 if(IsEqualIID(riid, &IID_IUnknown) ||
2955 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2956 IsEqualIID(riid, &IID_IAudioSessionManager2))
2959 IUnknown_AddRef((IUnknown*)*ppv);
2963 WARN("Unknown interface %s\n", debugstr_guid(riid));
2964 return E_NOINTERFACE;
2967 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2969 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2971 ref = InterlockedIncrement(&This->ref);
2972 TRACE("(%p) Refcount now %u\n", This, ref);
2976 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2978 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2980 ref = InterlockedDecrement(&This->ref);
2981 TRACE("(%p) Refcount now %u\n", This, ref);
2983 HeapFree(GetProcessHeap(), 0, This);
2987 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2988 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2989 IAudioSessionControl **out)
2991 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2992 AudioSession *session;
2993 AudioSessionWrapper *wrapper;
2996 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2999 hr = get_audio_session(session_guid, This->device, 0, &session);
3003 wrapper = AudioSessionWrapper_Create(NULL);
3005 return E_OUTOFMEMORY;
3007 wrapper->session = session;
3009 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
3014 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
3015 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
3016 ISimpleAudioVolume **out)
3018 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3019 AudioSession *session;
3020 AudioSessionWrapper *wrapper;
3023 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
3026 hr = get_audio_session(session_guid, This->device, 0, &session);
3030 wrapper = AudioSessionWrapper_Create(NULL);
3032 return E_OUTOFMEMORY;
3034 wrapper->session = session;
3036 *out = &wrapper->ISimpleAudioVolume_iface;
3041 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
3042 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
3044 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3045 FIXME("(%p)->(%p) - stub\n", This, out);
3049 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
3050 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
3052 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3053 FIXME("(%p)->(%p) - stub\n", This, notification);
3057 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
3058 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
3060 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3061 FIXME("(%p)->(%p) - stub\n", This, notification);
3065 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
3066 IAudioSessionManager2 *iface, const WCHAR *session_id,
3067 IAudioVolumeDuckNotification *notification)
3069 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3070 FIXME("(%p)->(%p) - stub\n", This, notification);
3074 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
3075 IAudioSessionManager2 *iface,
3076 IAudioVolumeDuckNotification *notification)
3078 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3079 FIXME("(%p)->(%p) - stub\n", This, notification);
3083 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
3085 AudioSessionManager_QueryInterface,
3086 AudioSessionManager_AddRef,
3087 AudioSessionManager_Release,
3088 AudioSessionManager_GetAudioSessionControl,
3089 AudioSessionManager_GetSimpleAudioVolume,
3090 AudioSessionManager_GetSessionEnumerator,
3091 AudioSessionManager_RegisterSessionNotification,
3092 AudioSessionManager_UnregisterSessionNotification,
3093 AudioSessionManager_RegisterDuckNotification,
3094 AudioSessionManager_UnregisterDuckNotification
3097 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
3098 IAudioSessionManager2 **out)
3102 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
3104 return E_OUTOFMEMORY;
3106 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
3107 This->device = device;
3110 *out = &This->IAudioSessionManager2_iface;