winewayland.drv: Implement vkGetPhysicalDeviceSurfaceSupportKHR.
[wine.git] / dlls / winecoreaudio.drv / coreaudio.c
blob3299b84d489c14e3c1d6b3bc7a374fcecaf61616
1 /*
2 * Unixlib for winecoreaudio driver.
4 * Copyright 2011 Andrew Eikum for CodeWeavers
5 * Copyright 2021 Huw Davies
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #if 0
22 #pragma makedep unix
23 #endif
25 #include "config.h"
27 #define LoadResource __carbon_LoadResource
28 #define CompareString __carbon_CompareString
29 #define GetCurrentThread __carbon_GetCurrentThread
30 #define GetCurrentProcess __carbon_GetCurrentProcess
32 #include <stdarg.h>
34 #include <errno.h>
35 #include <limits.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <sys/ioctl.h>
42 #include <fcntl.h>
43 #include <fenv.h>
44 #include <unistd.h>
46 #include <CoreAudio/CoreAudio.h>
47 #include <AudioToolbox/AudioFormat.h>
48 #include <AudioToolbox/AudioConverter.h>
49 #include <AudioUnit/AudioUnit.h>
51 #undef LoadResource
52 #undef CompareString
53 #undef GetCurrentThread
54 #undef GetCurrentProcess
55 #undef _CDECL
57 #include "ntstatus.h"
58 #define WIN32_NO_STATUS
59 #include "windef.h"
60 #include "winbase.h"
61 #include "winnls.h"
62 #include "winreg.h"
63 #include "winternl.h"
64 #include "mmdeviceapi.h"
65 #include "initguid.h"
66 #include "audioclient.h"
67 #include "wine/debug.h"
68 #include "wine/unixlib.h"
70 #include "unixlib.h"
72 #if !defined(MAC_OS_VERSION_12_0) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_VERSION_12_0
73 #define kAudioObjectPropertyElementMain kAudioObjectPropertyElementMaster
74 #endif
76 #if defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
77 #include <os/lock.h>
78 #else
79 #include <libkern/OSAtomic.h>
80 typedef OSSpinLock os_unfair_lock;
81 #define os_unfair_lock_lock(lock) OSSpinLockLock(lock)
82 #define os_unfair_lock_unlock(lock) OSSpinLockUnlock(lock)
83 #endif
85 WINE_DEFAULT_DEBUG_CHANNEL(coreaudio);
87 #define MAX_DEV_NAME_LEN 10 /* Max 32 bit digits */
89 struct coreaudio_stream
91 os_unfair_lock lock;
92 AudioComponentInstance unit;
93 AudioConverterRef converter;
94 AudioStreamBasicDescription dev_desc; /* audio unit format, not necessarily the same as fmt */
95 AudioDeviceID dev_id;
97 EDataFlow flow;
98 DWORD flags;
99 AUDCLNT_SHAREMODE share;
100 HANDLE event;
102 BOOL playing, please_quit;
103 REFERENCE_TIME period;
104 UINT32 period_frames;
105 UINT32 bufsize_frames, resamp_bufsize_frames;
106 UINT32 lcl_offs_frames, held_frames, wri_offs_frames, tmp_buffer_frames;
107 UINT32 cap_bufsize_frames, cap_offs_frames, cap_held_frames;
108 UINT32 wrap_bufsize_frames;
109 UINT64 written_frames;
110 INT32 getbuf_last;
111 WAVEFORMATEX *fmt;
112 BYTE *local_buffer, *cap_buffer, *wrap_buffer, *resamp_buffer, *tmp_buffer;
115 static const REFERENCE_TIME def_period = 100000;
116 static const REFERENCE_TIME min_period = 50000;
118 static ULONG_PTR zero_bits = 0;
120 static NTSTATUS unix_not_implemented(void *args)
122 return STATUS_SUCCESS;
125 static HRESULT osstatus_to_hresult(OSStatus sc)
127 switch(sc){
128 case kAudioFormatUnsupportedDataFormatError:
129 case kAudioFormatUnknownFormatError:
130 case kAudioDeviceUnsupportedFormatError:
131 return AUDCLNT_E_UNSUPPORTED_FORMAT;
132 case kAudioHardwareBadDeviceError:
133 return AUDCLNT_E_DEVICE_INVALIDATED;
135 return E_FAIL;
138 static struct coreaudio_stream *handle_get_stream(stream_handle h)
140 return (struct coreaudio_stream *)(UINT_PTR)h;
143 /* copied from kernelbase */
144 static int muldiv( int a, int b, int c )
146 LONGLONG ret;
148 if (!c) return -1;
150 /* We want to deal with a positive divisor to simplify the logic. */
151 if (c < 0)
153 a = -a;
154 c = -c;
157 /* If the result is positive, we "add" to round. else, we subtract to round. */
158 if ((a < 0 && b < 0) || (a >= 0 && b >= 0))
159 ret = (((LONGLONG)a * b) + (c / 2)) / c;
160 else
161 ret = (((LONGLONG)a * b) - (c / 2)) / c;
163 if (ret > 2147483647 || ret < -2147483647) return -1;
164 return ret;
167 static AudioObjectPropertyScope get_scope(EDataFlow flow)
169 return (flow == eRender) ? kAudioDevicePropertyScopeOutput : kAudioDevicePropertyScopeInput;
172 static BOOL device_has_channels(AudioDeviceID device, EDataFlow flow)
174 AudioObjectPropertyAddress addr;
175 AudioBufferList *buffers;
176 BOOL ret = FALSE;
177 OSStatus sc;
178 UInt32 size;
179 int i;
181 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
182 addr.mScope = get_scope(flow);
183 addr.mElement = 0;
185 sc = AudioObjectGetPropertyDataSize(device, &addr, 0, NULL, &size);
186 if(sc != noErr){
187 WARN("Unable to get _StreamConfiguration property size for device %u: %x\n",
188 (unsigned int)device, (int)sc);
189 return FALSE;
192 buffers = malloc(size);
193 if(!buffers) return FALSE;
195 sc = AudioObjectGetPropertyData(device, &addr, 0, NULL, &size, buffers);
196 if(sc != noErr){
197 WARN("Unable to get _StreamConfiguration property for device %u: %x\n",
198 (unsigned int)device, (int)sc);
199 free(buffers);
200 return FALSE;
203 for(i = 0; i < buffers->mNumberBuffers; i++){
204 if(buffers->mBuffers[i].mNumberChannels > 0){
205 ret = TRUE;
206 break;
209 free(buffers);
210 return ret;
213 static NTSTATUS unix_process_attach(void *args)
215 #ifdef _WIN64
216 if (NtCurrentTeb()->WowTebOffset)
218 SYSTEM_BASIC_INFORMATION info;
220 NtQuerySystemInformation(SystemEmulationBasicInformation, &info, sizeof(info), NULL);
221 zero_bits = (ULONG_PTR)info.HighestUserAddress | 0x7fffffff;
223 #endif
224 return STATUS_SUCCESS;
227 static NTSTATUS unix_main_loop(void *args)
229 struct main_loop_params *params = args;
230 NtSetEvent(params->event, NULL);
231 return STATUS_SUCCESS;
234 static NTSTATUS unix_get_endpoint_ids(void *args)
236 struct get_endpoint_ids_params *params = args;
237 unsigned int num_devices, i, needed, offset;
238 AudioDeviceID *devices, default_id;
239 AudioObjectPropertyAddress addr;
240 struct endpoint *endpoint;
241 UInt32 devsize, size;
242 struct endpoint_info
244 CFStringRef name;
245 AudioDeviceID id;
246 } *info;
247 OSStatus sc;
248 UniChar *ptr;
250 params->num = 0;
251 params->default_idx = 0;
253 addr.mScope = kAudioObjectPropertyScopeGlobal;
254 addr.mElement = kAudioObjectPropertyElementMain;
255 if(params->flow == eRender) addr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
256 else if(params->flow == eCapture) addr.mSelector = kAudioHardwarePropertyDefaultInputDevice;
257 else{
258 params->result = E_INVALIDARG;
259 return STATUS_SUCCESS;
262 size = sizeof(default_id);
263 sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL, &size, &default_id);
264 if(sc != noErr){
265 WARN("Getting _DefaultInputDevice property failed: %x\n", (int)sc);
266 default_id = -1;
269 addr.mSelector = kAudioHardwarePropertyDevices;
270 sc = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, 0, NULL, &devsize);
271 if(sc != noErr){
272 WARN("Getting _Devices property size failed: %x\n", (int)sc);
273 params->result = osstatus_to_hresult(sc);
274 return STATUS_SUCCESS;
277 num_devices = devsize / sizeof(AudioDeviceID);
278 devices = malloc(devsize);
279 info = malloc(num_devices * sizeof(*info));
280 if(!devices || !info){
281 free(info);
282 free(devices);
283 params->result = E_OUTOFMEMORY;
284 return STATUS_SUCCESS;
287 sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL, &devsize, devices);
288 if(sc != noErr){
289 WARN("Getting _Devices property failed: %x\n", (int)sc);
290 free(info);
291 free(devices);
292 params->result = osstatus_to_hresult(sc);
293 return STATUS_SUCCESS;
296 addr.mSelector = kAudioObjectPropertyName;
297 addr.mScope = get_scope(params->flow);
298 addr.mElement = 0;
300 for(i = 0; i < num_devices; i++){
301 if(!device_has_channels(devices[i], params->flow)) continue;
303 size = sizeof(CFStringRef);
304 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL, &size, &info[params->num].name);
305 if(sc != noErr){
306 WARN("Unable to get _Name property for device %u: %x\n",
307 (unsigned int)devices[i], (int)sc);
308 continue;
310 info[params->num++].id = devices[i];
312 free(devices);
314 offset = needed = sizeof(*endpoint) * params->num;
315 endpoint = params->endpoints;
317 for(i = 0; i < params->num; i++){
318 const SIZE_T name_len = CFStringGetLength(info[i].name) + 1;
319 const SIZE_T device_len = MAX_DEV_NAME_LEN + 1;
320 needed += name_len * sizeof(WCHAR) + ((device_len + 1) & ~1);
322 if(needed <= params->size){
323 endpoint->name = offset;
324 ptr = (UniChar *)((char *)params->endpoints + offset);
325 CFStringGetCharacters(info[i].name, CFRangeMake(0, name_len - 1), ptr);
326 ptr[name_len - 1] = 0;
327 offset += name_len * sizeof(WCHAR);
328 endpoint->device = offset;
329 sprintf((char *)params->endpoints + offset, "%u", (unsigned int)info[i].id);
330 offset += (device_len + 1) & ~1;
331 endpoint++;
333 CFRelease(info[i].name);
334 if(info[i].id == default_id) params->default_idx = i;
336 free(info);
338 if(needed > params->size){
339 params->size = needed;
340 params->result = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
342 else params->result = S_OK;
344 return STATUS_SUCCESS;
347 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
349 WAVEFORMATEX *ret;
350 size_t size;
352 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
353 size = sizeof(WAVEFORMATEXTENSIBLE);
354 else
355 size = sizeof(WAVEFORMATEX);
357 ret = malloc(size);
358 if(!ret)
359 return NULL;
361 memcpy(ret, fmt, size);
363 ret->cbSize = size - sizeof(WAVEFORMATEX);
365 return ret;
368 static void silence_buffer(struct coreaudio_stream *stream, BYTE *buffer, UINT32 frames)
370 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)stream->fmt;
371 if((stream->fmt->wFormatTag == WAVE_FORMAT_PCM ||
372 (stream->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
373 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
374 stream->fmt->wBitsPerSample == 8)
375 memset(buffer, 128, frames * stream->fmt->nBlockAlign);
376 else
377 memset(buffer, 0, frames * stream->fmt->nBlockAlign);
380 /* CA is pulling data from us */
381 static OSStatus ca_render_cb(void *user, AudioUnitRenderActionFlags *flags,
382 const AudioTimeStamp *ts, UInt32 bus, UInt32 nframes,
383 AudioBufferList *data)
385 struct coreaudio_stream *stream = user;
386 UINT32 to_copy_bytes, to_copy_frames, chunk_bytes, lcl_offs_bytes;
388 os_unfair_lock_lock(&stream->lock);
390 if(stream->playing){
391 lcl_offs_bytes = stream->lcl_offs_frames * stream->fmt->nBlockAlign;
392 to_copy_frames = min(nframes, stream->held_frames);
393 to_copy_bytes = to_copy_frames * stream->fmt->nBlockAlign;
395 chunk_bytes = (stream->bufsize_frames - stream->lcl_offs_frames) * stream->fmt->nBlockAlign;
397 if(to_copy_bytes > chunk_bytes){
398 memcpy(data->mBuffers[0].mData, stream->local_buffer + lcl_offs_bytes, chunk_bytes);
399 memcpy(((BYTE *)data->mBuffers[0].mData) + chunk_bytes, stream->local_buffer, to_copy_bytes - chunk_bytes);
400 }else
401 memcpy(data->mBuffers[0].mData, stream->local_buffer + lcl_offs_bytes, to_copy_bytes);
403 stream->lcl_offs_frames += to_copy_frames;
404 stream->lcl_offs_frames %= stream->bufsize_frames;
405 stream->held_frames -= to_copy_frames;
406 }else
407 to_copy_bytes = to_copy_frames = 0;
409 if(nframes > to_copy_frames)
410 silence_buffer(stream, ((BYTE *)data->mBuffers[0].mData) + to_copy_bytes, nframes - to_copy_frames);
412 os_unfair_lock_unlock(&stream->lock);
414 return noErr;
417 static void ca_wrap_buffer(BYTE *dst, UINT32 dst_offs, UINT32 dst_bytes,
418 BYTE *src, UINT32 src_bytes)
420 UINT32 chunk_bytes = dst_bytes - dst_offs;
422 if(chunk_bytes < src_bytes){
423 memcpy(dst + dst_offs, src, chunk_bytes);
424 memcpy(dst, src + chunk_bytes, src_bytes - chunk_bytes);
425 }else
426 memcpy(dst + dst_offs, src, src_bytes);
429 /* we need to trigger CA to pull data from the device and give it to us
431 * raw data from CA is stored in cap_buffer, possibly via wrap_buffer
433 * raw data is resampled from cap_buffer into resamp_buffer in period-size
434 * chunks and copied to local_buffer
436 static OSStatus ca_capture_cb(void *user, AudioUnitRenderActionFlags *flags,
437 const AudioTimeStamp *ts, UInt32 bus, UInt32 nframes,
438 AudioBufferList *data)
440 struct coreaudio_stream *stream = user;
441 AudioBufferList list;
442 OSStatus sc;
443 UINT32 cap_wri_offs_frames;
445 os_unfair_lock_lock(&stream->lock);
447 cap_wri_offs_frames = (stream->cap_offs_frames + stream->cap_held_frames) % stream->cap_bufsize_frames;
449 list.mNumberBuffers = 1;
450 list.mBuffers[0].mNumberChannels = stream->fmt->nChannels;
451 list.mBuffers[0].mDataByteSize = nframes * stream->fmt->nBlockAlign;
453 if(!stream->playing || cap_wri_offs_frames + nframes > stream->cap_bufsize_frames){
454 if(stream->wrap_bufsize_frames < nframes){
455 free(stream->wrap_buffer);
456 stream->wrap_buffer = malloc(list.mBuffers[0].mDataByteSize);
457 stream->wrap_bufsize_frames = nframes;
460 list.mBuffers[0].mData = stream->wrap_buffer;
461 }else
462 list.mBuffers[0].mData = stream->cap_buffer + cap_wri_offs_frames * stream->fmt->nBlockAlign;
464 sc = AudioUnitRender(stream->unit, flags, ts, bus, nframes, &list);
465 if(sc != noErr){
466 os_unfair_lock_unlock(&stream->lock);
467 return sc;
470 if(stream->playing){
471 if(list.mBuffers[0].mData == stream->wrap_buffer){
472 ca_wrap_buffer(stream->cap_buffer,
473 cap_wri_offs_frames * stream->fmt->nBlockAlign,
474 stream->cap_bufsize_frames * stream->fmt->nBlockAlign,
475 stream->wrap_buffer, list.mBuffers[0].mDataByteSize);
478 stream->cap_held_frames += list.mBuffers[0].mDataByteSize / stream->fmt->nBlockAlign;
479 if(stream->cap_held_frames > stream->cap_bufsize_frames){
480 stream->cap_offs_frames += stream->cap_held_frames % stream->cap_bufsize_frames;
481 stream->cap_offs_frames %= stream->cap_bufsize_frames;
482 stream->cap_held_frames = stream->cap_bufsize_frames;
486 os_unfair_lock_unlock(&stream->lock);
487 return noErr;
490 static AudioComponentInstance get_audiounit(EDataFlow dataflow, AudioDeviceID adevid)
492 AudioComponentInstance unit;
493 AudioComponent comp;
494 AudioComponentDescription desc;
495 OSStatus sc;
497 memset(&desc, 0, sizeof(desc));
498 desc.componentType = kAudioUnitType_Output;
499 desc.componentSubType = kAudioUnitSubType_HALOutput;
500 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
502 if(!(comp = AudioComponentFindNext(NULL, &desc))){
503 WARN("AudioComponentFindNext failed\n");
504 return NULL;
507 sc = AudioComponentInstanceNew(comp, &unit);
508 if(sc != noErr){
509 WARN("AudioComponentInstanceNew failed: %x\n", (int)sc);
510 return NULL;
513 if(dataflow == eCapture){
514 UInt32 enableio;
516 enableio = 1;
517 sc = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_EnableIO,
518 kAudioUnitScope_Input, 1, &enableio, sizeof(enableio));
519 if(sc != noErr){
520 WARN("Couldn't enable I/O on input element: %x\n", (int)sc);
521 AudioComponentInstanceDispose(unit);
522 return NULL;
525 enableio = 0;
526 sc = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_EnableIO,
527 kAudioUnitScope_Output, 0, &enableio, sizeof(enableio));
528 if(sc != noErr){
529 WARN("Couldn't disable I/O on output element: %x\n", (int)sc);
530 AudioComponentInstanceDispose(unit);
531 return NULL;
535 sc = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_CurrentDevice,
536 kAudioUnitScope_Global, 0, &adevid, sizeof(adevid));
537 if(sc != noErr){
538 WARN("Couldn't set audio unit device\n");
539 AudioComponentInstanceDispose(unit);
540 return NULL;
543 return unit;
546 static void dump_adesc(const char *aux, AudioStreamBasicDescription *desc)
548 TRACE("%s: mSampleRate: %f\n", aux, desc->mSampleRate);
549 TRACE("%s: mBytesPerPacket: %u\n", aux, (unsigned int)desc->mBytesPerPacket);
550 TRACE("%s: mFramesPerPacket: %u\n", aux, (unsigned int)desc->mFramesPerPacket);
551 TRACE("%s: mBytesPerFrame: %u\n", aux, (unsigned int)desc->mBytesPerFrame);
552 TRACE("%s: mChannelsPerFrame: %u\n", aux, (unsigned int)desc->mChannelsPerFrame);
553 TRACE("%s: mBitsPerChannel: %u\n", aux, (unsigned int)desc->mBitsPerChannel);
556 static HRESULT ca_get_audiodesc(AudioStreamBasicDescription *desc,
557 const WAVEFORMATEX *fmt)
559 const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
561 desc->mFormatFlags = 0;
563 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
564 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
565 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
566 desc->mFormatID = kAudioFormatLinearPCM;
567 if(fmt->wBitsPerSample > 8)
568 desc->mFormatFlags = kAudioFormatFlagIsSignedInteger;
569 }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
570 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
571 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
572 desc->mFormatID = kAudioFormatLinearPCM;
573 desc->mFormatFlags = kAudioFormatFlagIsFloat;
574 }else if(fmt->wFormatTag == WAVE_FORMAT_MULAW ||
575 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
576 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_MULAW))){
577 desc->mFormatID = kAudioFormatULaw;
578 }else if(fmt->wFormatTag == WAVE_FORMAT_ALAW ||
579 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
580 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_ALAW))){
581 desc->mFormatID = kAudioFormatALaw;
582 }else
583 return AUDCLNT_E_UNSUPPORTED_FORMAT;
585 desc->mSampleRate = fmt->nSamplesPerSec;
586 desc->mBytesPerPacket = fmt->nBlockAlign;
587 desc->mFramesPerPacket = 1;
588 desc->mBytesPerFrame = fmt->nBlockAlign;
589 desc->mChannelsPerFrame = fmt->nChannels;
590 desc->mBitsPerChannel = fmt->wBitsPerSample;
591 desc->mReserved = 0;
593 return S_OK;
596 static HRESULT ca_setup_audiounit(EDataFlow dataflow, AudioComponentInstance unit,
597 const WAVEFORMATEX *fmt, AudioStreamBasicDescription *dev_desc,
598 AudioConverterRef *converter)
600 OSStatus sc;
601 HRESULT hr;
603 if(dataflow == eCapture){
604 AudioStreamBasicDescription desc;
605 UInt32 size;
606 Float64 rate;
607 fenv_t fenv;
608 BOOL fenv_stored = TRUE;
610 hr = ca_get_audiodesc(&desc, fmt);
611 if(FAILED(hr))
612 return hr;
613 dump_adesc("requested", &desc);
615 /* input-only units can't perform sample rate conversion, so we have to
616 * set up our own AudioConverter to support arbitrary sample rates. */
617 size = sizeof(*dev_desc);
618 sc = AudioUnitGetProperty(unit, kAudioUnitProperty_StreamFormat,
619 kAudioUnitScope_Input, 1, dev_desc, &size);
620 if(sc != noErr){
621 WARN("Couldn't get unit format: %x\n", (int)sc);
622 return osstatus_to_hresult(sc);
624 dump_adesc("hardware", dev_desc);
626 rate = dev_desc->mSampleRate;
627 *dev_desc = desc;
628 dev_desc->mSampleRate = rate;
630 dump_adesc("final", dev_desc);
631 sc = AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat,
632 kAudioUnitScope_Output, 1, dev_desc, sizeof(*dev_desc));
633 if(sc != noErr){
634 WARN("Couldn't set unit format: %x\n", (int)sc);
635 return osstatus_to_hresult(sc);
638 /* AudioConverterNew requires divide-by-zero SSE exceptions to be masked */
639 if(feholdexcept(&fenv)){
640 WARN("Failed to store fenv state\n");
641 fenv_stored = FALSE;
644 sc = AudioConverterNew(dev_desc, &desc, converter);
646 if(fenv_stored && fesetenv(&fenv))
647 WARN("Failed to restore fenv state\n");
649 if(sc != noErr){
650 WARN("Couldn't create audio converter: %x\n", (int)sc);
651 return osstatus_to_hresult(sc);
653 }else{
654 hr = ca_get_audiodesc(dev_desc, fmt);
655 if(FAILED(hr))
656 return hr;
658 dump_adesc("final", dev_desc);
659 sc = AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat,
660 kAudioUnitScope_Input, 0, dev_desc, sizeof(*dev_desc));
661 if(sc != noErr){
662 WARN("Couldn't set format: %x\n", (int)sc);
663 return osstatus_to_hresult(sc);
667 return S_OK;
670 static AudioDeviceID dev_id_from_device(const char *device)
672 return strtoul(device, NULL, 10);
675 static NTSTATUS unix_create_stream(void *args)
677 struct create_stream_params *params = args;
678 struct coreaudio_stream *stream;
679 AURenderCallbackStruct input;
680 OSStatus sc;
681 SIZE_T size;
683 params->result = S_OK;
685 if (params->share == AUDCLNT_SHAREMODE_SHARED) {
686 params->period = def_period;
687 if (params->duration < 3 * params->period)
688 params->duration = 3 * params->period;
689 } else {
690 const WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE *)params->fmt;
691 if (fmtex->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
692 (fmtex->dwChannelMask == 0 || fmtex->dwChannelMask & SPEAKER_RESERVED))
693 params->result = AUDCLNT_E_UNSUPPORTED_FORMAT;
694 else {
695 if (!params->period)
696 params->period = def_period;
697 if (params->period < min_period || params->period > 5000000)
698 params->result = AUDCLNT_E_INVALID_DEVICE_PERIOD;
699 else if (params->duration > 20000000) /* The smaller the period, the lower this limit. */
700 params->result = AUDCLNT_E_BUFFER_SIZE_ERROR;
701 else if (params->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) {
702 if (params->duration != params->period)
703 params->result = AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
705 FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
707 params->result = AUDCLNT_E_DEVICE_IN_USE;
708 } else if (params->duration < 8 * params->period)
709 params->duration = 8 * params->period; /* May grow above 2s. */
713 if (FAILED(params->result))
714 return STATUS_SUCCESS;
716 if (!(stream = calloc(1, sizeof(*stream)))) {
717 params->result = E_OUTOFMEMORY;
718 return STATUS_SUCCESS;
721 stream->fmt = clone_format(params->fmt);
722 if(!stream->fmt){
723 params->result = E_OUTOFMEMORY;
724 goto end;
727 stream->period = params->period;
728 stream->period_frames = muldiv(params->period, stream->fmt->nSamplesPerSec, 10000000);
729 stream->dev_id = dev_id_from_device(params->device);
730 stream->flow = params->flow;
731 stream->flags = params->flags;
732 stream->share = params->share;
734 stream->bufsize_frames = muldiv(params->duration, stream->fmt->nSamplesPerSec, 10000000);
735 if(params->share == AUDCLNT_SHAREMODE_EXCLUSIVE)
736 stream->bufsize_frames -= stream->bufsize_frames % stream->period_frames;
738 if(!(stream->unit = get_audiounit(stream->flow, stream->dev_id))){
739 params->result = AUDCLNT_E_DEVICE_INVALIDATED;
740 goto end;
743 params->result = ca_setup_audiounit(stream->flow, stream->unit, stream->fmt, &stream->dev_desc, &stream->converter);
744 if(FAILED(params->result)) goto end;
746 input.inputProcRefCon = stream;
747 if(stream->flow == eCapture){
748 input.inputProc = ca_capture_cb;
749 sc = AudioUnitSetProperty(stream->unit, kAudioOutputUnitProperty_SetInputCallback,
750 kAudioUnitScope_Output, 1, &input, sizeof(input));
751 }else{
752 input.inputProc = ca_render_cb;
753 sc = AudioUnitSetProperty(stream->unit, kAudioUnitProperty_SetRenderCallback,
754 kAudioUnitScope_Input, 0, &input, sizeof(input));
756 if(sc != noErr){
757 WARN("Couldn't set callback: %x\n", (int)sc);
758 params->result = osstatus_to_hresult(sc);
759 goto end;
762 sc = AudioUnitInitialize(stream->unit);
763 if(sc != noErr){
764 WARN("Couldn't initialize: %x\n", (int)sc);
765 params->result = osstatus_to_hresult(sc);
766 goto end;
769 /* we play audio continuously because AudioOutputUnitStart sometimes takes
770 * a while to return */
771 sc = AudioOutputUnitStart(stream->unit);
772 if(sc != noErr){
773 WARN("Unit failed to start: %x\n", (int)sc);
774 params->result = osstatus_to_hresult(sc);
775 goto end;
778 size = stream->bufsize_frames * stream->fmt->nBlockAlign;
779 if(NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, zero_bits,
780 &size, MEM_COMMIT, PAGE_READWRITE)){
781 params->result = E_OUTOFMEMORY;
782 goto end;
784 silence_buffer(stream, stream->local_buffer, stream->bufsize_frames);
786 if(stream->flow == eCapture){
787 stream->cap_bufsize_frames = muldiv(params->duration, stream->dev_desc.mSampleRate, 10000000);
788 stream->cap_buffer = malloc(stream->cap_bufsize_frames * stream->fmt->nBlockAlign);
790 params->result = S_OK;
792 end:
793 if(FAILED(params->result)){
794 if(stream->converter) AudioConverterDispose(stream->converter);
795 if(stream->unit) AudioComponentInstanceDispose(stream->unit);
796 free(stream->fmt);
797 free(stream);
798 } else {
799 *params->channel_count = params->fmt->nChannels;
800 *params->stream = (stream_handle)(UINT_PTR)stream;
803 return STATUS_SUCCESS;
806 static NTSTATUS unix_release_stream( void *args )
808 struct release_stream_params *params = args;
809 struct coreaudio_stream *stream = handle_get_stream(params->stream);
810 SIZE_T size;
812 if(params->timer_thread){
813 stream->please_quit = TRUE;
814 NtWaitForSingleObject(params->timer_thread, FALSE, NULL);
815 NtClose(params->timer_thread);
818 if(stream->unit){
819 AudioOutputUnitStop(stream->unit);
820 AudioComponentInstanceDispose(stream->unit);
823 if(stream->converter) AudioConverterDispose(stream->converter);
824 free(stream->resamp_buffer);
825 free(stream->wrap_buffer);
826 free(stream->cap_buffer);
827 if(stream->local_buffer){
828 size = 0;
829 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer,
830 &size, MEM_RELEASE);
832 if(stream->tmp_buffer){
833 size = 0;
834 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer,
835 &size, MEM_RELEASE);
837 free(stream->fmt);
838 free(stream);
839 params->result = S_OK;
840 return STATUS_SUCCESS;
843 static UINT ca_channel_layout_to_channel_mask(const AudioChannelLayout *layout)
845 int i;
846 UINT mask = 0;
848 for (i = 0; i < layout->mNumberChannelDescriptions; ++i) {
849 switch (layout->mChannelDescriptions[i].mChannelLabel) {
850 default: FIXME("Unhandled channel 0x%x\n",
851 (unsigned int)layout->mChannelDescriptions[i].mChannelLabel); break;
852 case kAudioChannelLabel_Left: mask |= SPEAKER_FRONT_LEFT; break;
853 case kAudioChannelLabel_Mono:
854 case kAudioChannelLabel_Center: mask |= SPEAKER_FRONT_CENTER; break;
855 case kAudioChannelLabel_Right: mask |= SPEAKER_FRONT_RIGHT; break;
856 case kAudioChannelLabel_LeftSurround: mask |= SPEAKER_BACK_LEFT; break;
857 case kAudioChannelLabel_CenterSurround: mask |= SPEAKER_BACK_CENTER; break;
858 case kAudioChannelLabel_RightSurround: mask |= SPEAKER_BACK_RIGHT; break;
859 case kAudioChannelLabel_LFEScreen: mask |= SPEAKER_LOW_FREQUENCY; break;
860 case kAudioChannelLabel_LeftSurroundDirect: mask |= SPEAKER_SIDE_LEFT; break;
861 case kAudioChannelLabel_RightSurroundDirect: mask |= SPEAKER_SIDE_RIGHT; break;
862 case kAudioChannelLabel_TopCenterSurround: mask |= SPEAKER_TOP_CENTER; break;
863 case kAudioChannelLabel_VerticalHeightLeft: mask |= SPEAKER_TOP_FRONT_LEFT; break;
864 case kAudioChannelLabel_VerticalHeightCenter: mask |= SPEAKER_TOP_FRONT_CENTER; break;
865 case kAudioChannelLabel_VerticalHeightRight: mask |= SPEAKER_TOP_FRONT_RIGHT; break;
866 case kAudioChannelLabel_TopBackLeft: mask |= SPEAKER_TOP_BACK_LEFT; break;
867 case kAudioChannelLabel_TopBackCenter: mask |= SPEAKER_TOP_BACK_CENTER; break;
868 case kAudioChannelLabel_TopBackRight: mask |= SPEAKER_TOP_BACK_RIGHT; break;
869 case kAudioChannelLabel_LeftCenter: mask |= SPEAKER_FRONT_LEFT_OF_CENTER; break;
870 case kAudioChannelLabel_RightCenter: mask |= SPEAKER_FRONT_RIGHT_OF_CENTER; break;
874 return mask;
877 /* For most hardware on Windows, users must choose a configuration with an even
878 * number of channels (stereo, quad, 5.1, 7.1). Users can then disable
879 * channels, but those channels are still reported to applications from
880 * GetMixFormat! Some applications behave badly if given an odd number of
881 * channels (e.g. 2.1). Here, we find the nearest configuration that Windows
882 * would report for a given channel layout. */
883 static void convert_channel_layout(const AudioChannelLayout *ca_layout, WAVEFORMATEXTENSIBLE *fmt)
885 UINT ca_mask = ca_channel_layout_to_channel_mask(ca_layout);
887 TRACE("Got channel mask for CA: 0x%x\n", ca_mask);
889 if (ca_layout->mNumberChannelDescriptions == 1)
891 fmt->Format.nChannels = 1;
892 fmt->dwChannelMask = ca_mask;
893 return;
896 /* compare against known configurations and find smallest configuration
897 * which is a superset of the given speakers */
899 if (ca_layout->mNumberChannelDescriptions <= 2 &&
900 (ca_mask & ~KSAUDIO_SPEAKER_STEREO) == 0)
902 fmt->Format.nChannels = 2;
903 fmt->dwChannelMask = KSAUDIO_SPEAKER_STEREO;
904 return;
907 if (ca_layout->mNumberChannelDescriptions <= 4 &&
908 (ca_mask & ~KSAUDIO_SPEAKER_QUAD) == 0)
910 fmt->Format.nChannels = 4;
911 fmt->dwChannelMask = KSAUDIO_SPEAKER_QUAD;
912 return;
915 if (ca_layout->mNumberChannelDescriptions <= 4 &&
916 (ca_mask & ~KSAUDIO_SPEAKER_SURROUND) == 0)
918 fmt->Format.nChannels = 4;
919 fmt->dwChannelMask = KSAUDIO_SPEAKER_SURROUND;
920 return;
923 if (ca_layout->mNumberChannelDescriptions <= 6 &&
924 (ca_mask & ~KSAUDIO_SPEAKER_5POINT1) == 0)
926 fmt->Format.nChannels = 6;
927 fmt->dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
928 return;
931 if (ca_layout->mNumberChannelDescriptions <= 6 &&
932 (ca_mask & ~KSAUDIO_SPEAKER_5POINT1_SURROUND) == 0)
934 fmt->Format.nChannels = 6;
935 fmt->dwChannelMask = KSAUDIO_SPEAKER_5POINT1_SURROUND;
936 return;
939 if (ca_layout->mNumberChannelDescriptions <= 8 &&
940 (ca_mask & ~KSAUDIO_SPEAKER_7POINT1) == 0)
942 fmt->Format.nChannels = 8;
943 fmt->dwChannelMask = KSAUDIO_SPEAKER_7POINT1;
944 return;
947 if (ca_layout->mNumberChannelDescriptions <= 8 &&
948 (ca_mask & ~KSAUDIO_SPEAKER_7POINT1_SURROUND) == 0)
950 fmt->Format.nChannels = 8;
951 fmt->dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
952 return;
955 /* oddball format, report truthfully */
956 fmt->Format.nChannels = ca_layout->mNumberChannelDescriptions;
957 fmt->dwChannelMask = ca_mask;
960 static DWORD get_channel_mask(unsigned int channels)
962 switch(channels){
963 case 0:
964 return 0;
965 case 1:
966 return KSAUDIO_SPEAKER_MONO;
967 case 2:
968 return KSAUDIO_SPEAKER_STEREO;
969 case 3:
970 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
971 case 4:
972 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
973 case 5:
974 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
975 case 6:
976 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
977 case 7:
978 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
979 case 8:
980 return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
982 FIXME("Unknown speaker configuration: %u\n", channels);
983 return 0;
986 static NTSTATUS unix_get_mix_format(void *args)
988 struct get_mix_format_params *params = args;
989 AudioObjectPropertyAddress addr;
990 AudioChannelLayout *layout;
991 AudioBufferList *buffers;
992 Float64 rate;
993 UInt32 size;
994 OSStatus sc;
995 int i;
996 const AudioDeviceID dev_id = dev_id_from_device(params->device);
998 params->fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1000 addr.mScope = get_scope(params->flow);
1001 addr.mElement = 0;
1002 addr.mSelector = kAudioDevicePropertyPreferredChannelLayout;
1004 sc = AudioObjectGetPropertyDataSize(dev_id, &addr, 0, NULL, &size);
1005 if(sc == noErr){
1006 layout = malloc(size);
1007 sc = AudioObjectGetPropertyData(dev_id, &addr, 0, NULL, &size, layout);
1008 if(sc == noErr){
1009 TRACE("Got channel layout: {tag: 0x%x, bitmap: 0x%x, num_descs: %u}\n",
1010 (unsigned int)layout->mChannelLayoutTag, (unsigned int)layout->mChannelBitmap,
1011 (unsigned int)layout->mNumberChannelDescriptions);
1013 if(layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions){
1014 convert_channel_layout(layout, params->fmt);
1015 }else{
1016 WARN("Haven't implemented support for this layout tag: 0x%x, guessing at layout\n",
1017 (unsigned int)layout->mChannelLayoutTag);
1018 params->fmt->Format.nChannels = 0;
1020 }else{
1021 TRACE("Unable to get _PreferredChannelLayout property: %x, guessing at layout\n", (int)sc);
1022 params->fmt->Format.nChannels = 0;
1025 free(layout);
1026 }else{
1027 TRACE("Unable to get size for _PreferredChannelLayout property: %x, guessing at layout\n", (int)sc);
1028 params->fmt->Format.nChannels = 0;
1031 if(params->fmt->Format.nChannels == 0){
1032 addr.mScope = get_scope(params->flow);
1033 addr.mElement = 0;
1034 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
1036 sc = AudioObjectGetPropertyDataSize(dev_id, &addr, 0, NULL, &size);
1037 if(sc != noErr){
1038 WARN("Unable to get size for _StreamConfiguration property: %x\n", (int)sc);
1039 params->result = osstatus_to_hresult(sc);
1040 return STATUS_SUCCESS;
1043 buffers = malloc(size);
1044 if(!buffers){
1045 params->result = E_OUTOFMEMORY;
1046 return STATUS_SUCCESS;
1049 sc = AudioObjectGetPropertyData(dev_id, &addr, 0, NULL, &size, buffers);
1050 if(sc != noErr){
1051 free(buffers);
1052 WARN("Unable to get _StreamConfiguration property: %x\n", (int)sc);
1053 params->result = osstatus_to_hresult(sc);
1054 return STATUS_SUCCESS;
1057 for(i = 0; i < buffers->mNumberBuffers; ++i)
1058 params->fmt->Format.nChannels += buffers->mBuffers[i].mNumberChannels;
1060 free(buffers);
1062 params->fmt->dwChannelMask = get_channel_mask(params->fmt->Format.nChannels);
1065 addr.mSelector = kAudioDevicePropertyNominalSampleRate;
1066 size = sizeof(Float64);
1067 sc = AudioObjectGetPropertyData(dev_id, &addr, 0, NULL, &size, &rate);
1068 if(sc != noErr){
1069 WARN("Unable to get _NominalSampleRate property: %x\n", (int)sc);
1070 params->result = osstatus_to_hresult(sc);
1071 return STATUS_SUCCESS;
1073 params->fmt->Format.nSamplesPerSec = rate;
1075 params->fmt->Format.wBitsPerSample = 32;
1076 params->fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1078 params->fmt->Format.nBlockAlign = (params->fmt->Format.wBitsPerSample *
1079 params->fmt->Format.nChannels) / 8;
1080 params->fmt->Format.nAvgBytesPerSec = params->fmt->Format.nSamplesPerSec *
1081 params->fmt->Format.nBlockAlign;
1083 params->fmt->Samples.wValidBitsPerSample = params->fmt->Format.wBitsPerSample;
1084 params->fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1085 params->result = S_OK;
1086 return STATUS_SUCCESS;
1089 static NTSTATUS unix_is_format_supported(void *args)
1091 struct is_format_supported_params *params = args;
1092 const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)params->fmt_in;
1093 AudioStreamBasicDescription dev_desc;
1094 AudioConverterRef converter;
1095 AudioComponentInstance unit;
1096 const AudioDeviceID dev_id = dev_id_from_device(params->device);
1098 params->result = S_OK;
1100 if(!params->fmt_in || (params->share == AUDCLNT_SHAREMODE_SHARED && !params->fmt_out))
1101 params->result = E_POINTER;
1102 else if(params->share != AUDCLNT_SHAREMODE_SHARED && params->share != AUDCLNT_SHAREMODE_EXCLUSIVE)
1103 params->result = E_INVALIDARG;
1104 else if(params->fmt_in->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
1105 if(params->fmt_in->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1106 params->result = E_INVALIDARG;
1107 else if(params->fmt_in->nAvgBytesPerSec == 0 || params->fmt_in->nBlockAlign == 0 ||
1108 fmtex->Samples.wValidBitsPerSample > params->fmt_in->wBitsPerSample)
1109 params->result = E_INVALIDARG;
1110 else if(fmtex->Samples.wValidBitsPerSample < params->fmt_in->wBitsPerSample)
1111 goto unsupported;
1112 else if(params->share == AUDCLNT_SHAREMODE_EXCLUSIVE &&
1113 (fmtex->dwChannelMask == 0 || fmtex->dwChannelMask & SPEAKER_RESERVED))
1114 goto unsupported;
1116 if(FAILED(params->result)) return STATUS_SUCCESS;
1118 if(params->fmt_in->nBlockAlign != params->fmt_in->nChannels * params->fmt_in->wBitsPerSample / 8 ||
1119 params->fmt_in->nAvgBytesPerSec != params->fmt_in->nBlockAlign * params->fmt_in->nSamplesPerSec)
1120 goto unsupported;
1122 if(params->fmt_in->nChannels == 0){
1123 params->result = AUDCLNT_E_UNSUPPORTED_FORMAT;
1124 return STATUS_SUCCESS;
1126 unit = get_audiounit(params->flow, dev_id);
1128 converter = NULL;
1129 params->result = ca_setup_audiounit(params->flow, unit, params->fmt_in, &dev_desc, &converter);
1130 AudioComponentInstanceDispose(unit);
1131 if(FAILED(params->result)) goto unsupported;
1132 if(converter) AudioConverterDispose(converter);
1134 params->result = S_OK;
1135 return STATUS_SUCCESS;
1137 unsupported:
1138 if(params->fmt_out){
1139 struct get_mix_format_params get_mix_params =
1141 .device = params->device,
1142 .flow = params->flow,
1143 .fmt = params->fmt_out,
1146 unix_get_mix_format(&get_mix_params);
1147 params->result = get_mix_params.result;
1148 if(SUCCEEDED(params->result)) params->result = S_FALSE;
1150 else params->result = AUDCLNT_E_UNSUPPORTED_FORMAT;
1151 return STATUS_SUCCESS;
1154 static NTSTATUS unix_get_device_period(void *args)
1156 struct get_device_period_params *params = args;
1158 if (params->def_period)
1159 *params->def_period = def_period;
1160 if (params->min_period)
1161 *params->min_period = min_period;
1163 params->result = S_OK;
1165 return STATUS_SUCCESS;
1168 static UINT buf_ptr_diff(UINT left, UINT right, UINT bufsize)
1170 if(left <= right)
1171 return right - left;
1172 return bufsize - (left - right);
1175 /* place data from cap_buffer into provided AudioBufferList */
1176 static OSStatus feed_cb(AudioConverterRef converter, UInt32 *nframes, AudioBufferList *data,
1177 AudioStreamPacketDescription **packets, void *user)
1179 struct coreaudio_stream *stream = user;
1181 *nframes = min(*nframes, stream->cap_held_frames);
1182 if(!*nframes){
1183 data->mBuffers[0].mData = NULL;
1184 data->mBuffers[0].mDataByteSize = 0;
1185 data->mBuffers[0].mNumberChannels = stream->fmt->nChannels;
1186 return noErr;
1189 data->mBuffers[0].mDataByteSize = *nframes * stream->fmt->nBlockAlign;
1190 data->mBuffers[0].mNumberChannels = stream->fmt->nChannels;
1192 if(stream->cap_offs_frames + *nframes > stream->cap_bufsize_frames){
1193 UINT32 chunk_frames = stream->cap_bufsize_frames - stream->cap_offs_frames;
1195 if(stream->wrap_bufsize_frames < *nframes){
1196 free(stream->wrap_buffer);
1197 stream->wrap_buffer = malloc(data->mBuffers[0].mDataByteSize);
1198 stream->wrap_bufsize_frames = *nframes;
1201 memcpy(stream->wrap_buffer, stream->cap_buffer + stream->cap_offs_frames * stream->fmt->nBlockAlign,
1202 chunk_frames * stream->fmt->nBlockAlign);
1203 memcpy(stream->wrap_buffer + chunk_frames * stream->fmt->nBlockAlign, stream->cap_buffer,
1204 (*nframes - chunk_frames) * stream->fmt->nBlockAlign);
1206 data->mBuffers[0].mData = stream->wrap_buffer;
1207 }else
1208 data->mBuffers[0].mData = stream->cap_buffer + stream->cap_offs_frames * stream->fmt->nBlockAlign;
1210 stream->cap_offs_frames += *nframes;
1211 stream->cap_offs_frames %= stream->cap_bufsize_frames;
1212 stream->cap_held_frames -= *nframes;
1214 if(packets)
1215 *packets = NULL;
1217 return noErr;
1220 static void capture_resample(struct coreaudio_stream *stream)
1222 UINT32 resamp_period_frames = muldiv(stream->period_frames, stream->dev_desc.mSampleRate,
1223 stream->fmt->nSamplesPerSec);
1224 OSStatus sc;
1226 /* the resampling process often needs more source frames than we'd
1227 * guess from a straight conversion using the sample rate ratio. so
1228 * only convert if we have extra source data. */
1229 while(stream->cap_held_frames > resamp_period_frames * 2){
1230 AudioBufferList converted_list;
1231 UInt32 wanted_frames = stream->period_frames;
1233 converted_list.mNumberBuffers = 1;
1234 converted_list.mBuffers[0].mNumberChannels = stream->fmt->nChannels;
1235 converted_list.mBuffers[0].mDataByteSize = wanted_frames * stream->fmt->nBlockAlign;
1237 if(stream->resamp_bufsize_frames < wanted_frames){
1238 free(stream->resamp_buffer);
1239 stream->resamp_buffer = malloc(converted_list.mBuffers[0].mDataByteSize);
1240 stream->resamp_bufsize_frames = wanted_frames;
1243 converted_list.mBuffers[0].mData = stream->resamp_buffer;
1245 sc = AudioConverterFillComplexBuffer(stream->converter, feed_cb,
1246 stream, &wanted_frames, &converted_list, NULL);
1247 if(sc != noErr){
1248 WARN("AudioConverterFillComplexBuffer failed: %x\n", (int)sc);
1249 break;
1252 ca_wrap_buffer(stream->local_buffer,
1253 stream->wri_offs_frames * stream->fmt->nBlockAlign,
1254 stream->bufsize_frames * stream->fmt->nBlockAlign,
1255 stream->resamp_buffer, wanted_frames * stream->fmt->nBlockAlign);
1257 stream->wri_offs_frames += wanted_frames;
1258 stream->wri_offs_frames %= stream->bufsize_frames;
1259 if(stream->held_frames + wanted_frames > stream->bufsize_frames){
1260 stream->lcl_offs_frames += buf_ptr_diff(stream->lcl_offs_frames, stream->wri_offs_frames,
1261 stream->bufsize_frames);
1262 stream->held_frames = stream->bufsize_frames;
1263 }else
1264 stream->held_frames += wanted_frames;
1268 static NTSTATUS unix_get_buffer_size(void *args)
1270 struct get_buffer_size_params *params = args;
1271 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1273 os_unfair_lock_lock(&stream->lock);
1274 *params->frames = stream->bufsize_frames;
1275 os_unfair_lock_unlock(&stream->lock);
1276 params->result = S_OK;
1277 return STATUS_SUCCESS;
1280 static HRESULT ca_get_max_stream_latency(struct coreaudio_stream *stream, UInt32 *max)
1282 AudioObjectPropertyAddress addr;
1283 AudioStreamID *ids;
1284 UInt32 size;
1285 OSStatus sc;
1286 int nstreams, i;
1288 addr.mScope = get_scope(stream->flow);
1289 addr.mElement = 0;
1290 addr.mSelector = kAudioDevicePropertyStreams;
1292 sc = AudioObjectGetPropertyDataSize(stream->dev_id, &addr, 0, NULL, &size);
1293 if(sc != noErr){
1294 WARN("Unable to get size for _Streams property: %x\n", (int)sc);
1295 return osstatus_to_hresult(sc);
1298 ids = malloc(size);
1299 if(!ids)
1300 return E_OUTOFMEMORY;
1302 sc = AudioObjectGetPropertyData(stream->dev_id, &addr, 0, NULL, &size, ids);
1303 if(sc != noErr){
1304 WARN("Unable to get _Streams property: %x\n", (int)sc);
1305 free(ids);
1306 return osstatus_to_hresult(sc);
1309 nstreams = size / sizeof(AudioStreamID);
1310 *max = 0;
1312 addr.mSelector = kAudioStreamPropertyLatency;
1313 for(i = 0; i < nstreams; ++i){
1314 UInt32 latency;
1316 size = sizeof(latency);
1317 sc = AudioObjectGetPropertyData(ids[i], &addr, 0, NULL, &size, &latency);
1318 if(sc != noErr){
1319 WARN("Unable to get _Latency property: %x\n", (int)sc);
1320 continue;
1323 if(latency > *max)
1324 *max = latency;
1327 free(ids);
1329 return S_OK;
1332 static NTSTATUS unix_get_latency(void *args)
1334 struct get_latency_params *params = args;
1335 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1336 UInt32 latency, stream_latency, size;
1337 AudioObjectPropertyAddress addr;
1338 OSStatus sc;
1340 os_unfair_lock_lock(&stream->lock);
1342 addr.mScope = get_scope(stream->flow);
1343 addr.mSelector = kAudioDevicePropertyLatency;
1344 addr.mElement = 0;
1346 size = sizeof(latency);
1347 sc = AudioObjectGetPropertyData(stream->dev_id, &addr, 0, NULL, &size, &latency);
1348 if(sc != noErr){
1349 WARN("Couldn't get _Latency property: %x\n", (int)sc);
1350 os_unfair_lock_unlock(&stream->lock);
1351 params->result = osstatus_to_hresult(sc);
1352 return STATUS_SUCCESS;
1355 params->result = ca_get_max_stream_latency(stream, &stream_latency);
1356 if(FAILED(params->result)){
1357 os_unfair_lock_unlock(&stream->lock);
1358 return STATUS_SUCCESS;
1361 latency += stream_latency;
1362 /* pretend we process audio in Period chunks, so max latency includes
1363 * the period time */
1364 *params->latency = muldiv(latency, 10000000, stream->fmt->nSamplesPerSec) + stream->period;
1366 os_unfair_lock_unlock(&stream->lock);
1367 params->result = S_OK;
1368 return STATUS_SUCCESS;
1371 static UINT32 get_current_padding_nolock(struct coreaudio_stream *stream)
1373 if(stream->flow == eCapture) capture_resample(stream);
1374 return stream->held_frames;
1377 static NTSTATUS unix_get_current_padding(void *args)
1379 struct get_current_padding_params *params = args;
1380 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1382 os_unfair_lock_lock(&stream->lock);
1383 *params->padding = get_current_padding_nolock(stream);
1384 os_unfair_lock_unlock(&stream->lock);
1385 params->result = S_OK;
1386 return STATUS_SUCCESS;
1389 static NTSTATUS unix_start(void *args)
1391 struct start_params *params = args;
1392 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1394 os_unfair_lock_lock(&stream->lock);
1396 if((stream->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !stream->event)
1397 params->result = AUDCLNT_E_EVENTHANDLE_NOT_SET;
1398 else if(stream->playing)
1399 params->result = AUDCLNT_E_NOT_STOPPED;
1400 else{
1401 stream->playing = TRUE;
1402 params->result = S_OK;
1405 os_unfair_lock_unlock(&stream->lock);
1407 return STATUS_SUCCESS;
1410 static NTSTATUS unix_stop(void *args)
1412 struct stop_params *params = args;
1413 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1415 os_unfair_lock_lock(&stream->lock);
1417 if(!stream->playing)
1418 params->result = S_FALSE;
1419 else{
1420 stream->playing = FALSE;
1421 params->result = S_OK;
1424 os_unfair_lock_unlock(&stream->lock);
1426 return STATUS_SUCCESS;
1429 static NTSTATUS unix_reset(void *args)
1431 struct reset_params *params = args;
1432 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1434 os_unfair_lock_lock(&stream->lock);
1436 if(stream->playing)
1437 params->result = AUDCLNT_E_NOT_STOPPED;
1438 else if(stream->getbuf_last)
1439 params->result = AUDCLNT_E_BUFFER_OPERATION_PENDING;
1440 else{
1441 if(stream->flow == eRender)
1442 stream->written_frames = 0;
1443 else
1444 stream->written_frames += stream->held_frames;
1445 stream->held_frames = 0;
1446 stream->lcl_offs_frames = 0;
1447 stream->wri_offs_frames = 0;
1448 stream->cap_offs_frames = 0;
1449 stream->cap_held_frames = 0;
1450 params->result = S_OK;
1453 os_unfair_lock_unlock(&stream->lock);
1454 return STATUS_SUCCESS;
1457 static NTSTATUS unix_timer_loop(void *args)
1459 struct timer_loop_params *params = args;
1460 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1461 LARGE_INTEGER delay, next, last;
1462 int adjust;
1464 delay.QuadPart = -stream->period;
1465 NtQueryPerformanceCounter(&last, NULL);
1466 next.QuadPart = last.QuadPart + stream->period;
1468 while(!stream->please_quit){
1469 NtSetEvent(stream->event, NULL);
1470 NtDelayExecution(FALSE, &delay);
1471 NtQueryPerformanceCounter(&last, NULL);
1473 adjust = next.QuadPart - last.QuadPart;
1474 if(adjust > stream->period / 2)
1475 adjust = stream->period / 2;
1476 else if(adjust < -stream->period / 2)
1477 adjust = -stream->period / 2;
1479 delay.QuadPart = -(stream->period + adjust);
1480 next.QuadPart += stream->period;
1483 return STATUS_SUCCESS;
1486 static NTSTATUS unix_get_render_buffer(void *args)
1488 struct get_render_buffer_params *params = args;
1489 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1490 SIZE_T size;
1491 UINT32 pad;
1493 os_unfair_lock_lock(&stream->lock);
1495 pad = get_current_padding_nolock(stream);
1497 if(stream->getbuf_last){
1498 params->result = AUDCLNT_E_OUT_OF_ORDER;
1499 goto end;
1501 if(!params->frames){
1502 params->result = S_OK;
1503 goto end;
1505 if(pad + params->frames > stream->bufsize_frames){
1506 params->result = AUDCLNT_E_BUFFER_TOO_LARGE;
1507 goto end;
1510 if(stream->wri_offs_frames + params->frames > stream->bufsize_frames){
1511 if(stream->tmp_buffer_frames < params->frames){
1512 if(stream->tmp_buffer){
1513 size = 0;
1514 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer,
1515 &size, MEM_RELEASE);
1516 stream->tmp_buffer = NULL;
1518 size = params->frames * stream->fmt->nBlockAlign;
1519 if(NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, zero_bits,
1520 &size, MEM_COMMIT, PAGE_READWRITE)){
1521 stream->tmp_buffer_frames = 0;
1522 params->result = E_OUTOFMEMORY;
1523 goto end;
1525 stream->tmp_buffer_frames = params->frames;
1527 *params->data = stream->tmp_buffer;
1528 stream->getbuf_last = -params->frames;
1529 }else{
1530 *params->data = stream->local_buffer + stream->wri_offs_frames * stream->fmt->nBlockAlign;
1531 stream->getbuf_last = params->frames;
1534 silence_buffer(stream, *params->data, params->frames);
1535 params->result = S_OK;
1537 end:
1538 os_unfair_lock_unlock(&stream->lock);
1540 return STATUS_SUCCESS;
1543 static NTSTATUS unix_release_render_buffer(void *args)
1545 struct release_render_buffer_params *params = args;
1546 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1547 BYTE *buffer;
1549 os_unfair_lock_lock(&stream->lock);
1551 if(!params->written_frames){
1552 stream->getbuf_last = 0;
1553 params->result = S_OK;
1554 }else if(!stream->getbuf_last)
1555 params->result = AUDCLNT_E_OUT_OF_ORDER;
1556 else if(params->written_frames > (stream->getbuf_last >= 0 ? stream->getbuf_last : -stream->getbuf_last))
1557 params->result = AUDCLNT_E_INVALID_SIZE;
1558 else{
1559 if(stream->getbuf_last >= 0)
1560 buffer = stream->local_buffer + stream->wri_offs_frames * stream->fmt->nBlockAlign;
1561 else
1562 buffer = stream->tmp_buffer;
1564 if(params->flags & AUDCLNT_BUFFERFLAGS_SILENT)
1565 silence_buffer(stream, buffer, params->written_frames);
1567 if(stream->getbuf_last < 0)
1568 ca_wrap_buffer(stream->local_buffer,
1569 stream->wri_offs_frames * stream->fmt->nBlockAlign,
1570 stream->bufsize_frames * stream->fmt->nBlockAlign,
1571 buffer, params->written_frames * stream->fmt->nBlockAlign);
1573 stream->wri_offs_frames += params->written_frames;
1574 stream->wri_offs_frames %= stream->bufsize_frames;
1575 stream->held_frames += params->written_frames;
1576 stream->written_frames += params->written_frames;
1577 stream->getbuf_last = 0;
1579 params->result = S_OK;
1582 os_unfair_lock_unlock(&stream->lock);
1584 return STATUS_SUCCESS;
1587 static NTSTATUS unix_get_capture_buffer(void *args)
1589 struct get_capture_buffer_params *params = args;
1590 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1591 UINT32 chunk_bytes, chunk_frames;
1592 LARGE_INTEGER stamp, freq;
1593 SIZE_T size;
1595 os_unfair_lock_lock(&stream->lock);
1597 if(stream->getbuf_last){
1598 params->result = AUDCLNT_E_OUT_OF_ORDER;
1599 goto end;
1602 capture_resample(stream);
1604 *params->frames = 0;
1606 if(stream->held_frames < stream->period_frames){
1607 params->result = AUDCLNT_S_BUFFER_EMPTY;
1608 goto end;
1611 *params->flags = 0;
1612 chunk_frames = stream->bufsize_frames - stream->lcl_offs_frames;
1613 if(chunk_frames < stream->period_frames){
1614 chunk_bytes = chunk_frames * stream->fmt->nBlockAlign;
1615 if(!stream->tmp_buffer){
1616 size = stream->period_frames * stream->fmt->nBlockAlign;
1617 NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, zero_bits,
1618 &size, MEM_COMMIT, PAGE_READWRITE);
1620 *params->data = stream->tmp_buffer;
1621 memcpy(*params->data, stream->local_buffer + stream->lcl_offs_frames * stream->fmt->nBlockAlign,
1622 chunk_bytes);
1623 memcpy(*params->data + chunk_bytes, stream->local_buffer,
1624 stream->period_frames * stream->fmt->nBlockAlign - chunk_bytes);
1625 }else
1626 *params->data = stream->local_buffer + stream->lcl_offs_frames * stream->fmt->nBlockAlign;
1628 stream->getbuf_last = *params->frames = stream->period_frames;
1630 if(params->devpos)
1631 *params->devpos = stream->written_frames;
1632 if(params->qpcpos){ /* fixme: qpc of recording time */
1633 NtQueryPerformanceCounter(&stamp, &freq);
1634 *params->qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1636 params->result = S_OK;
1638 end:
1639 os_unfair_lock_unlock(&stream->lock);
1640 return STATUS_SUCCESS;
1643 static NTSTATUS unix_release_capture_buffer(void *args)
1645 struct release_capture_buffer_params *params = args;
1646 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1648 os_unfair_lock_lock(&stream->lock);
1650 if(!params->done){
1651 stream->getbuf_last = 0;
1652 params->result = S_OK;
1653 }else if(!stream->getbuf_last)
1654 params->result = AUDCLNT_E_OUT_OF_ORDER;
1655 else if(stream->getbuf_last != params->done)
1656 params->result = AUDCLNT_E_INVALID_SIZE;
1657 else{
1658 stream->written_frames += params->done;
1659 stream->held_frames -= params->done;
1660 stream->lcl_offs_frames += params->done;
1661 stream->lcl_offs_frames %= stream->bufsize_frames;
1662 stream->getbuf_last = 0;
1663 params->result = S_OK;
1666 os_unfair_lock_unlock(&stream->lock);
1668 return STATUS_SUCCESS;
1671 static NTSTATUS unix_get_next_packet_size(void *args)
1673 struct get_next_packet_size_params *params = args;
1674 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1676 os_unfair_lock_lock(&stream->lock);
1678 capture_resample(stream);
1680 if(stream->held_frames >= stream->period_frames)
1681 *params->frames = stream->period_frames;
1682 else
1683 *params->frames = 0;
1685 os_unfair_lock_unlock(&stream->lock);
1687 params->result = S_OK;
1688 return STATUS_SUCCESS;
1691 static NTSTATUS unix_get_position(void *args)
1693 struct get_position_params *params = args;
1694 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1695 LARGE_INTEGER stamp, freq;
1697 if (params->device) {
1698 FIXME("Device position reporting not implemented\n");
1699 params->result = E_NOTIMPL;
1700 return STATUS_SUCCESS;
1703 os_unfair_lock_lock(&stream->lock);
1705 *params->pos = stream->written_frames - stream->held_frames;
1707 if(stream->share == AUDCLNT_SHAREMODE_SHARED)
1708 *params->pos *= stream->fmt->nBlockAlign;
1710 if(params->qpctime){
1711 NtQueryPerformanceCounter(&stamp, &freq);
1712 *params->qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1715 os_unfair_lock_unlock(&stream->lock);
1717 params->result = S_OK;
1718 return STATUS_SUCCESS;
1721 static NTSTATUS unix_get_frequency(void *args)
1723 struct get_frequency_params *params = args;
1724 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1726 if(stream->share == AUDCLNT_SHAREMODE_SHARED)
1727 *params->freq = (UINT64)stream->fmt->nSamplesPerSec * stream->fmt->nBlockAlign;
1728 else
1729 *params->freq = stream->fmt->nSamplesPerSec;
1731 params->result = S_OK;
1732 return STATUS_SUCCESS;
1735 static NTSTATUS unix_is_started(void *args)
1737 struct is_started_params *params = args;
1738 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1740 if(stream->playing)
1741 params->result = S_OK;
1742 else
1743 params->result = S_FALSE;
1745 return STATUS_SUCCESS;
1748 static NTSTATUS unix_get_prop_value(void *args)
1750 struct get_prop_value_params *params = args;
1752 params->result = E_NOTIMPL;
1754 return STATUS_SUCCESS;
1757 static NTSTATUS unix_set_volumes(void *args)
1759 struct set_volumes_params *params = args;
1760 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1761 Float32 level = params->master_volume;
1762 OSStatus sc;
1763 UINT32 i;
1764 AudioObjectPropertyAddress prop_addr = {
1765 kAudioDevicePropertyVolumeScalar,
1766 kAudioObjectPropertyScopeGlobal,
1767 kAudioObjectPropertyElementMain
1770 sc = AudioObjectSetPropertyData(stream->dev_id, &prop_addr, 0, NULL, sizeof(float), &level);
1771 if (sc == noErr)
1772 level = 1.0f;
1773 else
1774 WARN("Couldn't set master volume, applying it directly to the channels: %x\n", (int)sc);
1776 for (i = 1; i <= stream->fmt->nChannels; ++i) {
1777 const float vol = level * params->session_volumes[i - 1] * params->volumes[i - 1];
1779 prop_addr.mElement = i;
1781 sc = AudioObjectSetPropertyData(stream->dev_id, &prop_addr, 0, NULL, sizeof(float), &vol);
1782 if (sc != noErr) {
1783 WARN("Couldn't set channel #%u volume: %x\n", i, (int)sc);
1787 return STATUS_SUCCESS;
1790 static NTSTATUS unix_set_event_handle(void *args)
1792 struct set_event_handle_params *params = args;
1793 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1794 HRESULT hr = S_OK;
1796 os_unfair_lock_lock(&stream->lock);
1797 if(!stream->unit)
1798 hr = AUDCLNT_E_DEVICE_INVALIDATED;
1799 else if(!(stream->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK))
1800 hr = AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1801 else if(stream->event)
1802 hr = HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
1803 else
1804 stream->event = params->event;
1805 os_unfair_lock_unlock(&stream->lock);
1807 params->result = hr;
1808 return STATUS_SUCCESS;
1811 const unixlib_entry_t __wine_unix_call_funcs[] =
1813 unix_process_attach,
1814 unix_not_implemented,
1815 unix_main_loop,
1816 unix_get_endpoint_ids,
1817 unix_create_stream,
1818 unix_release_stream,
1819 unix_start,
1820 unix_stop,
1821 unix_reset,
1822 unix_timer_loop,
1823 unix_get_render_buffer,
1824 unix_release_render_buffer,
1825 unix_get_capture_buffer,
1826 unix_release_capture_buffer,
1827 unix_is_format_supported,
1828 unix_get_mix_format,
1829 unix_get_device_period,
1830 unix_get_buffer_size,
1831 unix_get_latency,
1832 unix_get_current_padding,
1833 unix_get_next_packet_size,
1834 unix_get_frequency,
1835 unix_get_position,
1836 unix_set_volumes,
1837 unix_set_event_handle,
1838 unix_not_implemented,
1839 unix_is_started,
1840 unix_get_prop_value,
1841 unix_midi_init,
1842 unix_midi_release,
1843 unix_midi_out_message,
1844 unix_midi_in_message,
1845 unix_midi_notify_wait,
1846 unix_not_implemented,
1849 C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs) == funcs_count);
1851 #ifdef _WIN64
1853 typedef UINT PTR32;
1855 static NTSTATUS unix_wow64_main_loop(void *args)
1857 struct
1859 PTR32 event;
1860 } *params32 = args;
1861 struct main_loop_params params =
1863 .event = ULongToHandle(params32->event)
1865 return unix_main_loop(&params);
1868 static NTSTATUS unix_wow64_get_endpoint_ids(void *args)
1870 struct
1872 EDataFlow flow;
1873 PTR32 endpoints;
1874 unsigned int size;
1875 HRESULT result;
1876 unsigned int num;
1877 unsigned int default_idx;
1878 } *params32 = args;
1879 struct get_endpoint_ids_params params =
1881 .flow = params32->flow,
1882 .endpoints = ULongToPtr(params32->endpoints),
1883 .size = params32->size
1885 unix_get_endpoint_ids(&params);
1886 params32->size = params.size;
1887 params32->result = params.result;
1888 params32->num = params.num;
1889 params32->default_idx = params.default_idx;
1890 return STATUS_SUCCESS;
1893 static NTSTATUS unix_wow64_create_stream(void *args)
1895 struct
1897 PTR32 name;
1898 PTR32 device;
1899 EDataFlow flow;
1900 AUDCLNT_SHAREMODE share;
1901 DWORD flags;
1902 REFERENCE_TIME duration;
1903 REFERENCE_TIME period;
1904 PTR32 fmt;
1905 HRESULT result;
1906 PTR32 channel_count;
1907 PTR32 stream;
1908 } *params32 = args;
1909 struct create_stream_params params =
1911 .name = ULongToPtr(params32->name),
1912 .device = ULongToPtr(params32->device),
1913 .flow = params32->flow,
1914 .share = params32->share,
1915 .flags = params32->flags,
1916 .duration = params32->duration,
1917 .period = params32->period,
1918 .fmt = ULongToPtr(params32->fmt),
1919 .channel_count = ULongToPtr(params32->channel_count),
1920 .stream = ULongToPtr(params32->stream)
1922 unix_create_stream(&params);
1923 params32->result = params.result;
1924 return STATUS_SUCCESS;
1927 static NTSTATUS unix_wow64_release_stream(void *args)
1929 struct
1931 stream_handle stream;
1932 PTR32 timer_thread;
1933 HRESULT result;
1934 } *params32 = args;
1935 struct release_stream_params params =
1937 .stream = params32->stream,
1938 .timer_thread = ULongToHandle(params32->timer_thread)
1940 unix_release_stream(&params);
1941 params32->result = params.result;
1942 return STATUS_SUCCESS;
1945 static NTSTATUS unix_wow64_get_render_buffer(void *args)
1947 struct
1949 stream_handle stream;
1950 UINT32 frames;
1951 HRESULT result;
1952 PTR32 data;
1953 } *params32 = args;
1954 BYTE *data = NULL;
1955 struct get_render_buffer_params params =
1957 .stream = params32->stream,
1958 .frames = params32->frames,
1959 .data = &data
1961 unix_get_render_buffer(&params);
1962 params32->result = params.result;
1963 *(unsigned int *)ULongToPtr(params32->data) = PtrToUlong(data);
1964 return STATUS_SUCCESS;
1967 static NTSTATUS unix_wow64_get_capture_buffer(void *args)
1969 struct
1971 stream_handle stream;
1972 HRESULT result;
1973 PTR32 data;
1974 PTR32 frames;
1975 PTR32 flags;
1976 PTR32 devpos;
1977 PTR32 qpcpos;
1978 } *params32 = args;
1979 BYTE *data = NULL;
1980 struct get_capture_buffer_params params =
1982 .stream = params32->stream,
1983 .data = &data,
1984 .frames = ULongToPtr(params32->frames),
1985 .flags = ULongToPtr(params32->flags),
1986 .devpos = ULongToPtr(params32->devpos),
1987 .qpcpos = ULongToPtr(params32->qpcpos)
1989 unix_get_capture_buffer(&params);
1990 params32->result = params.result;
1991 *(unsigned int *)ULongToPtr(params32->data) = PtrToUlong(data);
1992 return STATUS_SUCCESS;
1995 static NTSTATUS unix_wow64_is_format_supported(void *args)
1997 struct
1999 PTR32 device;
2000 EDataFlow flow;
2001 AUDCLNT_SHAREMODE share;
2002 PTR32 fmt_in;
2003 PTR32 fmt_out;
2004 HRESULT result;
2005 } *params32 = args;
2006 struct is_format_supported_params params =
2008 .device = ULongToPtr(params32->device),
2009 .flow = params32->flow,
2010 .share = params32->share,
2011 .fmt_in = ULongToPtr(params32->fmt_in),
2012 .fmt_out = ULongToPtr(params32->fmt_out)
2014 unix_is_format_supported(&params);
2015 params32->result = params.result;
2016 return STATUS_SUCCESS;
2019 static NTSTATUS unix_wow64_get_mix_format(void *args)
2021 struct
2023 PTR32 device;
2024 EDataFlow flow;
2025 PTR32 fmt;
2026 HRESULT result;
2027 } *params32 = args;
2028 struct get_mix_format_params params =
2030 .device = ULongToPtr(params32->device),
2031 .flow = params32->flow,
2032 .fmt = ULongToPtr(params32->fmt)
2034 unix_get_mix_format(&params);
2035 params32->result = params.result;
2036 return STATUS_SUCCESS;
2039 static NTSTATUS unix_wow64_get_device_period(void *args)
2041 struct
2043 PTR32 device;
2044 EDataFlow flow;
2045 HRESULT result;
2046 PTR32 def_period;
2047 PTR32 min_period;
2048 } *params32 = args;
2049 struct get_device_period_params params =
2051 .device = ULongToPtr(params32->device),
2052 .flow = params32->flow,
2053 .def_period = ULongToPtr(params32->def_period),
2054 .min_period = ULongToPtr(params32->min_period),
2056 unix_get_device_period(&params);
2057 params32->result = params.result;
2058 return STATUS_SUCCESS;
2061 static NTSTATUS unix_wow64_get_buffer_size(void *args)
2063 struct
2065 stream_handle stream;
2066 HRESULT result;
2067 PTR32 frames;
2068 } *params32 = args;
2069 struct get_buffer_size_params params =
2071 .stream = params32->stream,
2072 .frames = ULongToPtr(params32->frames)
2074 unix_get_buffer_size(&params);
2075 params32->result = params.result;
2076 return STATUS_SUCCESS;
2079 static NTSTATUS unix_wow64_get_latency(void *args)
2081 struct
2083 stream_handle stream;
2084 HRESULT result;
2085 PTR32 latency;
2086 } *params32 = args;
2087 struct get_latency_params params =
2089 .stream = params32->stream,
2090 .latency = ULongToPtr(params32->latency)
2092 unix_get_latency(&params);
2093 params32->result = params.result;
2094 return STATUS_SUCCESS;
2097 static NTSTATUS unix_wow64_get_current_padding(void *args)
2099 struct
2101 stream_handle stream;
2102 HRESULT result;
2103 PTR32 padding;
2104 } *params32 = args;
2105 struct get_current_padding_params params =
2107 .stream = params32->stream,
2108 .padding = ULongToPtr(params32->padding)
2110 unix_get_current_padding(&params);
2111 params32->result = params.result;
2112 return STATUS_SUCCESS;
2115 static NTSTATUS unix_wow64_get_next_packet_size(void *args)
2117 struct
2119 stream_handle stream;
2120 HRESULT result;
2121 PTR32 frames;
2122 } *params32 = args;
2123 struct get_next_packet_size_params params =
2125 .stream = params32->stream,
2126 .frames = ULongToPtr(params32->frames)
2128 unix_get_next_packet_size(&params);
2129 params32->result = params.result;
2130 return STATUS_SUCCESS;
2133 static NTSTATUS unix_wow64_get_position(void *args)
2135 struct
2137 stream_handle stream;
2138 BOOL device;
2139 HRESULT result;
2140 PTR32 pos;
2141 PTR32 qpctime;
2142 } *params32 = args;
2143 struct get_position_params params =
2145 .stream = params32->stream,
2146 .device = params32->device,
2147 .pos = ULongToPtr(params32->pos),
2148 .qpctime = ULongToPtr(params32->qpctime)
2150 unix_get_position(&params);
2151 params32->result = params.result;
2152 return STATUS_SUCCESS;
2155 static NTSTATUS unix_wow64_get_frequency(void *args)
2157 struct
2159 stream_handle stream;
2160 HRESULT result;
2161 PTR32 freq;
2162 } *params32 = args;
2163 struct get_frequency_params params =
2165 .stream = params32->stream,
2166 .freq = ULongToPtr(params32->freq)
2168 unix_get_frequency(&params);
2169 params32->result = params.result;
2170 return STATUS_SUCCESS;
2173 static NTSTATUS unix_wow64_set_volumes(void *args)
2175 struct
2177 stream_handle stream;
2178 float master_volume;
2179 PTR32 volumes;
2180 PTR32 session_volumes;
2181 } *params32 = args;
2182 struct set_volumes_params params =
2184 .stream = params32->stream,
2185 .master_volume = params32->master_volume,
2186 .volumes = ULongToPtr(params32->volumes),
2187 .session_volumes = ULongToPtr(params32->session_volumes),
2189 return unix_set_volumes(&params);
2192 static NTSTATUS unix_wow64_set_event_handle(void *args)
2194 struct
2196 stream_handle stream;
2197 PTR32 event;
2198 HRESULT result;
2199 } *params32 = args;
2200 struct set_event_handle_params params =
2202 .stream = params32->stream,
2203 .event = ULongToHandle(params32->event)
2205 unix_set_event_handle(&params);
2206 params32->result = params.result;
2207 return STATUS_SUCCESS;
2210 static NTSTATUS unix_wow64_get_prop_value(void *args)
2212 struct propvariant32
2214 WORD vt;
2215 WORD pad1, pad2, pad3;
2216 union
2218 ULONG ulVal;
2219 PTR32 ptr;
2220 ULARGE_INTEGER uhVal;
2222 } *value32;
2223 struct
2225 PTR32 device;
2226 EDataFlow flow;
2227 PTR32 guid;
2228 PTR32 prop;
2229 HRESULT result;
2230 PTR32 value;
2231 PTR32 buffer; /* caller allocated buffer to hold value's strings */
2232 PTR32 buffer_size;
2233 } *params32 = args;
2234 PROPVARIANT value;
2235 struct get_prop_value_params params =
2237 .device = ULongToPtr(params32->device),
2238 .flow = params32->flow,
2239 .guid = ULongToPtr(params32->guid),
2240 .prop = ULongToPtr(params32->prop),
2241 .value = &value,
2242 .buffer = ULongToPtr(params32->buffer),
2243 .buffer_size = ULongToPtr(params32->buffer_size)
2245 unix_get_prop_value(&params);
2246 params32->result = params.result;
2247 if (SUCCEEDED(params.result))
2249 value32 = UlongToPtr(params32->value);
2250 value32->vt = value.vt;
2251 switch (value.vt)
2253 case VT_UI4:
2254 value32->ulVal = value.ulVal;
2255 break;
2256 case VT_LPWSTR:
2257 value32->ptr = params32->buffer;
2258 break;
2259 default:
2260 FIXME("Unhandled vt %04x\n", value.vt);
2263 return STATUS_SUCCESS;
2266 const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
2268 unix_process_attach,
2269 unix_not_implemented,
2270 unix_wow64_main_loop,
2271 unix_wow64_get_endpoint_ids,
2272 unix_wow64_create_stream,
2273 unix_wow64_release_stream,
2274 unix_start,
2275 unix_stop,
2276 unix_reset,
2277 unix_timer_loop,
2278 unix_wow64_get_render_buffer,
2279 unix_release_render_buffer,
2280 unix_wow64_get_capture_buffer,
2281 unix_release_capture_buffer,
2282 unix_wow64_is_format_supported,
2283 unix_wow64_get_mix_format,
2284 unix_wow64_get_device_period,
2285 unix_wow64_get_buffer_size,
2286 unix_wow64_get_latency,
2287 unix_wow64_get_current_padding,
2288 unix_wow64_get_next_packet_size,
2289 unix_wow64_get_frequency,
2290 unix_wow64_get_position,
2291 unix_wow64_set_volumes,
2292 unix_wow64_set_event_handle,
2293 unix_not_implemented,
2294 unix_is_started,
2295 unix_wow64_get_prop_value,
2296 unix_wow64_midi_init,
2297 unix_midi_release,
2298 unix_wow64_midi_out_message,
2299 unix_wow64_midi_in_message,
2300 unix_wow64_midi_notify_wait,
2301 unix_not_implemented,
2304 C_ASSERT(ARRAYSIZE(__wine_unix_call_wow64_funcs) == funcs_count);
2306 #endif /* _WIN64 */