mscoree: Update Wine Mono to 9.2.0.
[wine.git] / dlls / winecoreaudio.drv / coreaudio.c
blobdb5e1116bf89c10da0f6053fb470868751b682d8
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 struct coreaudio_stream
89 os_unfair_lock lock;
90 AudioComponentInstance unit;
91 AudioConverterRef converter;
92 AudioStreamBasicDescription dev_desc; /* audio unit format, not necessarily the same as fmt */
93 AudioDeviceID dev_id;
95 EDataFlow flow;
96 DWORD flags;
97 AUDCLNT_SHAREMODE share;
98 HANDLE event;
100 BOOL playing, please_quit;
101 REFERENCE_TIME period;
102 UINT32 period_frames;
103 UINT32 bufsize_frames, resamp_bufsize_frames;
104 UINT32 lcl_offs_frames, held_frames, wri_offs_frames, tmp_buffer_frames;
105 UINT32 cap_bufsize_frames, cap_offs_frames, cap_held_frames;
106 UINT32 wrap_bufsize_frames;
107 UINT64 written_frames;
108 INT32 getbuf_last;
109 WAVEFORMATEX *fmt;
110 BYTE *local_buffer, *cap_buffer, *wrap_buffer, *resamp_buffer, *tmp_buffer;
113 static const REFERENCE_TIME def_period = 100000;
114 static const REFERENCE_TIME min_period = 50000;
116 static ULONG_PTR zero_bits = 0;
118 static NTSTATUS unix_not_implemented(void *args)
120 return STATUS_SUCCESS;
123 static HRESULT osstatus_to_hresult(OSStatus sc)
125 switch(sc){
126 case kAudioFormatUnsupportedDataFormatError:
127 case kAudioFormatUnknownFormatError:
128 case kAudioDeviceUnsupportedFormatError:
129 return AUDCLNT_E_UNSUPPORTED_FORMAT;
130 case kAudioHardwareBadDeviceError:
131 return AUDCLNT_E_DEVICE_INVALIDATED;
133 return E_FAIL;
136 static struct coreaudio_stream *handle_get_stream(stream_handle h)
138 return (struct coreaudio_stream *)(UINT_PTR)h;
141 /* copied from kernelbase */
142 static int muldiv( int a, int b, int c )
144 LONGLONG ret;
146 if (!c) return -1;
148 /* We want to deal with a positive divisor to simplify the logic. */
149 if (c < 0)
151 a = -a;
152 c = -c;
155 /* If the result is positive, we "add" to round. else, we subtract to round. */
156 if ((a < 0 && b < 0) || (a >= 0 && b >= 0))
157 ret = (((LONGLONG)a * b) + (c / 2)) / c;
158 else
159 ret = (((LONGLONG)a * b) - (c / 2)) / c;
161 if (ret > 2147483647 || ret < -2147483647) return -1;
162 return ret;
165 static AudioObjectPropertyScope get_scope(EDataFlow flow)
167 return (flow == eRender) ? kAudioDevicePropertyScopeOutput : kAudioDevicePropertyScopeInput;
170 static BOOL device_has_channels(AudioDeviceID device, EDataFlow flow)
172 AudioObjectPropertyAddress addr;
173 AudioBufferList *buffers;
174 BOOL ret = FALSE;
175 OSStatus sc;
176 UInt32 size;
177 int i;
179 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
180 addr.mScope = get_scope(flow);
181 addr.mElement = 0;
183 sc = AudioObjectGetPropertyDataSize(device, &addr, 0, NULL, &size);
184 if(sc != noErr){
185 WARN("Unable to get _StreamConfiguration property size for device %u: %x\n",
186 (unsigned int)device, (int)sc);
187 return FALSE;
190 buffers = malloc(size);
191 if(!buffers) return FALSE;
193 sc = AudioObjectGetPropertyData(device, &addr, 0, NULL, &size, buffers);
194 if(sc != noErr){
195 WARN("Unable to get _StreamConfiguration property for device %u: %x\n",
196 (unsigned int)device, (int)sc);
197 free(buffers);
198 return FALSE;
201 for(i = 0; i < buffers->mNumberBuffers; i++){
202 if(buffers->mBuffers[i].mNumberChannels > 0){
203 ret = TRUE;
204 break;
207 free(buffers);
208 return ret;
211 static NTSTATUS unix_process_attach(void *args)
213 #ifdef _WIN64
214 if (NtCurrentTeb()->WowTebOffset)
216 SYSTEM_BASIC_INFORMATION info;
218 NtQuerySystemInformation(SystemEmulationBasicInformation, &info, sizeof(info), NULL);
219 zero_bits = (ULONG_PTR)info.HighestUserAddress | 0x7fffffff;
221 #endif
222 return STATUS_SUCCESS;
225 static NTSTATUS unix_main_loop(void *args)
227 struct main_loop_params *params = args;
228 NtSetEvent(params->event, NULL);
229 return STATUS_SUCCESS;
232 static NTSTATUS unix_get_endpoint_ids(void *args)
234 struct get_endpoint_ids_params *params = args;
235 unsigned int num_devices, i, needed, offset;
236 AudioDeviceID *devices, default_id;
237 AudioObjectPropertyAddress addr;
238 struct endpoint *endpoint;
239 UInt32 devsize, size;
240 struct endpoint_info
242 CFStringRef name;
243 CFStringRef uid;
244 AudioDeviceID id;
245 } *info;
246 OSStatus sc;
247 UniChar *ptr;
249 params->num = 0;
250 params->default_idx = 0;
252 addr.mScope = kAudioObjectPropertyScopeGlobal;
253 addr.mElement = kAudioObjectPropertyElementMain;
254 if(params->flow == eRender) addr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
255 else if(params->flow == eCapture) addr.mSelector = kAudioHardwarePropertyDefaultInputDevice;
256 else{
257 params->result = E_INVALIDARG;
258 return STATUS_SUCCESS;
261 size = sizeof(default_id);
262 sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL, &size, &default_id);
263 if(sc != noErr){
264 WARN("Getting _DefaultInputDevice property failed: %x\n", (int)sc);
265 default_id = -1;
268 addr.mSelector = kAudioHardwarePropertyDevices;
269 sc = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, 0, NULL, &devsize);
270 if(sc != noErr){
271 WARN("Getting _Devices property size failed: %x\n", (int)sc);
272 params->result = osstatus_to_hresult(sc);
273 return STATUS_SUCCESS;
276 num_devices = devsize / sizeof(AudioDeviceID);
277 devices = malloc(devsize);
278 info = malloc(num_devices * sizeof(*info));
279 if(!devices || !info){
280 free(info);
281 free(devices);
282 params->result = E_OUTOFMEMORY;
283 return STATUS_SUCCESS;
286 sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL, &devsize, devices);
287 if(sc != noErr){
288 WARN("Getting _Devices property failed: %x\n", (int)sc);
289 free(info);
290 free(devices);
291 params->result = osstatus_to_hresult(sc);
292 return STATUS_SUCCESS;
295 addr.mScope = get_scope(params->flow);
296 addr.mElement = 0;
298 for(i = 0; i < num_devices; i++){
299 if(!device_has_channels(devices[i], params->flow)) continue;
301 addr.mSelector = kAudioObjectPropertyName;
302 size = sizeof(CFStringRef);
303 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL, &size, &info[params->num].name);
304 if(sc != noErr){
305 WARN("Unable to get _Name property for device %u: %x\n",
306 (unsigned int)devices[i], (int)sc);
307 continue;
310 addr.mSelector = kAudioDevicePropertyDeviceUID;
311 size = sizeof(CFStringRef);
312 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL, &size, &info[params->num].uid);
313 if(sc != noErr){
314 WARN("Unable to get UID property for device %u: %x\n",
315 (unsigned int)devices[i], (int)sc);
316 continue;
319 info[params->num++].id = devices[i];
321 free(devices);
323 offset = needed = sizeof(*endpoint) * params->num;
324 endpoint = params->endpoints;
326 for(i = 0; i < params->num; i++){
327 const SIZE_T name_len = CFStringGetLength(info[i].name) + 1;
328 CFIndex device_len;
330 CFStringGetBytes(info[i].uid, CFRangeMake(0, CFStringGetLength(info[i].uid)), kCFStringEncodingUTF8,
331 0, false, NULL, 0, &device_len);
332 device_len++; /* for null terminator */
334 needed += name_len * sizeof(WCHAR) + ((device_len + 1) & ~1);
336 if(needed <= params->size){
337 endpoint->name = offset;
338 ptr = (UniChar *)((char *)params->endpoints + offset);
339 CFStringGetCharacters(info[i].name, CFRangeMake(0, name_len - 1), ptr);
340 ptr[name_len - 1] = 0;
341 offset += name_len * sizeof(WCHAR);
343 endpoint->device = offset;
344 CFStringGetBytes(info[i].uid, CFRangeMake(0, CFStringGetLength(info[i].uid)), kCFStringEncodingUTF8,
345 0, false, (UInt8 *)params->endpoints + offset, params->size - offset, NULL);
346 ((char *)params->endpoints)[offset + device_len - 1] = '\0';
347 offset += (device_len + 1) & ~1;
349 endpoint++;
351 CFRelease(info[i].name);
352 CFRelease(info[i].uid);
353 if(info[i].id == default_id) params->default_idx = i;
355 free(info);
357 if(needed > params->size){
358 params->size = needed;
359 params->result = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
361 else params->result = S_OK;
363 return STATUS_SUCCESS;
366 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
368 WAVEFORMATEX *ret;
369 size_t size;
371 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
372 size = sizeof(WAVEFORMATEXTENSIBLE);
373 else
374 size = sizeof(WAVEFORMATEX);
376 ret = malloc(size);
377 if(!ret)
378 return NULL;
380 memcpy(ret, fmt, size);
382 ret->cbSize = size - sizeof(WAVEFORMATEX);
384 return ret;
387 static void silence_buffer(struct coreaudio_stream *stream, BYTE *buffer, UINT32 frames)
389 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)stream->fmt;
390 if((stream->fmt->wFormatTag == WAVE_FORMAT_PCM ||
391 (stream->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
392 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
393 stream->fmt->wBitsPerSample == 8)
394 memset(buffer, 128, frames * stream->fmt->nBlockAlign);
395 else
396 memset(buffer, 0, frames * stream->fmt->nBlockAlign);
399 /* CA is pulling data from us */
400 static OSStatus ca_render_cb(void *user, AudioUnitRenderActionFlags *flags,
401 const AudioTimeStamp *ts, UInt32 bus, UInt32 nframes,
402 AudioBufferList *data)
404 struct coreaudio_stream *stream = user;
405 UINT32 to_copy_bytes, to_copy_frames, chunk_bytes, lcl_offs_bytes;
407 os_unfair_lock_lock(&stream->lock);
409 if(stream->playing){
410 lcl_offs_bytes = stream->lcl_offs_frames * stream->fmt->nBlockAlign;
411 to_copy_frames = min(nframes, stream->held_frames);
412 to_copy_bytes = to_copy_frames * stream->fmt->nBlockAlign;
414 chunk_bytes = (stream->bufsize_frames - stream->lcl_offs_frames) * stream->fmt->nBlockAlign;
416 if(to_copy_bytes > chunk_bytes){
417 memcpy(data->mBuffers[0].mData, stream->local_buffer + lcl_offs_bytes, chunk_bytes);
418 memcpy(((BYTE *)data->mBuffers[0].mData) + chunk_bytes, stream->local_buffer, to_copy_bytes - chunk_bytes);
419 }else
420 memcpy(data->mBuffers[0].mData, stream->local_buffer + lcl_offs_bytes, to_copy_bytes);
422 stream->lcl_offs_frames += to_copy_frames;
423 stream->lcl_offs_frames %= stream->bufsize_frames;
424 stream->held_frames -= to_copy_frames;
425 }else
426 to_copy_bytes = to_copy_frames = 0;
428 if(nframes > to_copy_frames)
429 silence_buffer(stream, ((BYTE *)data->mBuffers[0].mData) + to_copy_bytes, nframes - to_copy_frames);
431 os_unfair_lock_unlock(&stream->lock);
433 return noErr;
436 static void ca_wrap_buffer(BYTE *dst, UINT32 dst_offs, UINT32 dst_bytes,
437 BYTE *src, UINT32 src_bytes)
439 UINT32 chunk_bytes = dst_bytes - dst_offs;
441 if(chunk_bytes < src_bytes){
442 memcpy(dst + dst_offs, src, chunk_bytes);
443 memcpy(dst, src + chunk_bytes, src_bytes - chunk_bytes);
444 }else
445 memcpy(dst + dst_offs, src, src_bytes);
448 /* we need to trigger CA to pull data from the device and give it to us
450 * raw data from CA is stored in cap_buffer, possibly via wrap_buffer
452 * raw data is resampled from cap_buffer into resamp_buffer in period-size
453 * chunks and copied to local_buffer
455 static OSStatus ca_capture_cb(void *user, AudioUnitRenderActionFlags *flags,
456 const AudioTimeStamp *ts, UInt32 bus, UInt32 nframes,
457 AudioBufferList *data)
459 struct coreaudio_stream *stream = user;
460 AudioBufferList list;
461 OSStatus sc;
462 UINT32 cap_wri_offs_frames;
464 os_unfair_lock_lock(&stream->lock);
466 cap_wri_offs_frames = (stream->cap_offs_frames + stream->cap_held_frames) % stream->cap_bufsize_frames;
468 list.mNumberBuffers = 1;
469 list.mBuffers[0].mNumberChannels = stream->fmt->nChannels;
470 list.mBuffers[0].mDataByteSize = nframes * stream->fmt->nBlockAlign;
472 if(!stream->playing || cap_wri_offs_frames + nframes > stream->cap_bufsize_frames){
473 if(stream->wrap_bufsize_frames < nframes){
474 free(stream->wrap_buffer);
475 stream->wrap_buffer = malloc(list.mBuffers[0].mDataByteSize);
476 stream->wrap_bufsize_frames = nframes;
479 list.mBuffers[0].mData = stream->wrap_buffer;
480 }else
481 list.mBuffers[0].mData = stream->cap_buffer + cap_wri_offs_frames * stream->fmt->nBlockAlign;
483 sc = AudioUnitRender(stream->unit, flags, ts, bus, nframes, &list);
484 if(sc != noErr){
485 os_unfair_lock_unlock(&stream->lock);
486 return sc;
489 if(stream->playing){
490 if(list.mBuffers[0].mData == stream->wrap_buffer){
491 ca_wrap_buffer(stream->cap_buffer,
492 cap_wri_offs_frames * stream->fmt->nBlockAlign,
493 stream->cap_bufsize_frames * stream->fmt->nBlockAlign,
494 stream->wrap_buffer, list.mBuffers[0].mDataByteSize);
497 stream->cap_held_frames += list.mBuffers[0].mDataByteSize / stream->fmt->nBlockAlign;
498 if(stream->cap_held_frames > stream->cap_bufsize_frames){
499 stream->cap_offs_frames += stream->cap_held_frames % stream->cap_bufsize_frames;
500 stream->cap_offs_frames %= stream->cap_bufsize_frames;
501 stream->cap_held_frames = stream->cap_bufsize_frames;
505 os_unfair_lock_unlock(&stream->lock);
506 return noErr;
509 static AudioComponentInstance get_audiounit(EDataFlow dataflow, AudioDeviceID adevid)
511 AudioComponentInstance unit;
512 AudioComponent comp;
513 AudioComponentDescription desc;
514 OSStatus sc;
516 memset(&desc, 0, sizeof(desc));
517 desc.componentType = kAudioUnitType_Output;
518 desc.componentSubType = kAudioUnitSubType_HALOutput;
519 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
521 if(!(comp = AudioComponentFindNext(NULL, &desc))){
522 WARN("AudioComponentFindNext failed\n");
523 return NULL;
526 sc = AudioComponentInstanceNew(comp, &unit);
527 if(sc != noErr){
528 WARN("AudioComponentInstanceNew failed: %x\n", (int)sc);
529 return NULL;
532 if(dataflow == eCapture){
533 UInt32 enableio;
535 enableio = 1;
536 sc = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_EnableIO,
537 kAudioUnitScope_Input, 1, &enableio, sizeof(enableio));
538 if(sc != noErr){
539 WARN("Couldn't enable I/O on input element: %x\n", (int)sc);
540 AudioComponentInstanceDispose(unit);
541 return NULL;
544 enableio = 0;
545 sc = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_EnableIO,
546 kAudioUnitScope_Output, 0, &enableio, sizeof(enableio));
547 if(sc != noErr){
548 WARN("Couldn't disable I/O on output element: %x\n", (int)sc);
549 AudioComponentInstanceDispose(unit);
550 return NULL;
554 sc = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_CurrentDevice,
555 kAudioUnitScope_Global, 0, &adevid, sizeof(adevid));
556 if(sc != noErr){
557 WARN("Couldn't set audio unit device\n");
558 AudioComponentInstanceDispose(unit);
559 return NULL;
562 return unit;
565 static void dump_adesc(const char *aux, AudioStreamBasicDescription *desc)
567 TRACE("%s: mSampleRate: %f\n", aux, desc->mSampleRate);
568 TRACE("%s: mBytesPerPacket: %u\n", aux, (unsigned int)desc->mBytesPerPacket);
569 TRACE("%s: mFramesPerPacket: %u\n", aux, (unsigned int)desc->mFramesPerPacket);
570 TRACE("%s: mBytesPerFrame: %u\n", aux, (unsigned int)desc->mBytesPerFrame);
571 TRACE("%s: mChannelsPerFrame: %u\n", aux, (unsigned int)desc->mChannelsPerFrame);
572 TRACE("%s: mBitsPerChannel: %u\n", aux, (unsigned int)desc->mBitsPerChannel);
575 static HRESULT ca_get_audiodesc(AudioStreamBasicDescription *desc,
576 const WAVEFORMATEX *fmt)
578 const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
580 desc->mFormatFlags = 0;
582 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
583 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
584 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
585 desc->mFormatID = kAudioFormatLinearPCM;
586 if(fmt->wBitsPerSample > 8)
587 desc->mFormatFlags = kAudioFormatFlagIsSignedInteger;
588 }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
589 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
590 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
591 desc->mFormatID = kAudioFormatLinearPCM;
592 desc->mFormatFlags = kAudioFormatFlagIsFloat;
593 }else if(fmt->wFormatTag == WAVE_FORMAT_MULAW ||
594 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
595 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_MULAW))){
596 desc->mFormatID = kAudioFormatULaw;
597 }else if(fmt->wFormatTag == WAVE_FORMAT_ALAW ||
598 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
599 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_ALAW))){
600 desc->mFormatID = kAudioFormatALaw;
601 }else
602 return AUDCLNT_E_UNSUPPORTED_FORMAT;
604 desc->mSampleRate = fmt->nSamplesPerSec;
605 desc->mBytesPerPacket = fmt->nBlockAlign;
606 desc->mFramesPerPacket = 1;
607 desc->mBytesPerFrame = fmt->nBlockAlign;
608 desc->mChannelsPerFrame = fmt->nChannels;
609 desc->mBitsPerChannel = fmt->wBitsPerSample;
610 desc->mReserved = 0;
612 return S_OK;
615 static HRESULT ca_setup_audiounit(EDataFlow dataflow, AudioComponentInstance unit,
616 const WAVEFORMATEX *fmt, AudioStreamBasicDescription *dev_desc,
617 AudioConverterRef *converter)
619 OSStatus sc;
620 HRESULT hr;
622 if(dataflow == eCapture){
623 AudioStreamBasicDescription desc;
624 UInt32 size;
625 Float64 rate;
626 fenv_t fenv;
627 BOOL fenv_stored = TRUE;
629 hr = ca_get_audiodesc(&desc, fmt);
630 if(FAILED(hr))
631 return hr;
632 dump_adesc("requested", &desc);
634 /* input-only units can't perform sample rate conversion, so we have to
635 * set up our own AudioConverter to support arbitrary sample rates. */
636 size = sizeof(*dev_desc);
637 sc = AudioUnitGetProperty(unit, kAudioUnitProperty_StreamFormat,
638 kAudioUnitScope_Input, 1, dev_desc, &size);
639 if(sc != noErr){
640 WARN("Couldn't get unit format: %x\n", (int)sc);
641 return osstatus_to_hresult(sc);
643 dump_adesc("hardware", dev_desc);
645 rate = dev_desc->mSampleRate;
646 *dev_desc = desc;
647 dev_desc->mSampleRate = rate;
649 dump_adesc("final", dev_desc);
650 sc = AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat,
651 kAudioUnitScope_Output, 1, dev_desc, sizeof(*dev_desc));
652 if(sc != noErr){
653 WARN("Couldn't set unit format: %x\n", (int)sc);
654 return osstatus_to_hresult(sc);
657 /* AudioConverterNew requires divide-by-zero SSE exceptions to be masked */
658 if(feholdexcept(&fenv)){
659 WARN("Failed to store fenv state\n");
660 fenv_stored = FALSE;
663 sc = AudioConverterNew(dev_desc, &desc, converter);
665 if(fenv_stored && fesetenv(&fenv))
666 WARN("Failed to restore fenv state\n");
668 if(sc != noErr){
669 WARN("Couldn't create audio converter: %x\n", (int)sc);
670 return osstatus_to_hresult(sc);
672 }else{
673 hr = ca_get_audiodesc(dev_desc, fmt);
674 if(FAILED(hr))
675 return hr;
677 dump_adesc("final", dev_desc);
678 sc = AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat,
679 kAudioUnitScope_Input, 0, dev_desc, sizeof(*dev_desc));
680 if(sc != noErr){
681 WARN("Couldn't set format: %x\n", (int)sc);
682 return osstatus_to_hresult(sc);
686 return S_OK;
689 static AudioDeviceID dev_id_from_device(const char *device)
691 AudioDeviceID id;
692 CFStringRef uid;
693 UInt32 size;
694 OSStatus sc;
695 const AudioObjectPropertyAddress addr =
697 .mScope = kAudioObjectPropertyScopeGlobal,
698 .mElement = kAudioObjectPropertyElementMain,
699 .mSelector = kAudioHardwarePropertyTranslateUIDToDevice,
702 uid = CFStringCreateWithCStringNoCopy(NULL, device, kCFStringEncodingUTF8, kCFAllocatorNull);
704 size = sizeof(id);
705 sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, sizeof(uid), &uid, &size, &id);
706 CFRelease(uid);
707 if(sc != noErr){
708 WARN("Failed to get device ID for UID %s: %x\n", device, (int)sc);
709 return kAudioObjectUnknown;
712 if (id == kAudioObjectUnknown)
713 WARN("Failed to get device ID for UID %s\n", device);
715 return id;
718 static NTSTATUS unix_create_stream(void *args)
720 struct create_stream_params *params = args;
721 struct coreaudio_stream *stream;
722 AURenderCallbackStruct input;
723 OSStatus sc;
724 SIZE_T size;
726 params->result = S_OK;
728 if (!(stream = calloc(1, sizeof(*stream)))) {
729 params->result = E_OUTOFMEMORY;
730 return STATUS_SUCCESS;
733 stream->fmt = clone_format(params->fmt);
734 if(!stream->fmt){
735 params->result = E_OUTOFMEMORY;
736 goto end;
739 stream->period = params->period;
740 stream->period_frames = muldiv(params->period, stream->fmt->nSamplesPerSec, 10000000);
741 stream->dev_id = dev_id_from_device(params->device);
742 stream->flow = params->flow;
743 stream->flags = params->flags;
744 stream->share = params->share;
746 stream->bufsize_frames = muldiv(params->duration, stream->fmt->nSamplesPerSec, 10000000);
747 if(params->share == AUDCLNT_SHAREMODE_EXCLUSIVE)
748 stream->bufsize_frames -= stream->bufsize_frames % stream->period_frames;
750 if(!(stream->unit = get_audiounit(stream->flow, stream->dev_id))){
751 params->result = AUDCLNT_E_DEVICE_INVALIDATED;
752 goto end;
755 params->result = ca_setup_audiounit(stream->flow, stream->unit, stream->fmt, &stream->dev_desc, &stream->converter);
756 if(FAILED(params->result)) goto end;
758 input.inputProcRefCon = stream;
759 if(stream->flow == eCapture){
760 input.inputProc = ca_capture_cb;
761 sc = AudioUnitSetProperty(stream->unit, kAudioOutputUnitProperty_SetInputCallback,
762 kAudioUnitScope_Output, 1, &input, sizeof(input));
763 }else{
764 input.inputProc = ca_render_cb;
765 sc = AudioUnitSetProperty(stream->unit, kAudioUnitProperty_SetRenderCallback,
766 kAudioUnitScope_Input, 0, &input, sizeof(input));
768 if(sc != noErr){
769 WARN("Couldn't set callback: %x\n", (int)sc);
770 params->result = osstatus_to_hresult(sc);
771 goto end;
774 sc = AudioUnitInitialize(stream->unit);
775 if(sc != noErr){
776 WARN("Couldn't initialize: %x\n", (int)sc);
777 params->result = osstatus_to_hresult(sc);
778 goto end;
781 /* we play audio continuously because AudioOutputUnitStart sometimes takes
782 * a while to return */
783 sc = AudioOutputUnitStart(stream->unit);
784 if(sc != noErr){
785 WARN("Unit failed to start: %x\n", (int)sc);
786 params->result = osstatus_to_hresult(sc);
787 goto end;
790 size = stream->bufsize_frames * stream->fmt->nBlockAlign;
791 if(NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, zero_bits,
792 &size, MEM_COMMIT, PAGE_READWRITE)){
793 params->result = E_OUTOFMEMORY;
794 goto end;
796 silence_buffer(stream, stream->local_buffer, stream->bufsize_frames);
798 if(stream->flow == eCapture){
799 stream->cap_bufsize_frames = muldiv(params->duration, stream->dev_desc.mSampleRate, 10000000);
800 stream->cap_buffer = malloc(stream->cap_bufsize_frames * stream->fmt->nBlockAlign);
802 params->result = S_OK;
804 end:
805 if(FAILED(params->result)){
806 if(stream->converter) AudioConverterDispose(stream->converter);
807 if(stream->unit) AudioComponentInstanceDispose(stream->unit);
808 free(stream->fmt);
809 free(stream);
810 } else {
811 *params->channel_count = params->fmt->nChannels;
812 *params->stream = (stream_handle)(UINT_PTR)stream;
815 return STATUS_SUCCESS;
818 static NTSTATUS unix_release_stream( void *args )
820 struct release_stream_params *params = args;
821 struct coreaudio_stream *stream = handle_get_stream(params->stream);
822 SIZE_T size;
824 if(params->timer_thread){
825 stream->please_quit = TRUE;
826 NtWaitForSingleObject(params->timer_thread, FALSE, NULL);
827 NtClose(params->timer_thread);
830 if(stream->unit){
831 AudioOutputUnitStop(stream->unit);
832 AudioComponentInstanceDispose(stream->unit);
835 if(stream->converter) AudioConverterDispose(stream->converter);
836 free(stream->resamp_buffer);
837 free(stream->wrap_buffer);
838 free(stream->cap_buffer);
839 if(stream->local_buffer){
840 size = 0;
841 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer,
842 &size, MEM_RELEASE);
844 if(stream->tmp_buffer){
845 size = 0;
846 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer,
847 &size, MEM_RELEASE);
849 free(stream->fmt);
850 free(stream);
851 params->result = S_OK;
852 return STATUS_SUCCESS;
855 static UINT ca_channel_layout_to_channel_mask(const AudioChannelLayout *layout)
857 int i;
858 UINT mask = 0;
860 for (i = 0; i < layout->mNumberChannelDescriptions; ++i) {
861 switch (layout->mChannelDescriptions[i].mChannelLabel) {
862 default: FIXME("Unhandled channel 0x%x\n",
863 (unsigned int)layout->mChannelDescriptions[i].mChannelLabel); break;
864 case kAudioChannelLabel_Left: mask |= SPEAKER_FRONT_LEFT; break;
865 case kAudioChannelLabel_Mono:
866 case kAudioChannelLabel_Center: mask |= SPEAKER_FRONT_CENTER; break;
867 case kAudioChannelLabel_Right: mask |= SPEAKER_FRONT_RIGHT; break;
868 case kAudioChannelLabel_LeftSurround: mask |= SPEAKER_BACK_LEFT; break;
869 case kAudioChannelLabel_CenterSurround: mask |= SPEAKER_BACK_CENTER; break;
870 case kAudioChannelLabel_RightSurround: mask |= SPEAKER_BACK_RIGHT; break;
871 case kAudioChannelLabel_LFEScreen: mask |= SPEAKER_LOW_FREQUENCY; break;
872 case kAudioChannelLabel_LeftSurroundDirect: mask |= SPEAKER_SIDE_LEFT; break;
873 case kAudioChannelLabel_RightSurroundDirect: mask |= SPEAKER_SIDE_RIGHT; break;
874 case kAudioChannelLabel_TopCenterSurround: mask |= SPEAKER_TOP_CENTER; break;
875 case kAudioChannelLabel_VerticalHeightLeft: mask |= SPEAKER_TOP_FRONT_LEFT; break;
876 case kAudioChannelLabel_VerticalHeightCenter: mask |= SPEAKER_TOP_FRONT_CENTER; break;
877 case kAudioChannelLabel_VerticalHeightRight: mask |= SPEAKER_TOP_FRONT_RIGHT; break;
878 case kAudioChannelLabel_TopBackLeft: mask |= SPEAKER_TOP_BACK_LEFT; break;
879 case kAudioChannelLabel_TopBackCenter: mask |= SPEAKER_TOP_BACK_CENTER; break;
880 case kAudioChannelLabel_TopBackRight: mask |= SPEAKER_TOP_BACK_RIGHT; break;
881 case kAudioChannelLabel_LeftCenter: mask |= SPEAKER_FRONT_LEFT_OF_CENTER; break;
882 case kAudioChannelLabel_RightCenter: mask |= SPEAKER_FRONT_RIGHT_OF_CENTER; break;
886 return mask;
889 /* For most hardware on Windows, users must choose a configuration with an even
890 * number of channels (stereo, quad, 5.1, 7.1). Users can then disable
891 * channels, but those channels are still reported to applications from
892 * GetMixFormat! Some applications behave badly if given an odd number of
893 * channels (e.g. 2.1). Here, we find the nearest configuration that Windows
894 * would report for a given channel layout. */
895 static void convert_channel_layout(const AudioChannelLayout *ca_layout, WAVEFORMATEXTENSIBLE *fmt)
897 UINT ca_mask = ca_channel_layout_to_channel_mask(ca_layout);
899 TRACE("Got channel mask for CA: 0x%x\n", ca_mask);
901 if (ca_layout->mNumberChannelDescriptions == 1)
903 fmt->Format.nChannels = 1;
904 fmt->dwChannelMask = ca_mask;
905 return;
908 /* compare against known configurations and find smallest configuration
909 * which is a superset of the given speakers */
911 if (ca_layout->mNumberChannelDescriptions <= 2 &&
912 (ca_mask & ~KSAUDIO_SPEAKER_STEREO) == 0)
914 fmt->Format.nChannels = 2;
915 fmt->dwChannelMask = KSAUDIO_SPEAKER_STEREO;
916 return;
919 if (ca_layout->mNumberChannelDescriptions <= 4 &&
920 (ca_mask & ~KSAUDIO_SPEAKER_QUAD) == 0)
922 fmt->Format.nChannels = 4;
923 fmt->dwChannelMask = KSAUDIO_SPEAKER_QUAD;
924 return;
927 if (ca_layout->mNumberChannelDescriptions <= 4 &&
928 (ca_mask & ~KSAUDIO_SPEAKER_SURROUND) == 0)
930 fmt->Format.nChannels = 4;
931 fmt->dwChannelMask = KSAUDIO_SPEAKER_SURROUND;
932 return;
935 if (ca_layout->mNumberChannelDescriptions <= 6 &&
936 (ca_mask & ~KSAUDIO_SPEAKER_5POINT1) == 0)
938 fmt->Format.nChannels = 6;
939 fmt->dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
940 return;
943 if (ca_layout->mNumberChannelDescriptions <= 6 &&
944 (ca_mask & ~KSAUDIO_SPEAKER_5POINT1_SURROUND) == 0)
946 fmt->Format.nChannels = 6;
947 fmt->dwChannelMask = KSAUDIO_SPEAKER_5POINT1_SURROUND;
948 return;
951 if (ca_layout->mNumberChannelDescriptions <= 8 &&
952 (ca_mask & ~KSAUDIO_SPEAKER_7POINT1) == 0)
954 fmt->Format.nChannels = 8;
955 fmt->dwChannelMask = KSAUDIO_SPEAKER_7POINT1;
956 return;
959 if (ca_layout->mNumberChannelDescriptions <= 8 &&
960 (ca_mask & ~KSAUDIO_SPEAKER_7POINT1_SURROUND) == 0)
962 fmt->Format.nChannels = 8;
963 fmt->dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
964 return;
967 /* oddball format, report truthfully */
968 fmt->Format.nChannels = ca_layout->mNumberChannelDescriptions;
969 fmt->dwChannelMask = ca_mask;
972 static DWORD get_channel_mask(unsigned int channels)
974 switch(channels){
975 case 0:
976 return 0;
977 case 1:
978 return KSAUDIO_SPEAKER_MONO;
979 case 2:
980 return KSAUDIO_SPEAKER_STEREO;
981 case 3:
982 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
983 case 4:
984 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
985 case 5:
986 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
987 case 6:
988 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
989 case 7:
990 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
991 case 8:
992 return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
994 FIXME("Unknown speaker configuration: %u\n", channels);
995 return 0;
998 static NTSTATUS unix_get_mix_format(void *args)
1000 struct get_mix_format_params *params = args;
1001 AudioObjectPropertyAddress addr;
1002 AudioChannelLayout *layout;
1003 AudioBufferList *buffers;
1004 Float64 rate;
1005 UInt32 size;
1006 OSStatus sc;
1007 int i;
1008 const AudioDeviceID dev_id = dev_id_from_device(params->device);
1010 params->fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1012 addr.mScope = get_scope(params->flow);
1013 addr.mElement = 0;
1014 addr.mSelector = kAudioDevicePropertyPreferredChannelLayout;
1016 sc = AudioObjectGetPropertyDataSize(dev_id, &addr, 0, NULL, &size);
1017 if(sc == noErr){
1018 layout = malloc(size);
1019 sc = AudioObjectGetPropertyData(dev_id, &addr, 0, NULL, &size, layout);
1020 if(sc == noErr){
1021 TRACE("Got channel layout: {tag: 0x%x, bitmap: 0x%x, num_descs: %u}\n",
1022 (unsigned int)layout->mChannelLayoutTag, (unsigned int)layout->mChannelBitmap,
1023 (unsigned int)layout->mNumberChannelDescriptions);
1025 if(layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions){
1026 convert_channel_layout(layout, params->fmt);
1027 }else{
1028 WARN("Haven't implemented support for this layout tag: 0x%x, guessing at layout\n",
1029 (unsigned int)layout->mChannelLayoutTag);
1030 params->fmt->Format.nChannels = 0;
1032 }else{
1033 TRACE("Unable to get _PreferredChannelLayout property: %x, guessing at layout\n", (int)sc);
1034 params->fmt->Format.nChannels = 0;
1037 free(layout);
1038 }else{
1039 TRACE("Unable to get size for _PreferredChannelLayout property: %x, guessing at layout\n", (int)sc);
1040 params->fmt->Format.nChannels = 0;
1043 if(params->fmt->Format.nChannels == 0){
1044 addr.mScope = get_scope(params->flow);
1045 addr.mElement = 0;
1046 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
1048 sc = AudioObjectGetPropertyDataSize(dev_id, &addr, 0, NULL, &size);
1049 if(sc != noErr){
1050 WARN("Unable to get size for _StreamConfiguration property: %x\n", (int)sc);
1051 params->result = osstatus_to_hresult(sc);
1052 return STATUS_SUCCESS;
1055 buffers = malloc(size);
1056 if(!buffers){
1057 params->result = E_OUTOFMEMORY;
1058 return STATUS_SUCCESS;
1061 sc = AudioObjectGetPropertyData(dev_id, &addr, 0, NULL, &size, buffers);
1062 if(sc != noErr){
1063 free(buffers);
1064 WARN("Unable to get _StreamConfiguration property: %x\n", (int)sc);
1065 params->result = osstatus_to_hresult(sc);
1066 return STATUS_SUCCESS;
1069 for(i = 0; i < buffers->mNumberBuffers; ++i)
1070 params->fmt->Format.nChannels += buffers->mBuffers[i].mNumberChannels;
1072 free(buffers);
1074 params->fmt->dwChannelMask = get_channel_mask(params->fmt->Format.nChannels);
1077 addr.mSelector = kAudioDevicePropertyNominalSampleRate;
1078 size = sizeof(Float64);
1079 sc = AudioObjectGetPropertyData(dev_id, &addr, 0, NULL, &size, &rate);
1080 if(sc != noErr){
1081 WARN("Unable to get _NominalSampleRate property: %x\n", (int)sc);
1082 params->result = osstatus_to_hresult(sc);
1083 return STATUS_SUCCESS;
1085 params->fmt->Format.nSamplesPerSec = rate;
1087 params->fmt->Format.wBitsPerSample = 32;
1088 params->fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1090 params->fmt->Format.nBlockAlign = (params->fmt->Format.wBitsPerSample *
1091 params->fmt->Format.nChannels) / 8;
1092 params->fmt->Format.nAvgBytesPerSec = params->fmt->Format.nSamplesPerSec *
1093 params->fmt->Format.nBlockAlign;
1095 params->fmt->Samples.wValidBitsPerSample = params->fmt->Format.wBitsPerSample;
1096 params->fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1097 params->result = S_OK;
1098 return STATUS_SUCCESS;
1101 static NTSTATUS unix_is_format_supported(void *args)
1103 struct is_format_supported_params *params = args;
1104 const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)params->fmt_in;
1105 AudioStreamBasicDescription dev_desc;
1106 AudioConverterRef converter;
1107 AudioComponentInstance unit;
1108 const AudioDeviceID dev_id = dev_id_from_device(params->device);
1110 params->result = S_OK;
1112 if(!params->fmt_in || (params->share == AUDCLNT_SHAREMODE_SHARED && !params->fmt_out))
1113 params->result = E_POINTER;
1114 else if(params->share != AUDCLNT_SHAREMODE_SHARED && params->share != AUDCLNT_SHAREMODE_EXCLUSIVE)
1115 params->result = E_INVALIDARG;
1116 else if(params->fmt_in->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
1117 if(params->fmt_in->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1118 params->result = E_INVALIDARG;
1119 else if(params->fmt_in->nAvgBytesPerSec == 0 || params->fmt_in->nBlockAlign == 0 ||
1120 fmtex->Samples.wValidBitsPerSample > params->fmt_in->wBitsPerSample)
1121 params->result = E_INVALIDARG;
1122 else if(fmtex->Samples.wValidBitsPerSample < params->fmt_in->wBitsPerSample)
1123 goto unsupported;
1124 else if(params->share == AUDCLNT_SHAREMODE_EXCLUSIVE &&
1125 (fmtex->dwChannelMask == 0 || fmtex->dwChannelMask & SPEAKER_RESERVED))
1126 goto unsupported;
1128 if(FAILED(params->result)) return STATUS_SUCCESS;
1130 if(params->fmt_in->nBlockAlign != params->fmt_in->nChannels * params->fmt_in->wBitsPerSample / 8 ||
1131 params->fmt_in->nAvgBytesPerSec != params->fmt_in->nBlockAlign * params->fmt_in->nSamplesPerSec)
1132 goto unsupported;
1134 if(params->fmt_in->nChannels == 0){
1135 params->result = AUDCLNT_E_UNSUPPORTED_FORMAT;
1136 return STATUS_SUCCESS;
1138 unit = get_audiounit(params->flow, dev_id);
1140 converter = NULL;
1141 params->result = ca_setup_audiounit(params->flow, unit, params->fmt_in, &dev_desc, &converter);
1142 AudioComponentInstanceDispose(unit);
1143 if(FAILED(params->result)) goto unsupported;
1144 if(converter) AudioConverterDispose(converter);
1146 params->result = S_OK;
1147 return STATUS_SUCCESS;
1149 unsupported:
1150 if(params->fmt_out){
1151 struct get_mix_format_params get_mix_params =
1153 .device = params->device,
1154 .flow = params->flow,
1155 .fmt = params->fmt_out,
1158 unix_get_mix_format(&get_mix_params);
1159 params->result = get_mix_params.result;
1160 if(SUCCEEDED(params->result)) params->result = S_FALSE;
1162 else params->result = AUDCLNT_E_UNSUPPORTED_FORMAT;
1163 return STATUS_SUCCESS;
1166 static NTSTATUS unix_get_device_period(void *args)
1168 struct get_device_period_params *params = args;
1170 if (params->def_period)
1171 *params->def_period = def_period;
1172 if (params->min_period)
1173 *params->min_period = min_period;
1175 params->result = S_OK;
1177 return STATUS_SUCCESS;
1180 static UINT buf_ptr_diff(UINT left, UINT right, UINT bufsize)
1182 if(left <= right)
1183 return right - left;
1184 return bufsize - (left - right);
1187 /* place data from cap_buffer into provided AudioBufferList */
1188 static OSStatus feed_cb(AudioConverterRef converter, UInt32 *nframes, AudioBufferList *data,
1189 AudioStreamPacketDescription **packets, void *user)
1191 struct coreaudio_stream *stream = user;
1193 *nframes = min(*nframes, stream->cap_held_frames);
1194 if(!*nframes){
1195 data->mBuffers[0].mData = NULL;
1196 data->mBuffers[0].mDataByteSize = 0;
1197 data->mBuffers[0].mNumberChannels = stream->fmt->nChannels;
1198 return noErr;
1201 data->mBuffers[0].mDataByteSize = *nframes * stream->fmt->nBlockAlign;
1202 data->mBuffers[0].mNumberChannels = stream->fmt->nChannels;
1204 if(stream->cap_offs_frames + *nframes > stream->cap_bufsize_frames){
1205 UINT32 chunk_frames = stream->cap_bufsize_frames - stream->cap_offs_frames;
1207 if(stream->wrap_bufsize_frames < *nframes){
1208 free(stream->wrap_buffer);
1209 stream->wrap_buffer = malloc(data->mBuffers[0].mDataByteSize);
1210 stream->wrap_bufsize_frames = *nframes;
1213 memcpy(stream->wrap_buffer, stream->cap_buffer + stream->cap_offs_frames * stream->fmt->nBlockAlign,
1214 chunk_frames * stream->fmt->nBlockAlign);
1215 memcpy(stream->wrap_buffer + chunk_frames * stream->fmt->nBlockAlign, stream->cap_buffer,
1216 (*nframes - chunk_frames) * stream->fmt->nBlockAlign);
1218 data->mBuffers[0].mData = stream->wrap_buffer;
1219 }else
1220 data->mBuffers[0].mData = stream->cap_buffer + stream->cap_offs_frames * stream->fmt->nBlockAlign;
1222 stream->cap_offs_frames += *nframes;
1223 stream->cap_offs_frames %= stream->cap_bufsize_frames;
1224 stream->cap_held_frames -= *nframes;
1226 if(packets)
1227 *packets = NULL;
1229 return noErr;
1232 static void capture_resample(struct coreaudio_stream *stream)
1234 UINT32 resamp_period_frames = muldiv(stream->period_frames, stream->dev_desc.mSampleRate,
1235 stream->fmt->nSamplesPerSec);
1236 OSStatus sc;
1238 /* the resampling process often needs more source frames than we'd
1239 * guess from a straight conversion using the sample rate ratio. so
1240 * only convert if we have extra source data. */
1241 while(stream->cap_held_frames > resamp_period_frames * 2){
1242 AudioBufferList converted_list;
1243 UInt32 wanted_frames = stream->period_frames;
1245 converted_list.mNumberBuffers = 1;
1246 converted_list.mBuffers[0].mNumberChannels = stream->fmt->nChannels;
1247 converted_list.mBuffers[0].mDataByteSize = wanted_frames * stream->fmt->nBlockAlign;
1249 if(stream->resamp_bufsize_frames < wanted_frames){
1250 free(stream->resamp_buffer);
1251 stream->resamp_buffer = malloc(converted_list.mBuffers[0].mDataByteSize);
1252 stream->resamp_bufsize_frames = wanted_frames;
1255 converted_list.mBuffers[0].mData = stream->resamp_buffer;
1257 sc = AudioConverterFillComplexBuffer(stream->converter, feed_cb,
1258 stream, &wanted_frames, &converted_list, NULL);
1259 if(sc != noErr){
1260 WARN("AudioConverterFillComplexBuffer failed: %x\n", (int)sc);
1261 break;
1264 ca_wrap_buffer(stream->local_buffer,
1265 stream->wri_offs_frames * stream->fmt->nBlockAlign,
1266 stream->bufsize_frames * stream->fmt->nBlockAlign,
1267 stream->resamp_buffer, wanted_frames * stream->fmt->nBlockAlign);
1269 stream->wri_offs_frames += wanted_frames;
1270 stream->wri_offs_frames %= stream->bufsize_frames;
1271 if(stream->held_frames + wanted_frames > stream->bufsize_frames){
1272 stream->lcl_offs_frames += buf_ptr_diff(stream->lcl_offs_frames, stream->wri_offs_frames,
1273 stream->bufsize_frames);
1274 stream->held_frames = stream->bufsize_frames;
1275 }else
1276 stream->held_frames += wanted_frames;
1280 static NTSTATUS unix_get_buffer_size(void *args)
1282 struct get_buffer_size_params *params = args;
1283 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1285 os_unfair_lock_lock(&stream->lock);
1286 *params->frames = stream->bufsize_frames;
1287 os_unfair_lock_unlock(&stream->lock);
1288 params->result = S_OK;
1289 return STATUS_SUCCESS;
1292 static HRESULT ca_get_max_stream_latency(struct coreaudio_stream *stream, UInt32 *max)
1294 AudioObjectPropertyAddress addr;
1295 AudioStreamID *ids;
1296 UInt32 size;
1297 OSStatus sc;
1298 int nstreams, i;
1300 addr.mScope = get_scope(stream->flow);
1301 addr.mElement = 0;
1302 addr.mSelector = kAudioDevicePropertyStreams;
1304 sc = AudioObjectGetPropertyDataSize(stream->dev_id, &addr, 0, NULL, &size);
1305 if(sc != noErr){
1306 WARN("Unable to get size for _Streams property: %x\n", (int)sc);
1307 return osstatus_to_hresult(sc);
1310 ids = malloc(size);
1311 if(!ids)
1312 return E_OUTOFMEMORY;
1314 sc = AudioObjectGetPropertyData(stream->dev_id, &addr, 0, NULL, &size, ids);
1315 if(sc != noErr){
1316 WARN("Unable to get _Streams property: %x\n", (int)sc);
1317 free(ids);
1318 return osstatus_to_hresult(sc);
1321 nstreams = size / sizeof(AudioStreamID);
1322 *max = 0;
1324 addr.mSelector = kAudioStreamPropertyLatency;
1325 for(i = 0; i < nstreams; ++i){
1326 UInt32 latency;
1328 size = sizeof(latency);
1329 sc = AudioObjectGetPropertyData(ids[i], &addr, 0, NULL, &size, &latency);
1330 if(sc != noErr){
1331 WARN("Unable to get _Latency property: %x\n", (int)sc);
1332 continue;
1335 if(latency > *max)
1336 *max = latency;
1339 free(ids);
1341 return S_OK;
1344 static NTSTATUS unix_get_latency(void *args)
1346 struct get_latency_params *params = args;
1347 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1348 UInt32 latency, stream_latency, size;
1349 AudioObjectPropertyAddress addr;
1350 OSStatus sc;
1352 os_unfair_lock_lock(&stream->lock);
1354 addr.mScope = get_scope(stream->flow);
1355 addr.mSelector = kAudioDevicePropertyLatency;
1356 addr.mElement = 0;
1358 size = sizeof(latency);
1359 sc = AudioObjectGetPropertyData(stream->dev_id, &addr, 0, NULL, &size, &latency);
1360 if(sc != noErr){
1361 WARN("Couldn't get _Latency property: %x\n", (int)sc);
1362 os_unfair_lock_unlock(&stream->lock);
1363 params->result = osstatus_to_hresult(sc);
1364 return STATUS_SUCCESS;
1367 params->result = ca_get_max_stream_latency(stream, &stream_latency);
1368 if(FAILED(params->result)){
1369 os_unfair_lock_unlock(&stream->lock);
1370 return STATUS_SUCCESS;
1373 latency += stream_latency;
1374 /* pretend we process audio in Period chunks, so max latency includes
1375 * the period time */
1376 *params->latency = muldiv(latency, 10000000, stream->fmt->nSamplesPerSec) + stream->period;
1378 os_unfair_lock_unlock(&stream->lock);
1379 params->result = S_OK;
1380 return STATUS_SUCCESS;
1383 static UINT32 get_current_padding_nolock(struct coreaudio_stream *stream)
1385 if(stream->flow == eCapture) capture_resample(stream);
1386 return stream->held_frames;
1389 static NTSTATUS unix_get_current_padding(void *args)
1391 struct get_current_padding_params *params = args;
1392 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1394 os_unfair_lock_lock(&stream->lock);
1395 *params->padding = get_current_padding_nolock(stream);
1396 os_unfair_lock_unlock(&stream->lock);
1397 params->result = S_OK;
1398 return STATUS_SUCCESS;
1401 static NTSTATUS unix_start(void *args)
1403 struct start_params *params = args;
1404 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1406 os_unfair_lock_lock(&stream->lock);
1408 if((stream->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !stream->event)
1409 params->result = AUDCLNT_E_EVENTHANDLE_NOT_SET;
1410 else if(stream->playing)
1411 params->result = AUDCLNT_E_NOT_STOPPED;
1412 else{
1413 stream->playing = TRUE;
1414 params->result = S_OK;
1417 os_unfair_lock_unlock(&stream->lock);
1419 return STATUS_SUCCESS;
1422 static NTSTATUS unix_stop(void *args)
1424 struct stop_params *params = args;
1425 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1427 os_unfair_lock_lock(&stream->lock);
1429 if(!stream->playing)
1430 params->result = S_FALSE;
1431 else{
1432 stream->playing = FALSE;
1433 params->result = S_OK;
1436 os_unfair_lock_unlock(&stream->lock);
1438 return STATUS_SUCCESS;
1441 static NTSTATUS unix_reset(void *args)
1443 struct reset_params *params = args;
1444 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1446 os_unfair_lock_lock(&stream->lock);
1448 if(stream->playing)
1449 params->result = AUDCLNT_E_NOT_STOPPED;
1450 else if(stream->getbuf_last)
1451 params->result = AUDCLNT_E_BUFFER_OPERATION_PENDING;
1452 else{
1453 if(stream->flow == eRender)
1454 stream->written_frames = 0;
1455 else
1456 stream->written_frames += stream->held_frames;
1457 stream->held_frames = 0;
1458 stream->lcl_offs_frames = 0;
1459 stream->wri_offs_frames = 0;
1460 stream->cap_offs_frames = 0;
1461 stream->cap_held_frames = 0;
1462 params->result = S_OK;
1465 os_unfair_lock_unlock(&stream->lock);
1466 return STATUS_SUCCESS;
1469 static NTSTATUS unix_timer_loop(void *args)
1471 struct timer_loop_params *params = args;
1472 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1473 LARGE_INTEGER delay, next, last;
1474 int adjust;
1476 delay.QuadPart = -stream->period;
1477 NtQueryPerformanceCounter(&last, NULL);
1478 next.QuadPart = last.QuadPart + stream->period;
1480 while(!stream->please_quit){
1481 NtSetEvent(stream->event, NULL);
1482 NtDelayExecution(FALSE, &delay);
1483 NtQueryPerformanceCounter(&last, NULL);
1485 adjust = next.QuadPart - last.QuadPart;
1486 if(adjust > stream->period / 2)
1487 adjust = stream->period / 2;
1488 else if(adjust < -stream->period / 2)
1489 adjust = -stream->period / 2;
1491 delay.QuadPart = -(stream->period + adjust);
1492 next.QuadPart += stream->period;
1495 return STATUS_SUCCESS;
1498 static NTSTATUS unix_get_render_buffer(void *args)
1500 struct get_render_buffer_params *params = args;
1501 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1502 SIZE_T size;
1503 UINT32 pad;
1505 os_unfair_lock_lock(&stream->lock);
1507 pad = get_current_padding_nolock(stream);
1509 if(stream->getbuf_last){
1510 params->result = AUDCLNT_E_OUT_OF_ORDER;
1511 goto end;
1513 if(!params->frames){
1514 params->result = S_OK;
1515 goto end;
1517 if(pad + params->frames > stream->bufsize_frames){
1518 params->result = AUDCLNT_E_BUFFER_TOO_LARGE;
1519 goto end;
1522 if(stream->wri_offs_frames + params->frames > stream->bufsize_frames){
1523 if(stream->tmp_buffer_frames < params->frames){
1524 if(stream->tmp_buffer){
1525 size = 0;
1526 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer,
1527 &size, MEM_RELEASE);
1528 stream->tmp_buffer = NULL;
1530 size = params->frames * stream->fmt->nBlockAlign;
1531 if(NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, zero_bits,
1532 &size, MEM_COMMIT, PAGE_READWRITE)){
1533 stream->tmp_buffer_frames = 0;
1534 params->result = E_OUTOFMEMORY;
1535 goto end;
1537 stream->tmp_buffer_frames = params->frames;
1539 *params->data = stream->tmp_buffer;
1540 stream->getbuf_last = -params->frames;
1541 }else{
1542 *params->data = stream->local_buffer + stream->wri_offs_frames * stream->fmt->nBlockAlign;
1543 stream->getbuf_last = params->frames;
1546 silence_buffer(stream, *params->data, params->frames);
1547 params->result = S_OK;
1549 end:
1550 os_unfair_lock_unlock(&stream->lock);
1552 return STATUS_SUCCESS;
1555 static NTSTATUS unix_release_render_buffer(void *args)
1557 struct release_render_buffer_params *params = args;
1558 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1559 BYTE *buffer;
1561 os_unfair_lock_lock(&stream->lock);
1563 if(!params->written_frames){
1564 stream->getbuf_last = 0;
1565 params->result = S_OK;
1566 }else if(!stream->getbuf_last)
1567 params->result = AUDCLNT_E_OUT_OF_ORDER;
1568 else if(params->written_frames > (stream->getbuf_last >= 0 ? stream->getbuf_last : -stream->getbuf_last))
1569 params->result = AUDCLNT_E_INVALID_SIZE;
1570 else{
1571 if(stream->getbuf_last >= 0)
1572 buffer = stream->local_buffer + stream->wri_offs_frames * stream->fmt->nBlockAlign;
1573 else
1574 buffer = stream->tmp_buffer;
1576 if(params->flags & AUDCLNT_BUFFERFLAGS_SILENT)
1577 silence_buffer(stream, buffer, params->written_frames);
1579 if(stream->getbuf_last < 0)
1580 ca_wrap_buffer(stream->local_buffer,
1581 stream->wri_offs_frames * stream->fmt->nBlockAlign,
1582 stream->bufsize_frames * stream->fmt->nBlockAlign,
1583 buffer, params->written_frames * stream->fmt->nBlockAlign);
1585 stream->wri_offs_frames += params->written_frames;
1586 stream->wri_offs_frames %= stream->bufsize_frames;
1587 stream->held_frames += params->written_frames;
1588 stream->written_frames += params->written_frames;
1589 stream->getbuf_last = 0;
1591 params->result = S_OK;
1594 os_unfair_lock_unlock(&stream->lock);
1596 return STATUS_SUCCESS;
1599 static NTSTATUS unix_get_capture_buffer(void *args)
1601 struct get_capture_buffer_params *params = args;
1602 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1603 UINT32 chunk_bytes, chunk_frames;
1604 LARGE_INTEGER stamp, freq;
1605 SIZE_T size;
1607 os_unfair_lock_lock(&stream->lock);
1609 if(stream->getbuf_last){
1610 params->result = AUDCLNT_E_OUT_OF_ORDER;
1611 goto end;
1614 capture_resample(stream);
1616 *params->frames = 0;
1618 if(stream->held_frames < stream->period_frames){
1619 params->result = AUDCLNT_S_BUFFER_EMPTY;
1620 goto end;
1623 *params->flags = 0;
1624 chunk_frames = stream->bufsize_frames - stream->lcl_offs_frames;
1625 if(chunk_frames < stream->period_frames){
1626 chunk_bytes = chunk_frames * stream->fmt->nBlockAlign;
1627 if(!stream->tmp_buffer){
1628 size = stream->period_frames * stream->fmt->nBlockAlign;
1629 NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, zero_bits,
1630 &size, MEM_COMMIT, PAGE_READWRITE);
1632 *params->data = stream->tmp_buffer;
1633 memcpy(*params->data, stream->local_buffer + stream->lcl_offs_frames * stream->fmt->nBlockAlign,
1634 chunk_bytes);
1635 memcpy(*params->data + chunk_bytes, stream->local_buffer,
1636 stream->period_frames * stream->fmt->nBlockAlign - chunk_bytes);
1637 }else
1638 *params->data = stream->local_buffer + stream->lcl_offs_frames * stream->fmt->nBlockAlign;
1640 stream->getbuf_last = *params->frames = stream->period_frames;
1642 if(params->devpos)
1643 *params->devpos = stream->written_frames;
1644 if(params->qpcpos){ /* fixme: qpc of recording time */
1645 NtQueryPerformanceCounter(&stamp, &freq);
1646 *params->qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1648 params->result = S_OK;
1650 end:
1651 os_unfair_lock_unlock(&stream->lock);
1652 return STATUS_SUCCESS;
1655 static NTSTATUS unix_release_capture_buffer(void *args)
1657 struct release_capture_buffer_params *params = args;
1658 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1660 os_unfair_lock_lock(&stream->lock);
1662 if(!params->done){
1663 stream->getbuf_last = 0;
1664 params->result = S_OK;
1665 }else if(!stream->getbuf_last)
1666 params->result = AUDCLNT_E_OUT_OF_ORDER;
1667 else if(stream->getbuf_last != params->done)
1668 params->result = AUDCLNT_E_INVALID_SIZE;
1669 else{
1670 stream->written_frames += params->done;
1671 stream->held_frames -= params->done;
1672 stream->lcl_offs_frames += params->done;
1673 stream->lcl_offs_frames %= stream->bufsize_frames;
1674 stream->getbuf_last = 0;
1675 params->result = S_OK;
1678 os_unfair_lock_unlock(&stream->lock);
1680 return STATUS_SUCCESS;
1683 static NTSTATUS unix_get_next_packet_size(void *args)
1685 struct get_next_packet_size_params *params = args;
1686 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1688 os_unfair_lock_lock(&stream->lock);
1690 capture_resample(stream);
1692 if(stream->held_frames >= stream->period_frames)
1693 *params->frames = stream->period_frames;
1694 else
1695 *params->frames = 0;
1697 os_unfair_lock_unlock(&stream->lock);
1699 params->result = S_OK;
1700 return STATUS_SUCCESS;
1703 static NTSTATUS unix_get_position(void *args)
1705 struct get_position_params *params = args;
1706 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1707 LARGE_INTEGER stamp, freq;
1709 if (params->device) {
1710 FIXME("Device position reporting not implemented\n");
1711 params->result = E_NOTIMPL;
1712 return STATUS_SUCCESS;
1715 os_unfair_lock_lock(&stream->lock);
1717 *params->pos = stream->written_frames - stream->held_frames;
1719 if(stream->share == AUDCLNT_SHAREMODE_SHARED)
1720 *params->pos *= stream->fmt->nBlockAlign;
1722 if(params->qpctime){
1723 NtQueryPerformanceCounter(&stamp, &freq);
1724 *params->qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1727 os_unfair_lock_unlock(&stream->lock);
1729 params->result = S_OK;
1730 return STATUS_SUCCESS;
1733 static NTSTATUS unix_get_frequency(void *args)
1735 struct get_frequency_params *params = args;
1736 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1738 if(stream->share == AUDCLNT_SHAREMODE_SHARED)
1739 *params->freq = (UINT64)stream->fmt->nSamplesPerSec * stream->fmt->nBlockAlign;
1740 else
1741 *params->freq = stream->fmt->nSamplesPerSec;
1743 params->result = S_OK;
1744 return STATUS_SUCCESS;
1747 static NTSTATUS unix_is_started(void *args)
1749 struct is_started_params *params = args;
1750 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1752 if(stream->playing)
1753 params->result = S_OK;
1754 else
1755 params->result = S_FALSE;
1757 return STATUS_SUCCESS;
1760 static NTSTATUS unix_get_prop_value(void *args)
1762 struct get_prop_value_params *params = args;
1764 params->result = E_NOTIMPL;
1766 return STATUS_SUCCESS;
1769 static NTSTATUS unix_set_volumes(void *args)
1771 struct set_volumes_params *params = args;
1772 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1773 Float32 level = params->master_volume;
1774 OSStatus sc;
1775 UINT32 i;
1776 AudioObjectPropertyAddress prop_addr = {
1777 kAudioDevicePropertyVolumeScalar,
1778 kAudioObjectPropertyScopeGlobal,
1779 kAudioObjectPropertyElementMain
1782 sc = AudioObjectSetPropertyData(stream->dev_id, &prop_addr, 0, NULL, sizeof(float), &level);
1783 if (sc == noErr)
1784 level = 1.0f;
1785 else
1786 WARN("Couldn't set master volume, applying it directly to the channels: %x\n", (int)sc);
1788 for (i = 1; i <= stream->fmt->nChannels; ++i) {
1789 const float vol = level * params->session_volumes[i - 1] * params->volumes[i - 1];
1791 prop_addr.mElement = i;
1793 sc = AudioObjectSetPropertyData(stream->dev_id, &prop_addr, 0, NULL, sizeof(float), &vol);
1794 if (sc != noErr) {
1795 WARN("Couldn't set channel #%u volume: %x\n", i, (int)sc);
1799 return STATUS_SUCCESS;
1802 static NTSTATUS unix_set_event_handle(void *args)
1804 struct set_event_handle_params *params = args;
1805 struct coreaudio_stream *stream = handle_get_stream(params->stream);
1806 HRESULT hr = S_OK;
1808 os_unfair_lock_lock(&stream->lock);
1809 if(!stream->unit)
1810 hr = AUDCLNT_E_DEVICE_INVALIDATED;
1811 else if(!(stream->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK))
1812 hr = AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1813 else if(stream->event)
1814 hr = HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
1815 else
1816 stream->event = params->event;
1817 os_unfair_lock_unlock(&stream->lock);
1819 params->result = hr;
1820 return STATUS_SUCCESS;
1823 const unixlib_entry_t __wine_unix_call_funcs[] =
1825 unix_process_attach,
1826 unix_not_implemented,
1827 unix_main_loop,
1828 unix_get_endpoint_ids,
1829 unix_create_stream,
1830 unix_release_stream,
1831 unix_start,
1832 unix_stop,
1833 unix_reset,
1834 unix_timer_loop,
1835 unix_get_render_buffer,
1836 unix_release_render_buffer,
1837 unix_get_capture_buffer,
1838 unix_release_capture_buffer,
1839 unix_is_format_supported,
1840 unix_not_implemented,
1841 unix_get_mix_format,
1842 unix_get_device_period,
1843 unix_get_buffer_size,
1844 unix_get_latency,
1845 unix_get_current_padding,
1846 unix_get_next_packet_size,
1847 unix_get_frequency,
1848 unix_get_position,
1849 unix_set_volumes,
1850 unix_set_event_handle,
1851 unix_not_implemented,
1852 unix_is_started,
1853 unix_get_prop_value,
1854 unix_midi_init,
1855 unix_midi_release,
1856 unix_midi_out_message,
1857 unix_midi_in_message,
1858 unix_midi_notify_wait,
1859 unix_not_implemented,
1862 C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs) == funcs_count);
1864 #ifdef _WIN64
1866 typedef UINT PTR32;
1868 static NTSTATUS unix_wow64_main_loop(void *args)
1870 struct
1872 PTR32 event;
1873 } *params32 = args;
1874 struct main_loop_params params =
1876 .event = ULongToHandle(params32->event)
1878 return unix_main_loop(&params);
1881 static NTSTATUS unix_wow64_get_endpoint_ids(void *args)
1883 struct
1885 EDataFlow flow;
1886 PTR32 endpoints;
1887 unsigned int size;
1888 HRESULT result;
1889 unsigned int num;
1890 unsigned int default_idx;
1891 } *params32 = args;
1892 struct get_endpoint_ids_params params =
1894 .flow = params32->flow,
1895 .endpoints = ULongToPtr(params32->endpoints),
1896 .size = params32->size
1898 unix_get_endpoint_ids(&params);
1899 params32->size = params.size;
1900 params32->result = params.result;
1901 params32->num = params.num;
1902 params32->default_idx = params.default_idx;
1903 return STATUS_SUCCESS;
1906 static NTSTATUS unix_wow64_create_stream(void *args)
1908 struct
1910 PTR32 name;
1911 PTR32 device;
1912 EDataFlow flow;
1913 AUDCLNT_SHAREMODE share;
1914 DWORD flags;
1915 REFERENCE_TIME duration;
1916 REFERENCE_TIME period;
1917 PTR32 fmt;
1918 HRESULT result;
1919 PTR32 channel_count;
1920 PTR32 stream;
1921 } *params32 = args;
1922 struct create_stream_params params =
1924 .name = ULongToPtr(params32->name),
1925 .device = ULongToPtr(params32->device),
1926 .flow = params32->flow,
1927 .share = params32->share,
1928 .flags = params32->flags,
1929 .duration = params32->duration,
1930 .period = params32->period,
1931 .fmt = ULongToPtr(params32->fmt),
1932 .channel_count = ULongToPtr(params32->channel_count),
1933 .stream = ULongToPtr(params32->stream)
1935 unix_create_stream(&params);
1936 params32->result = params.result;
1937 return STATUS_SUCCESS;
1940 static NTSTATUS unix_wow64_release_stream(void *args)
1942 struct
1944 stream_handle stream;
1945 PTR32 timer_thread;
1946 HRESULT result;
1947 } *params32 = args;
1948 struct release_stream_params params =
1950 .stream = params32->stream,
1951 .timer_thread = ULongToHandle(params32->timer_thread)
1953 unix_release_stream(&params);
1954 params32->result = params.result;
1955 return STATUS_SUCCESS;
1958 static NTSTATUS unix_wow64_get_render_buffer(void *args)
1960 struct
1962 stream_handle stream;
1963 UINT32 frames;
1964 HRESULT result;
1965 PTR32 data;
1966 } *params32 = args;
1967 BYTE *data = NULL;
1968 struct get_render_buffer_params params =
1970 .stream = params32->stream,
1971 .frames = params32->frames,
1972 .data = &data
1974 unix_get_render_buffer(&params);
1975 params32->result = params.result;
1976 *(unsigned int *)ULongToPtr(params32->data) = PtrToUlong(data);
1977 return STATUS_SUCCESS;
1980 static NTSTATUS unix_wow64_get_capture_buffer(void *args)
1982 struct
1984 stream_handle stream;
1985 HRESULT result;
1986 PTR32 data;
1987 PTR32 frames;
1988 PTR32 flags;
1989 PTR32 devpos;
1990 PTR32 qpcpos;
1991 } *params32 = args;
1992 BYTE *data = NULL;
1993 struct get_capture_buffer_params params =
1995 .stream = params32->stream,
1996 .data = &data,
1997 .frames = ULongToPtr(params32->frames),
1998 .flags = ULongToPtr(params32->flags),
1999 .devpos = ULongToPtr(params32->devpos),
2000 .qpcpos = ULongToPtr(params32->qpcpos)
2002 unix_get_capture_buffer(&params);
2003 params32->result = params.result;
2004 *(unsigned int *)ULongToPtr(params32->data) = PtrToUlong(data);
2005 return STATUS_SUCCESS;
2008 static NTSTATUS unix_wow64_is_format_supported(void *args)
2010 struct
2012 PTR32 device;
2013 EDataFlow flow;
2014 AUDCLNT_SHAREMODE share;
2015 PTR32 fmt_in;
2016 PTR32 fmt_out;
2017 HRESULT result;
2018 } *params32 = args;
2019 struct is_format_supported_params params =
2021 .device = ULongToPtr(params32->device),
2022 .flow = params32->flow,
2023 .share = params32->share,
2024 .fmt_in = ULongToPtr(params32->fmt_in),
2025 .fmt_out = ULongToPtr(params32->fmt_out)
2027 unix_is_format_supported(&params);
2028 params32->result = params.result;
2029 return STATUS_SUCCESS;
2032 static NTSTATUS unix_wow64_get_mix_format(void *args)
2034 struct
2036 PTR32 device;
2037 EDataFlow flow;
2038 PTR32 fmt;
2039 HRESULT result;
2040 } *params32 = args;
2041 struct get_mix_format_params params =
2043 .device = ULongToPtr(params32->device),
2044 .flow = params32->flow,
2045 .fmt = ULongToPtr(params32->fmt)
2047 unix_get_mix_format(&params);
2048 params32->result = params.result;
2049 return STATUS_SUCCESS;
2052 static NTSTATUS unix_wow64_get_device_period(void *args)
2054 struct
2056 PTR32 device;
2057 EDataFlow flow;
2058 HRESULT result;
2059 PTR32 def_period;
2060 PTR32 min_period;
2061 } *params32 = args;
2062 struct get_device_period_params params =
2064 .device = ULongToPtr(params32->device),
2065 .flow = params32->flow,
2066 .def_period = ULongToPtr(params32->def_period),
2067 .min_period = ULongToPtr(params32->min_period),
2069 unix_get_device_period(&params);
2070 params32->result = params.result;
2071 return STATUS_SUCCESS;
2074 static NTSTATUS unix_wow64_get_buffer_size(void *args)
2076 struct
2078 stream_handle stream;
2079 HRESULT result;
2080 PTR32 frames;
2081 } *params32 = args;
2082 struct get_buffer_size_params params =
2084 .stream = params32->stream,
2085 .frames = ULongToPtr(params32->frames)
2087 unix_get_buffer_size(&params);
2088 params32->result = params.result;
2089 return STATUS_SUCCESS;
2092 static NTSTATUS unix_wow64_get_latency(void *args)
2094 struct
2096 stream_handle stream;
2097 HRESULT result;
2098 PTR32 latency;
2099 } *params32 = args;
2100 struct get_latency_params params =
2102 .stream = params32->stream,
2103 .latency = ULongToPtr(params32->latency)
2105 unix_get_latency(&params);
2106 params32->result = params.result;
2107 return STATUS_SUCCESS;
2110 static NTSTATUS unix_wow64_get_current_padding(void *args)
2112 struct
2114 stream_handle stream;
2115 HRESULT result;
2116 PTR32 padding;
2117 } *params32 = args;
2118 struct get_current_padding_params params =
2120 .stream = params32->stream,
2121 .padding = ULongToPtr(params32->padding)
2123 unix_get_current_padding(&params);
2124 params32->result = params.result;
2125 return STATUS_SUCCESS;
2128 static NTSTATUS unix_wow64_get_next_packet_size(void *args)
2130 struct
2132 stream_handle stream;
2133 HRESULT result;
2134 PTR32 frames;
2135 } *params32 = args;
2136 struct get_next_packet_size_params params =
2138 .stream = params32->stream,
2139 .frames = ULongToPtr(params32->frames)
2141 unix_get_next_packet_size(&params);
2142 params32->result = params.result;
2143 return STATUS_SUCCESS;
2146 static NTSTATUS unix_wow64_get_position(void *args)
2148 struct
2150 stream_handle stream;
2151 BOOL device;
2152 HRESULT result;
2153 PTR32 pos;
2154 PTR32 qpctime;
2155 } *params32 = args;
2156 struct get_position_params params =
2158 .stream = params32->stream,
2159 .device = params32->device,
2160 .pos = ULongToPtr(params32->pos),
2161 .qpctime = ULongToPtr(params32->qpctime)
2163 unix_get_position(&params);
2164 params32->result = params.result;
2165 return STATUS_SUCCESS;
2168 static NTSTATUS unix_wow64_get_frequency(void *args)
2170 struct
2172 stream_handle stream;
2173 HRESULT result;
2174 PTR32 freq;
2175 } *params32 = args;
2176 struct get_frequency_params params =
2178 .stream = params32->stream,
2179 .freq = ULongToPtr(params32->freq)
2181 unix_get_frequency(&params);
2182 params32->result = params.result;
2183 return STATUS_SUCCESS;
2186 static NTSTATUS unix_wow64_set_volumes(void *args)
2188 struct
2190 stream_handle stream;
2191 float master_volume;
2192 PTR32 volumes;
2193 PTR32 session_volumes;
2194 } *params32 = args;
2195 struct set_volumes_params params =
2197 .stream = params32->stream,
2198 .master_volume = params32->master_volume,
2199 .volumes = ULongToPtr(params32->volumes),
2200 .session_volumes = ULongToPtr(params32->session_volumes),
2202 return unix_set_volumes(&params);
2205 static NTSTATUS unix_wow64_set_event_handle(void *args)
2207 struct
2209 stream_handle stream;
2210 PTR32 event;
2211 HRESULT result;
2212 } *params32 = args;
2213 struct set_event_handle_params params =
2215 .stream = params32->stream,
2216 .event = ULongToHandle(params32->event)
2218 unix_set_event_handle(&params);
2219 params32->result = params.result;
2220 return STATUS_SUCCESS;
2223 static NTSTATUS unix_wow64_get_prop_value(void *args)
2225 struct propvariant32
2227 WORD vt;
2228 WORD pad1, pad2, pad3;
2229 union
2231 ULONG ulVal;
2232 PTR32 ptr;
2233 ULARGE_INTEGER uhVal;
2235 } *value32;
2236 struct
2238 PTR32 device;
2239 EDataFlow flow;
2240 PTR32 guid;
2241 PTR32 prop;
2242 HRESULT result;
2243 PTR32 value;
2244 PTR32 buffer; /* caller allocated buffer to hold value's strings */
2245 PTR32 buffer_size;
2246 } *params32 = args;
2247 PROPVARIANT value;
2248 struct get_prop_value_params params =
2250 .device = ULongToPtr(params32->device),
2251 .flow = params32->flow,
2252 .guid = ULongToPtr(params32->guid),
2253 .prop = ULongToPtr(params32->prop),
2254 .value = &value,
2255 .buffer = ULongToPtr(params32->buffer),
2256 .buffer_size = ULongToPtr(params32->buffer_size)
2258 unix_get_prop_value(&params);
2259 params32->result = params.result;
2260 if (SUCCEEDED(params.result))
2262 value32 = UlongToPtr(params32->value);
2263 value32->vt = value.vt;
2264 switch (value.vt)
2266 case VT_UI4:
2267 value32->ulVal = value.ulVal;
2268 break;
2269 case VT_LPWSTR:
2270 value32->ptr = params32->buffer;
2271 break;
2272 default:
2273 FIXME("Unhandled vt %04x\n", value.vt);
2276 return STATUS_SUCCESS;
2279 const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
2281 unix_process_attach,
2282 unix_not_implemented,
2283 unix_wow64_main_loop,
2284 unix_wow64_get_endpoint_ids,
2285 unix_wow64_create_stream,
2286 unix_wow64_release_stream,
2287 unix_start,
2288 unix_stop,
2289 unix_reset,
2290 unix_timer_loop,
2291 unix_wow64_get_render_buffer,
2292 unix_release_render_buffer,
2293 unix_wow64_get_capture_buffer,
2294 unix_release_capture_buffer,
2295 unix_wow64_is_format_supported,
2296 unix_not_implemented,
2297 unix_wow64_get_mix_format,
2298 unix_wow64_get_device_period,
2299 unix_wow64_get_buffer_size,
2300 unix_wow64_get_latency,
2301 unix_wow64_get_current_padding,
2302 unix_wow64_get_next_packet_size,
2303 unix_wow64_get_frequency,
2304 unix_wow64_get_position,
2305 unix_wow64_set_volumes,
2306 unix_wow64_set_event_handle,
2307 unix_not_implemented,
2308 unix_is_started,
2309 unix_wow64_get_prop_value,
2310 unix_wow64_midi_init,
2311 unix_midi_release,
2312 unix_wow64_midi_out_message,
2313 unix_wow64_midi_in_message,
2314 unix_wow64_midi_notify_wait,
2315 unix_not_implemented,
2318 C_ASSERT(ARRAYSIZE(__wine_unix_call_wow64_funcs) == funcs_count);
2320 #endif /* _WIN64 */