mmdevapi: Implement AudioClient_Create.
[wine.git] / dlls / wineoss.drv / oss.c
blob097e048d03be100a7b7f85da132b0bfd8533532e
1 /*
2 * OSS driver (unixlib)
4 * Copyright 2011 Andrew Eikum for CodeWeavers
5 * 2022 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
22 #if 0
23 #pragma makedep unix
24 #endif
26 #include <stdarg.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <sys/ioctl.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <errno.h>
33 #include <sys/soundcard.h>
34 #include <pthread.h>
36 #include "ntstatus.h"
37 #define WIN32_NO_STATUS
38 #include "winternl.h"
39 #include "initguid.h"
40 #include "audioclient.h"
41 #include "mmddk.h"
43 #include "wine/debug.h"
44 #include "wine/unixlib.h"
46 #include "unixlib.h"
48 struct oss_stream
50 WAVEFORMATEX *fmt;
51 EDataFlow flow;
52 UINT flags;
53 AUDCLNT_SHAREMODE share;
54 HANDLE event;
56 int fd;
58 BOOL playing, mute, please_quit;
59 UINT64 written_frames, last_pos_frames;
60 UINT32 period_frames, bufsize_frames, held_frames, tmp_buffer_frames, in_oss_frames;
61 UINT32 oss_bufsize_bytes, lcl_offs_frames; /* offs into local_buffer where valid data starts */
62 REFERENCE_TIME period;
64 BYTE *local_buffer, *tmp_buffer;
65 INT32 getbuf_last; /* <0 when using tmp_buffer */
67 pthread_mutex_t lock;
70 WINE_DEFAULT_DEBUG_CHANNEL(oss);
72 static const REFERENCE_TIME def_period = 100000;
73 static const REFERENCE_TIME min_period = 50000;
75 static ULONG_PTR zero_bits = 0;
77 static NTSTATUS oss_not_implemented(void *args)
79 return STATUS_SUCCESS;
82 /* copied from kernelbase */
83 static int muldiv( int a, int b, int c )
85 LONGLONG ret;
87 if (!c) return -1;
89 /* We want to deal with a positive divisor to simplify the logic. */
90 if (c < 0)
92 a = -a;
93 c = -c;
96 /* If the result is positive, we "add" to round. else, we subtract to round. */
97 if ((a < 0 && b < 0) || (a >= 0 && b >= 0))
98 ret = (((LONGLONG)a * b) + (c / 2)) / c;
99 else
100 ret = (((LONGLONG)a * b) - (c / 2)) / c;
102 if (ret > 2147483647 || ret < -2147483647) return -1;
103 return ret;
106 static void oss_lock(struct oss_stream *stream)
108 pthread_mutex_lock(&stream->lock);
111 static void oss_unlock(struct oss_stream *stream)
113 pthread_mutex_unlock(&stream->lock);
116 static NTSTATUS oss_unlock_result(struct oss_stream *stream,
117 HRESULT *result, HRESULT value)
119 *result = value;
120 oss_unlock(stream);
121 return STATUS_SUCCESS;
124 static struct oss_stream *handle_get_stream(stream_handle h)
126 return (struct oss_stream *)(UINT_PTR)h;
129 static NTSTATUS oss_test_connect(void *args)
131 struct test_connect_params *params = args;
132 int mixer_fd;
133 oss_sysinfo sysinfo;
135 /* Attempt to determine if we are running on OSS or ALSA's OSS
136 * compatibility layer. There is no official way to do that, so just check
137 * for validity as best as possible, without rejecting valid OSS
138 * implementations. */
140 mixer_fd = open("/dev/mixer", O_RDONLY, 0);
141 if(mixer_fd < 0){
142 TRACE("Priority_Unavailable: open failed\n");
143 params->priority = Priority_Unavailable;
144 return STATUS_SUCCESS;
147 sysinfo.version[0] = 0xFF;
148 sysinfo.versionnum = ~0;
149 if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){
150 TRACE("Priority_Unavailable: ioctl failed\n");
151 close(mixer_fd);
152 params->priority = Priority_Unavailable;
153 return STATUS_SUCCESS;
156 close(mixer_fd);
158 if(sysinfo.version[0] < '4' || sysinfo.version[0] > '9'){
159 TRACE("Priority_Low: sysinfo.version[0]: %x\n", sysinfo.version[0]);
160 params->priority = Priority_Low;
161 return STATUS_SUCCESS;
163 if(sysinfo.versionnum & 0x80000000){
164 TRACE("Priority_Low: sysinfo.versionnum: %x\n", sysinfo.versionnum);
165 params->priority = Priority_Low;
166 return STATUS_SUCCESS;
169 TRACE("Priority_Preferred: Seems like valid OSS!\n");
171 params->priority = Priority_Preferred;
172 return STATUS_SUCCESS;
175 /* dst must be large enough to hold devnode */
176 static void oss_clean_devnode(char *dest, const char *devnode)
178 const char *dot, *slash;
179 size_t len;
181 strcpy(dest, devnode);
182 dot = strrchr(dest, '.');
183 if(!dot)
184 return;
186 slash = strrchr(dest, '/');
187 if(slash && dot < slash)
188 return;
190 len = dot - dest;
191 dest[len] = '\0';
194 static int open_device(const char *device, EDataFlow flow)
196 int flags = ((flow == eRender) ? O_WRONLY : O_RDONLY) | O_NONBLOCK;
198 return open(device, flags, 0);
201 static void get_default_device(EDataFlow flow, char device[OSS_DEVNODE_SIZE])
203 int fd, err;
204 oss_audioinfo ai;
206 device[0] = '\0';
207 fd = open_device("/dev/dsp", flow);
208 if(fd < 0){
209 WARN("Couldn't open default device!\n");
210 return;
213 ai.dev = -1;
214 if((err = ioctl(fd, SNDCTL_ENGINEINFO, &ai)) < 0){
215 WARN("SNDCTL_ENGINEINFO failed: %d (%s)\n", err, strerror(errno));
216 close(fd);
217 return;
219 close(fd);
221 TRACE("Default devnode: %s\n", ai.devnode);
222 oss_clean_devnode(device, ai.devnode);
223 return;
226 static NTSTATUS oss_process_attach(void *args)
228 #ifdef _WIN64
229 if (NtCurrentTeb()->WowTebOffset)
231 SYSTEM_BASIC_INFORMATION info;
233 NtQuerySystemInformation(SystemEmulationBasicInformation, &info, sizeof(info), NULL);
234 zero_bits = (ULONG_PTR)info.HighestUserAddress | 0x7fffffff;
236 #endif
237 return STATUS_SUCCESS;
240 static NTSTATUS oss_main_loop(void *args)
242 struct main_loop_params *params = args;
243 NtSetEvent(params->event, NULL);
244 return STATUS_SUCCESS;
247 static NTSTATUS oss_get_endpoint_ids(void *args)
249 struct get_endpoint_ids_params *params = args;
250 oss_sysinfo sysinfo;
251 oss_audioinfo ai;
252 static int print_once = 0;
253 static const WCHAR outW[] = {'O','u','t',':',' ',0};
254 static const WCHAR inW[] = {'I','n',':',' ',0};
255 struct endpoint_info
257 WCHAR name[ARRAY_SIZE(ai.name) + ARRAY_SIZE(outW)];
258 char device[OSS_DEVNODE_SIZE];
259 } *info;
260 unsigned int i, j, num, needed, name_len, device_len, offset, default_idx = 0;
261 char default_device[OSS_DEVNODE_SIZE];
262 struct endpoint *endpoint;
263 int mixer_fd;
265 mixer_fd = open("/dev/mixer", O_RDONLY, 0);
266 if(mixer_fd < 0){
267 ERR("OSS /dev/mixer doesn't seem to exist\n");
268 params->result = AUDCLNT_E_SERVICE_NOT_RUNNING;
269 return STATUS_SUCCESS;
272 if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){
273 close(mixer_fd);
274 if(errno == EINVAL){
275 ERR("OSS version too old, need at least OSSv4\n");
276 params->result = AUDCLNT_E_SERVICE_NOT_RUNNING;
277 return STATUS_SUCCESS;
280 ERR("Error getting SNDCTL_SYSINFO: %d (%s)\n", errno, strerror(errno));
281 params->result = E_FAIL;
282 return STATUS_SUCCESS;
285 if(!print_once){
286 TRACE("OSS sysinfo:\n");
287 TRACE("product: %s\n", sysinfo.product);
288 TRACE("version: %s\n", sysinfo.version);
289 TRACE("versionnum: %x\n", sysinfo.versionnum);
290 TRACE("numaudios: %d\n", sysinfo.numaudios);
291 TRACE("nummixers: %d\n", sysinfo.nummixers);
292 TRACE("numcards: %d\n", sysinfo.numcards);
293 TRACE("numaudioengines: %d\n", sysinfo.numaudioengines);
294 print_once = 1;
297 if(sysinfo.numaudios <= 0){
298 WARN("No audio devices!\n");
299 close(mixer_fd);
300 params->result = AUDCLNT_E_SERVICE_NOT_RUNNING;
301 return STATUS_SUCCESS;
304 info = malloc(sysinfo.numaudios * sizeof(*info));
305 if(!info){
306 close(mixer_fd);
307 params->result = E_OUTOFMEMORY;
308 return STATUS_SUCCESS;
311 get_default_device(params->flow, default_device);
313 num = 0;
314 for(i = 0; i < sysinfo.numaudios; ++i){
315 char devnode[OSS_DEVNODE_SIZE];
316 int fd, prefix_len;
317 const WCHAR *prefix;
319 memset(&ai, 0, sizeof(ai));
320 ai.dev = i;
321 if(ioctl(mixer_fd, SNDCTL_AUDIOINFO, &ai) < 0){
322 WARN("Error getting AUDIOINFO for dev %d: %d (%s)\n", i, errno,
323 strerror(errno));
324 continue;
327 oss_clean_devnode(devnode, ai.devnode);
329 /* check for duplicates */
330 for(j = 0; j < num; j++)
331 if(!strcmp(devnode, info[j].device))
332 break;
333 if(j < num)
334 continue;
336 fd = open_device(devnode, params->flow);
337 if(fd < 0){
338 WARN("Opening device \"%s\" failed, pretending it doesn't exist: %d (%s)\n",
339 devnode, errno, strerror(errno));
340 continue;
342 close(fd);
344 if((params->flow == eCapture && !(ai.caps & PCM_CAP_INPUT)) ||
345 (params->flow == eRender && !(ai.caps & PCM_CAP_OUTPUT)))
346 continue;
348 strcpy(info[num].device, devnode);
350 if(params->flow == eRender){
351 prefix = outW;
352 prefix_len = ARRAY_SIZE(outW) - 1;
353 }else{
354 prefix = inW;
355 prefix_len = ARRAY_SIZE(inW) - 1;
357 memcpy(info[num].name, prefix, prefix_len * sizeof(WCHAR));
358 ntdll_umbstowcs(ai.name, strlen(ai.name) + 1, info[num].name + prefix_len,
359 ARRAY_SIZE(info[num].name) - prefix_len);
360 if(!strcmp(default_device, info[num].device))
361 default_idx = num;
362 num++;
364 close(mixer_fd);
366 offset = needed = num * sizeof(*params->endpoints);
367 endpoint = params->endpoints;
369 for(i = 0; i < num; i++){
370 name_len = wcslen(info[i].name) + 1;
371 device_len = strlen(info[i].device) + 1;
372 needed += name_len * sizeof(WCHAR) + ((device_len + 1) & ~1);
374 if(needed <= params->size){
375 endpoint->name = offset;
376 memcpy((char *)params->endpoints + offset, info[i].name, name_len * sizeof(WCHAR));
377 offset += name_len * sizeof(WCHAR);
378 endpoint->device = offset;
379 memcpy((char *)params->endpoints + offset, info[i].device, device_len);
380 offset += (device_len + 1) & ~1;
381 endpoint++;
384 free(info);
386 params->num = num;
387 params->default_idx = default_idx;
389 if(needed > params->size){
390 params->size = needed;
391 params->result = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
392 } else
393 params->result = S_OK;
395 return STATUS_SUCCESS;
398 static UINT get_channel_mask(unsigned int channels)
400 switch(channels){
401 case 0:
402 return 0;
403 case 1:
404 return KSAUDIO_SPEAKER_MONO;
405 case 2:
406 return KSAUDIO_SPEAKER_STEREO;
407 case 3:
408 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
409 case 4:
410 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
411 case 5:
412 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
413 case 6:
414 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
415 case 7:
416 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
417 case 8:
418 return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
420 FIXME("Unknown speaker configuration: %u\n", channels);
421 return 0;
424 static int get_oss_format(const WAVEFORMATEX *fmt)
426 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)fmt;
428 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
429 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
430 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
431 switch(fmt->wBitsPerSample){
432 case 8:
433 return AFMT_U8;
434 case 16:
435 return AFMT_S16_LE;
436 case 24:
437 return AFMT_S24_LE;
438 case 32:
439 return AFMT_S32_LE;
441 return -1;
444 #ifdef AFMT_FLOAT
445 if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
446 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
447 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
448 if(fmt->wBitsPerSample != 32)
449 return -1;
451 return AFMT_FLOAT;
453 #endif
455 return -1;
458 static WAVEFORMATEXTENSIBLE *clone_format(const WAVEFORMATEX *fmt)
460 WAVEFORMATEXTENSIBLE *ret;
461 size_t size;
463 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
464 size = sizeof(WAVEFORMATEXTENSIBLE);
465 else
466 size = sizeof(WAVEFORMATEX);
468 ret = malloc(size);
469 if(!ret)
470 return NULL;
472 memcpy(ret, fmt, size);
474 ret->Format.cbSize = size - sizeof(WAVEFORMATEX);
476 return ret;
479 static HRESULT setup_oss_device(AUDCLNT_SHAREMODE share, int fd,
480 const WAVEFORMATEX *fmt, WAVEFORMATEXTENSIBLE *out)
482 const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
483 int tmp, oss_format;
484 double tenth;
485 HRESULT ret = S_OK;
486 WAVEFORMATEXTENSIBLE *closest;
488 tmp = oss_format = get_oss_format(fmt);
489 if(oss_format < 0)
490 return AUDCLNT_E_UNSUPPORTED_FORMAT;
491 if(ioctl(fd, SNDCTL_DSP_SETFMT, &tmp) < 0){
492 WARN("SETFMT failed: %d (%s)\n", errno, strerror(errno));
493 return E_FAIL;
495 if(tmp != oss_format){
496 TRACE("Format unsupported by this OSS version: %x\n", oss_format);
497 return AUDCLNT_E_UNSUPPORTED_FORMAT;
500 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
501 (fmtex->Format.nAvgBytesPerSec == 0 ||
502 fmtex->Format.nBlockAlign == 0 ||
503 fmtex->Samples.wValidBitsPerSample > fmtex->Format.wBitsPerSample))
504 return E_INVALIDARG;
506 if(fmt->nChannels == 0)
507 return AUDCLNT_E_UNSUPPORTED_FORMAT;
509 closest = clone_format(fmt);
510 if(!closest)
511 return E_OUTOFMEMORY;
513 tmp = fmt->nSamplesPerSec;
514 if(ioctl(fd, SNDCTL_DSP_SPEED, &tmp) < 0){
515 WARN("SPEED failed: %d (%s)\n", errno, strerror(errno));
516 free(closest);
517 return E_FAIL;
519 tenth = fmt->nSamplesPerSec * 0.1;
520 if(tmp > fmt->nSamplesPerSec + tenth || tmp < fmt->nSamplesPerSec - tenth){
521 ret = S_FALSE;
522 closest->Format.nSamplesPerSec = tmp;
525 tmp = fmt->nChannels;
526 if(ioctl(fd, SNDCTL_DSP_CHANNELS, &tmp) < 0){
527 WARN("CHANNELS failed: %d (%s)\n", errno, strerror(errno));
528 free(closest);
529 return E_FAIL;
531 if(tmp != fmt->nChannels){
532 ret = S_FALSE;
533 closest->Format.nChannels = tmp;
536 if(closest->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
537 closest->dwChannelMask = get_channel_mask(closest->Format.nChannels);
539 if(fmt->nBlockAlign != fmt->nChannels * fmt->wBitsPerSample / 8 ||
540 fmt->nAvgBytesPerSec != fmt->nBlockAlign * fmt->nSamplesPerSec ||
541 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
542 fmtex->Samples.wValidBitsPerSample < fmtex->Format.wBitsPerSample))
543 ret = S_FALSE;
545 if(share == AUDCLNT_SHAREMODE_EXCLUSIVE &&
546 fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
547 if(fmtex->dwChannelMask == 0 || fmtex->dwChannelMask & SPEAKER_RESERVED)
548 ret = S_FALSE;
551 if(ret == S_FALSE && !out)
552 ret = AUDCLNT_E_UNSUPPORTED_FORMAT;
554 if(ret == S_FALSE && out){
555 closest->Format.nBlockAlign =
556 closest->Format.nChannels * closest->Format.wBitsPerSample / 8;
557 closest->Format.nAvgBytesPerSec =
558 closest->Format.nBlockAlign * closest->Format.nSamplesPerSec;
559 if(closest->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
560 closest->Samples.wValidBitsPerSample = closest->Format.wBitsPerSample;
561 memcpy(out, closest, closest->Format.cbSize + sizeof(WAVEFORMATEX));
563 free(closest);
565 TRACE("returning: %08x\n", (unsigned)ret);
566 return ret;
569 static NTSTATUS oss_create_stream(void *args)
571 struct create_stream_params *params = args;
572 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE *)params->fmt;
573 struct oss_stream *stream;
574 oss_audioinfo ai;
575 SIZE_T size;
577 params->result = S_OK;
579 if (params->share == AUDCLNT_SHAREMODE_SHARED) {
580 params->period = def_period;
581 if (params->duration < 3 * params->period)
582 params->duration = 3 * params->period;
583 } else {
584 if (fmtex->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
585 (fmtex->dwChannelMask == 0 || fmtex->dwChannelMask & SPEAKER_RESERVED))
586 params->result = AUDCLNT_E_UNSUPPORTED_FORMAT;
587 else {
588 if (!params->period)
589 params->period = def_period;
590 if (params->period < min_period || params->period > 5000000)
591 params->result = AUDCLNT_E_INVALID_DEVICE_PERIOD;
592 else if (params->duration > 20000000) /* The smaller the period, the lower this limit. */
593 params->result = AUDCLNT_E_BUFFER_SIZE_ERROR;
594 else if (params->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) {
595 if (params->duration != params->period)
596 params->result = AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
598 FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
600 params->result = AUDCLNT_E_DEVICE_IN_USE;
601 } else if (params->duration < 8 * params->period)
602 params->duration = 8 * params->period; /* May grow above 2s. */
606 if (FAILED(params->result))
607 return STATUS_SUCCESS;
609 stream = calloc(1, sizeof(*stream));
610 if(!stream){
611 params->result = E_OUTOFMEMORY;
612 return STATUS_SUCCESS;
615 stream->flow = params->flow;
616 pthread_mutex_init(&stream->lock, NULL);
618 stream->fd = open_device(params->device, params->flow);
619 if(stream->fd < 0){
620 WARN("Unable to open device %s: %d (%s)\n", params->device, errno, strerror(errno));
621 params->result = AUDCLNT_E_DEVICE_INVALIDATED;
622 goto exit;
625 ai.dev = -1;
626 if(ioctl(stream->fd, SNDCTL_ENGINEINFO, &ai) < 0){
627 WARN("Unable to get audio info for device %s: %d (%s)\n", params->device, errno, strerror(errno));
628 params->result = E_FAIL;
629 goto exit;
632 TRACE("OSS audioinfo:\n");
633 TRACE("devnode: %s\n", ai.devnode);
634 TRACE("name: %s\n", ai.name);
635 TRACE("busy: %x\n", ai.busy);
636 TRACE("caps: %x\n", ai.caps);
637 TRACE("iformats: %x\n", ai.iformats);
638 TRACE("oformats: %x\n", ai.oformats);
639 TRACE("enabled: %d\n", ai.enabled);
640 TRACE("min_rate: %d\n", ai.min_rate);
641 TRACE("max_rate: %d\n", ai.max_rate);
642 TRACE("min_channels: %d\n", ai.min_channels);
643 TRACE("max_channels: %d\n", ai.max_channels);
645 params->result = setup_oss_device(params->share, stream->fd, params->fmt, NULL);
646 if(FAILED(params->result))
647 goto exit;
649 fmtex = clone_format(params->fmt);
650 if(!fmtex){
651 params->result = E_OUTOFMEMORY;
652 goto exit;
654 stream->fmt = &fmtex->Format;
656 stream->period = params->period;
657 stream->period_frames = muldiv(params->fmt->nSamplesPerSec, params->period, 10000000);
659 stream->bufsize_frames = muldiv(params->duration, params->fmt->nSamplesPerSec, 10000000);
660 if(params->share == AUDCLNT_SHAREMODE_EXCLUSIVE)
661 stream->bufsize_frames -= stream->bufsize_frames % stream->period_frames;
662 size = stream->bufsize_frames * params->fmt->nBlockAlign;
663 if(NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, zero_bits,
664 &size, MEM_COMMIT, PAGE_READWRITE)){
665 params->result = E_OUTOFMEMORY;
666 goto exit;
669 stream->share = params->share;
670 stream->flags = params->flags;
671 stream->oss_bufsize_bytes = 0;
673 exit:
674 if(FAILED(params->result)){
675 if(stream->fd >= 0) close(stream->fd);
676 if(stream->local_buffer){
677 size = 0;
678 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, &size, MEM_RELEASE);
680 pthread_mutex_destroy(&stream->lock);
681 free(stream->fmt);
682 free(stream);
683 }else{
684 *params->channel_count = params->fmt->nChannels;
685 *params->stream = (stream_handle)(UINT_PTR)stream;
688 return STATUS_SUCCESS;
691 static NTSTATUS oss_release_stream(void *args)
693 struct release_stream_params *params = args;
694 struct oss_stream *stream = handle_get_stream(params->stream);
695 SIZE_T size;
697 if(params->timer_thread){
698 stream->please_quit = TRUE;
699 NtWaitForSingleObject(params->timer_thread, FALSE, NULL);
700 NtClose(params->timer_thread);
703 close(stream->fd);
704 if(stream->local_buffer){
705 size = 0;
706 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, &size, MEM_RELEASE);
708 if(stream->tmp_buffer){
709 size = 0;
710 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, &size, MEM_RELEASE);
712 free(stream->fmt);
713 pthread_mutex_destroy(&stream->lock);
714 free(stream);
716 params->result = S_OK;
717 return STATUS_SUCCESS;
720 static NTSTATUS oss_start(void *args)
722 struct start_params *params = args;
723 struct oss_stream *stream = handle_get_stream(params->stream);
725 oss_lock(stream);
727 if((stream->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !stream->event)
728 return oss_unlock_result(stream, &params->result, AUDCLNT_E_EVENTHANDLE_NOT_SET);
730 if(stream->playing)
731 return oss_unlock_result(stream, &params->result, AUDCLNT_E_NOT_STOPPED);
733 stream->playing = TRUE;
735 return oss_unlock_result(stream, &params->result, S_OK);
738 static NTSTATUS oss_stop(void *args)
740 struct stop_params *params = args;
741 struct oss_stream *stream = handle_get_stream(params->stream);
743 oss_lock(stream);
745 if(!stream->playing)
746 return oss_unlock_result(stream, &params->result, S_FALSE);
748 stream->playing = FALSE;
749 stream->in_oss_frames = 0;
751 return oss_unlock_result(stream, &params->result, S_OK);
754 static NTSTATUS oss_reset(void *args)
756 struct reset_params *params = args;
757 struct oss_stream *stream = handle_get_stream(params->stream);
759 oss_lock(stream);
761 if(stream->playing)
762 return oss_unlock_result(stream, &params->result, AUDCLNT_E_NOT_STOPPED);
764 if(stream->getbuf_last)
765 return oss_unlock_result(stream, &params->result, AUDCLNT_E_BUFFER_OPERATION_PENDING);
767 if(stream->flow == eRender){
768 stream->written_frames = 0;
769 stream->last_pos_frames = 0;
770 }else{
771 stream->written_frames += stream->held_frames;
773 stream->held_frames = 0;
774 stream->lcl_offs_frames = 0;
775 stream->in_oss_frames = 0;
777 return oss_unlock_result(stream, &params->result, S_OK);
780 static void silence_buffer(struct oss_stream *stream, BYTE *buffer, UINT32 frames)
782 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)stream->fmt;
783 if((stream->fmt->wFormatTag == WAVE_FORMAT_PCM ||
784 (stream->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
785 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
786 stream->fmt->wBitsPerSample == 8)
787 memset(buffer, 128, frames * stream->fmt->nBlockAlign);
788 else
789 memset(buffer, 0, frames * stream->fmt->nBlockAlign);
792 static void oss_write_data(struct oss_stream *stream)
794 ssize_t written_bytes;
795 UINT32 written_frames, in_oss_frames, write_limit, max_period, write_offs_frames, new_frames;
796 SIZE_T to_write_frames, to_write_bytes, advanced;
797 audio_buf_info bi;
798 BYTE *buf;
800 if(ioctl(stream->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0){
801 WARN("GETOSPACE failed: %d (%s)\n", errno, strerror(errno));
802 return;
805 max_period = max(bi.fragsize / stream->fmt->nBlockAlign, stream->period_frames);
807 if(bi.bytes > stream->oss_bufsize_bytes){
808 TRACE("New buffer size (%u) is larger than old buffer size (%u)\n",
809 bi.bytes, stream->oss_bufsize_bytes);
810 stream->oss_bufsize_bytes = bi.bytes;
811 in_oss_frames = 0;
812 }else
813 in_oss_frames = (stream->oss_bufsize_bytes - bi.bytes) / stream->fmt->nBlockAlign;
815 if(in_oss_frames > stream->in_oss_frames){
816 TRACE("Capping reported frames from %u to %u\n",
817 in_oss_frames, stream->in_oss_frames);
818 in_oss_frames = stream->in_oss_frames;
821 write_limit = 0;
822 while(write_limit + in_oss_frames < max_period * 3)
823 write_limit += max_period;
824 if(write_limit == 0)
825 return;
827 /* vvvvvv - in_oss_frames
828 * [--xxxxxxxxxx]
829 * [xxxxxxxxxx--]
830 * ^^^^^^^^^^ - held_frames
831 * ^ - lcl_offs_frames
833 advanced = stream->in_oss_frames - in_oss_frames;
834 if(advanced > stream->held_frames)
835 advanced = stream->held_frames;
836 stream->lcl_offs_frames += advanced;
837 stream->lcl_offs_frames %= stream->bufsize_frames;
838 stream->held_frames -= advanced;
839 stream->in_oss_frames = in_oss_frames;
840 TRACE("advanced by %lu, lcl_offs: %u, held: %u, in_oss: %u\n",
841 advanced, stream->lcl_offs_frames, stream->held_frames, stream->in_oss_frames);
844 if(stream->held_frames == stream->in_oss_frames)
845 return;
847 write_offs_frames = (stream->lcl_offs_frames + stream->in_oss_frames) % stream->bufsize_frames;
848 new_frames = stream->held_frames - stream->in_oss_frames;
850 if(write_offs_frames + new_frames > stream->bufsize_frames)
851 to_write_frames = stream->bufsize_frames - write_offs_frames;
852 else
853 to_write_frames = new_frames;
855 to_write_frames = min(to_write_frames, write_limit);
856 to_write_bytes = to_write_frames * stream->fmt->nBlockAlign;
857 TRACE("going to write %lu frames from %u (%lu of %u)\n", to_write_frames,
858 write_offs_frames, to_write_frames + write_offs_frames,
859 stream->bufsize_frames);
861 buf = stream->local_buffer + write_offs_frames * stream->fmt->nBlockAlign;
863 if(stream->mute)
864 silence_buffer(stream, buf, to_write_frames);
866 written_bytes = write(stream->fd, buf, to_write_bytes);
867 if(written_bytes < 0){
868 /* EAGAIN is OSS buffer full, log that too */
869 WARN("write failed: %d (%s)\n", errno, strerror(errno));
870 return;
872 written_frames = written_bytes / stream->fmt->nBlockAlign;
874 stream->in_oss_frames += written_frames;
876 if(written_frames < to_write_frames){
877 /* OSS buffer probably full */
878 return;
881 if(new_frames > written_frames && written_frames < write_limit){
882 /* wrapped and have some data back at the start to write */
884 to_write_frames = min(write_limit - written_frames, new_frames - written_frames);
885 to_write_bytes = to_write_frames * stream->fmt->nBlockAlign;
887 if(stream->mute)
888 silence_buffer(stream, stream->local_buffer, to_write_frames);
890 TRACE("wrapping to write %lu frames from beginning\n", to_write_frames);
892 written_bytes = write(stream->fd, stream->local_buffer, to_write_bytes);
893 if(written_bytes < 0){
894 WARN("write failed: %d (%s)\n", errno, strerror(errno));
895 return;
897 written_frames = written_bytes / stream->fmt->nBlockAlign;
898 stream->in_oss_frames += written_frames;
902 static void oss_read_data(struct oss_stream *stream)
904 UINT64 pos, readable;
905 ssize_t nread;
907 pos = (stream->held_frames + stream->lcl_offs_frames) % stream->bufsize_frames;
908 readable = (stream->bufsize_frames - pos) * stream->fmt->nBlockAlign;
910 nread = read(stream->fd, stream->local_buffer + pos * stream->fmt->nBlockAlign,
911 readable);
912 if(nread < 0){
913 WARN("read failed: %d (%s)\n", errno, strerror(errno));
914 return;
917 stream->held_frames += nread / stream->fmt->nBlockAlign;
919 if(stream->held_frames > stream->bufsize_frames){
920 WARN("Overflow of unread data\n");
921 stream->lcl_offs_frames += stream->held_frames;
922 stream->lcl_offs_frames %= stream->bufsize_frames;
923 stream->held_frames = stream->bufsize_frames;
927 static NTSTATUS oss_timer_loop(void *args)
929 struct timer_loop_params *params = args;
930 struct oss_stream *stream = handle_get_stream(params->stream);
931 LARGE_INTEGER delay, now, next;
932 int adjust;
934 oss_lock(stream);
936 delay.QuadPart = -stream->period;
937 NtQueryPerformanceCounter(&now, NULL);
938 next.QuadPart = now.QuadPart + stream->period;
940 while(!stream->please_quit){
941 if(stream->playing){
942 if(stream->flow == eRender && stream->held_frames)
943 oss_write_data(stream);
944 else if(stream->flow == eCapture)
945 oss_read_data(stream);
947 if(stream->event)
948 NtSetEvent(stream->event, NULL);
949 oss_unlock(stream);
951 NtDelayExecution(FALSE, &delay);
953 oss_lock(stream);
954 NtQueryPerformanceCounter(&now, NULL);
955 adjust = next.QuadPart - now.QuadPart;
956 if(adjust > stream->period / 2)
957 adjust = stream->period / 2;
958 else if(adjust < -stream->period / 2)
959 adjust = -stream->period / 2;
960 delay.QuadPart = -(stream->period + adjust);
961 next.QuadPart += stream->period;
964 oss_unlock(stream);
966 return STATUS_SUCCESS;
969 static NTSTATUS oss_get_render_buffer(void *args)
971 struct get_render_buffer_params *params = args;
972 struct oss_stream *stream = handle_get_stream(params->stream);
973 UINT32 write_pos, frames = params->frames;
974 BYTE **data = params->data;
975 SIZE_T size;
977 oss_lock(stream);
979 if(stream->getbuf_last)
980 return oss_unlock_result(stream, &params->result, AUDCLNT_E_OUT_OF_ORDER);
982 if(!frames)
983 return oss_unlock_result(stream, &params->result, S_OK);
985 if(stream->held_frames + frames > stream->bufsize_frames)
986 return oss_unlock_result(stream, &params->result, AUDCLNT_E_BUFFER_TOO_LARGE);
988 write_pos =
989 (stream->lcl_offs_frames + stream->held_frames) % stream->bufsize_frames;
990 if(write_pos + frames > stream->bufsize_frames){
991 if(stream->tmp_buffer_frames < frames){
992 if(stream->tmp_buffer){
993 size = 0;
994 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, &size, MEM_RELEASE);
995 stream->tmp_buffer = NULL;
997 size = frames * stream->fmt->nBlockAlign;
998 if(NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, zero_bits,
999 &size, MEM_COMMIT, PAGE_READWRITE)){
1000 stream->tmp_buffer_frames = 0;
1001 return oss_unlock_result(stream, &params->result, E_OUTOFMEMORY);
1003 stream->tmp_buffer_frames = frames;
1005 *data = stream->tmp_buffer;
1006 stream->getbuf_last = -frames;
1007 }else{
1008 *data = stream->local_buffer + write_pos * stream->fmt->nBlockAlign;
1009 stream->getbuf_last = frames;
1012 silence_buffer(stream, *data, frames);
1014 return oss_unlock_result(stream, &params->result, S_OK);
1017 static void oss_wrap_buffer(struct oss_stream *stream, BYTE *buffer, UINT32 written_frames)
1019 UINT32 write_offs_frames =
1020 (stream->lcl_offs_frames + stream->held_frames) % stream->bufsize_frames;
1021 UINT32 write_offs_bytes = write_offs_frames * stream->fmt->nBlockAlign;
1022 UINT32 chunk_frames = stream->bufsize_frames - write_offs_frames;
1023 UINT32 chunk_bytes = chunk_frames * stream->fmt->nBlockAlign;
1024 UINT32 written_bytes = written_frames * stream->fmt->nBlockAlign;
1026 if(written_bytes <= chunk_bytes){
1027 memcpy(stream->local_buffer + write_offs_bytes, buffer, written_bytes);
1028 }else{
1029 memcpy(stream->local_buffer + write_offs_bytes, buffer, chunk_bytes);
1030 memcpy(stream->local_buffer, buffer + chunk_bytes,
1031 written_bytes - chunk_bytes);
1035 static NTSTATUS oss_release_render_buffer(void *args)
1037 struct release_render_buffer_params *params = args;
1038 struct oss_stream *stream = handle_get_stream(params->stream);
1039 UINT32 written_frames = params->written_frames;
1040 UINT flags = params->flags;
1041 BYTE *buffer;
1043 oss_lock(stream);
1045 if(!written_frames){
1046 stream->getbuf_last = 0;
1047 return oss_unlock_result(stream, &params->result, S_OK);
1050 if(!stream->getbuf_last)
1051 return oss_unlock_result(stream, &params->result, AUDCLNT_E_OUT_OF_ORDER);
1053 if(written_frames > (stream->getbuf_last >= 0 ? stream->getbuf_last : -stream->getbuf_last))
1054 return oss_unlock_result(stream, &params->result, AUDCLNT_E_INVALID_SIZE);
1056 if(stream->getbuf_last >= 0)
1057 buffer = stream->local_buffer + stream->fmt->nBlockAlign *
1058 ((stream->lcl_offs_frames + stream->held_frames) % stream->bufsize_frames);
1059 else
1060 buffer = stream->tmp_buffer;
1062 if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
1063 silence_buffer(stream, buffer, written_frames);
1065 if(stream->getbuf_last < 0)
1066 oss_wrap_buffer(stream, buffer, written_frames);
1068 stream->held_frames += written_frames;
1069 stream->written_frames += written_frames;
1070 stream->getbuf_last = 0;
1072 return oss_unlock_result(stream, &params->result, S_OK);
1075 static NTSTATUS oss_get_capture_buffer(void *args)
1077 struct get_capture_buffer_params *params = args;
1078 struct oss_stream *stream = handle_get_stream(params->stream);
1079 UINT64 *devpos = params->devpos, *qpcpos = params->qpcpos;
1080 UINT32 *frames = params->frames;
1081 UINT *flags = params->flags;
1082 BYTE **data = params->data;
1083 SIZE_T size;
1085 oss_lock(stream);
1087 if(stream->getbuf_last)
1088 return oss_unlock_result(stream, &params->result, AUDCLNT_E_OUT_OF_ORDER);
1090 if(stream->held_frames < stream->period_frames){
1091 *frames = 0;
1092 return oss_unlock_result(stream, &params->result, AUDCLNT_S_BUFFER_EMPTY);
1095 *flags = 0;
1097 *frames = stream->period_frames;
1099 if(stream->lcl_offs_frames + *frames > stream->bufsize_frames){
1100 UINT32 chunk_bytes, offs_bytes, frames_bytes;
1101 if(stream->tmp_buffer_frames < *frames){
1102 if(stream->tmp_buffer){
1103 size = 0;
1104 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, &size, MEM_RELEASE);
1105 stream->tmp_buffer = NULL;
1107 size = *frames * stream->fmt->nBlockAlign;
1108 if(NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, zero_bits,
1109 &size, MEM_COMMIT, PAGE_READWRITE)){
1110 stream->tmp_buffer_frames = 0;
1111 return oss_unlock_result(stream, &params->result, E_OUTOFMEMORY);
1113 stream->tmp_buffer_frames = *frames;
1116 *data = stream->tmp_buffer;
1117 chunk_bytes = (stream->bufsize_frames - stream->lcl_offs_frames) *
1118 stream->fmt->nBlockAlign;
1119 offs_bytes = stream->lcl_offs_frames * stream->fmt->nBlockAlign;
1120 frames_bytes = *frames * stream->fmt->nBlockAlign;
1121 memcpy(stream->tmp_buffer, stream->local_buffer + offs_bytes, chunk_bytes);
1122 memcpy(stream->tmp_buffer + chunk_bytes, stream->local_buffer,
1123 frames_bytes - chunk_bytes);
1124 }else
1125 *data = stream->local_buffer +
1126 stream->lcl_offs_frames * stream->fmt->nBlockAlign;
1128 stream->getbuf_last = *frames;
1130 if(devpos)
1131 *devpos = stream->written_frames;
1132 if(qpcpos){
1133 LARGE_INTEGER stamp, freq;
1134 NtQueryPerformanceCounter(&stamp, &freq);
1135 *qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1138 return oss_unlock_result(stream, &params->result, *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY);
1141 static NTSTATUS oss_release_capture_buffer(void *args)
1143 struct release_capture_buffer_params *params = args;
1144 struct oss_stream *stream = handle_get_stream(params->stream);
1145 UINT32 done = params->done;
1147 oss_lock(stream);
1149 if(!done){
1150 stream->getbuf_last = 0;
1151 return oss_unlock_result(stream, &params->result, S_OK);
1154 if(!stream->getbuf_last)
1155 return oss_unlock_result(stream, &params->result, AUDCLNT_E_OUT_OF_ORDER);
1157 if(stream->getbuf_last != done)
1158 return oss_unlock_result(stream, &params->result, AUDCLNT_E_INVALID_SIZE);
1160 stream->written_frames += done;
1161 stream->held_frames -= done;
1162 stream->lcl_offs_frames += done;
1163 stream->lcl_offs_frames %= stream->bufsize_frames;
1164 stream->getbuf_last = 0;
1166 return oss_unlock_result(stream, &params->result, S_OK);
1169 static NTSTATUS oss_is_format_supported(void *args)
1171 struct is_format_supported_params *params = args;
1172 int fd;
1174 params->result = S_OK;
1176 if(!params->fmt_in || (params->share == AUDCLNT_SHAREMODE_SHARED && !params->fmt_out))
1177 params->result = E_POINTER;
1178 else if(params->share != AUDCLNT_SHAREMODE_SHARED && params->share != AUDCLNT_SHAREMODE_EXCLUSIVE)
1179 params->result = E_INVALIDARG;
1180 else if(params->fmt_in->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1181 params->fmt_in->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1182 params->result = E_INVALIDARG;
1183 if(FAILED(params->result))
1184 return STATUS_SUCCESS;
1186 fd = open_device(params->device, params->flow);
1187 if(fd < 0){
1188 WARN("Unable to open device %s: %d (%s)\n", params->device, errno, strerror(errno));
1189 params->result = AUDCLNT_E_DEVICE_INVALIDATED;
1190 return STATUS_SUCCESS;
1192 params->result = setup_oss_device(params->share, fd, params->fmt_in, params->fmt_out);
1193 close(fd);
1195 return STATUS_SUCCESS;
1198 static NTSTATUS oss_get_mix_format(void *args)
1200 struct get_mix_format_params *params = args;
1201 WAVEFORMATEXTENSIBLE *fmt = params->fmt;
1202 oss_audioinfo ai;
1203 int formats, fd;
1205 if(params->flow != eRender && params->flow != eCapture){
1206 params->result = E_UNEXPECTED;
1207 return STATUS_SUCCESS;
1210 fd = open_device(params->device, params->flow);
1211 if(fd < 0){
1212 WARN("Unable to open device %s: %d (%s)\n", params->device, errno, strerror(errno));
1213 params->result = AUDCLNT_E_DEVICE_INVALIDATED;
1214 return STATUS_SUCCESS;
1217 ai.dev = -1;
1218 if(ioctl(fd, SNDCTL_ENGINEINFO, &ai) < 0){
1219 WARN("Unable to get audio info for device %s: %d (%s)\n", params->device, errno, strerror(errno));
1220 close(fd);
1221 params->result = E_FAIL;
1222 return STATUS_SUCCESS;
1224 close(fd);
1226 if(params->flow == eRender)
1227 formats = ai.oformats;
1228 else
1229 formats = ai.iformats;
1231 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1232 if(formats & AFMT_S16_LE){
1233 fmt->Format.wBitsPerSample = 16;
1234 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1235 #ifdef AFMT_FLOAT
1236 }else if(formats & AFMT_FLOAT){
1237 fmt->Format.wBitsPerSample = 32;
1238 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1239 #endif
1240 }else if(formats & AFMT_U8){
1241 fmt->Format.wBitsPerSample = 8;
1242 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1243 }else if(formats & AFMT_S32_LE){
1244 fmt->Format.wBitsPerSample = 32;
1245 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1246 }else if(formats & AFMT_S24_LE){
1247 fmt->Format.wBitsPerSample = 24;
1248 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1249 }else{
1250 WARN("Didn't recognize any available OSS formats: %x\n", formats);
1251 params->result = E_FAIL;
1252 return STATUS_SUCCESS;
1255 /* some OSS drivers are buggy, so set reasonable defaults if
1256 * the reported values seem wacky */
1257 fmt->Format.nChannels = max(ai.max_channels, ai.min_channels);
1258 if(fmt->Format.nChannels == 0 || fmt->Format.nChannels > 8)
1259 fmt->Format.nChannels = 2;
1261 /* For most hardware on Windows, users must choose a configuration with an even
1262 * number of channels (stereo, quad, 5.1, 7.1). Users can then disable
1263 * channels, but those channels are still reported to applications from
1264 * GetMixFormat! Some applications behave badly if given an odd number of
1265 * channels (e.g. 2.1). */
1266 if(fmt->Format.nChannels > 1 && (fmt->Format.nChannels & 0x1))
1268 if(fmt->Format.nChannels < ai.max_channels)
1269 fmt->Format.nChannels += 1;
1270 else
1271 /* We could "fake" more channels and downmix the emulated channels,
1272 * but at that point you really ought to tweak your OSS setup or
1273 * just use PulseAudio. */
1274 WARN("Some Windows applications behave badly with an odd number of channels (%u)!\n", fmt->Format.nChannels);
1277 if(ai.max_rate == 0)
1278 fmt->Format.nSamplesPerSec = 44100;
1279 else
1280 fmt->Format.nSamplesPerSec = min(ai.max_rate, 44100);
1281 if(fmt->Format.nSamplesPerSec < ai.min_rate)
1282 fmt->Format.nSamplesPerSec = ai.min_rate;
1284 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1286 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1287 fmt->Format.nChannels) / 8;
1288 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1289 fmt->Format.nBlockAlign;
1291 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1292 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1294 params->result = S_OK;
1295 return STATUS_SUCCESS;
1298 static NTSTATUS oss_get_device_period(void *args)
1300 struct get_device_period_params *params = args;
1302 if (params->def_period)
1303 *params->def_period = def_period;
1304 if (params->min_period)
1305 *params->min_period = min_period;
1307 params->result = S_OK;
1309 return STATUS_SUCCESS;
1312 static NTSTATUS oss_get_buffer_size(void *args)
1314 struct get_buffer_size_params *params = args;
1315 struct oss_stream *stream = handle_get_stream(params->stream);
1317 oss_lock(stream);
1319 *params->frames = stream->bufsize_frames;
1321 return oss_unlock_result(stream, &params->result, S_OK);
1324 static NTSTATUS oss_get_latency(void *args)
1326 struct get_latency_params *params = args;
1327 struct oss_stream *stream = handle_get_stream(params->stream);
1329 oss_lock(stream);
1331 /* pretend we process audio in Period chunks, so max latency includes
1332 * the period time. Some native machines add .6666ms in shared mode. */
1333 *params->latency = stream->period + 6666;
1335 return oss_unlock_result(stream, &params->result, S_OK);
1338 static NTSTATUS oss_get_current_padding(void *args)
1340 struct get_current_padding_params *params = args;
1341 struct oss_stream *stream = handle_get_stream(params->stream);
1343 oss_lock(stream);
1345 *params->padding = stream->held_frames;
1347 return oss_unlock_result(stream, &params->result, S_OK);
1350 static NTSTATUS oss_get_next_packet_size(void *args)
1352 struct get_next_packet_size_params *params = args;
1353 struct oss_stream *stream = handle_get_stream(params->stream);
1354 UINT32 *frames = params->frames;
1356 oss_lock(stream);
1358 *frames = stream->held_frames < stream->period_frames ? 0 : stream->period_frames;
1360 return oss_unlock_result(stream, &params->result, S_OK);
1363 static NTSTATUS oss_get_frequency(void *args)
1365 struct get_frequency_params *params = args;
1366 struct oss_stream *stream = handle_get_stream(params->stream);
1367 UINT64 *freq = params->freq;
1369 oss_lock(stream);
1371 if(stream->share == AUDCLNT_SHAREMODE_SHARED)
1372 *freq = (UINT64)stream->fmt->nSamplesPerSec * stream->fmt->nBlockAlign;
1373 else
1374 *freq = stream->fmt->nSamplesPerSec;
1376 return oss_unlock_result(stream, &params->result, S_OK);
1379 static NTSTATUS oss_get_position(void *args)
1381 struct get_position_params *params = args;
1382 struct oss_stream *stream = handle_get_stream(params->stream);
1383 UINT64 *pos = params->pos, *qpctime = params->qpctime;
1385 if (params->device) {
1386 FIXME("Device position reporting not implemented\n");
1387 params->result = E_NOTIMPL;
1388 return STATUS_SUCCESS;
1391 oss_lock(stream);
1393 if(stream->flow == eRender){
1394 *pos = stream->written_frames - stream->held_frames;
1395 if(*pos < stream->last_pos_frames)
1396 *pos = stream->last_pos_frames;
1397 }else if(stream->flow == eCapture){
1398 audio_buf_info bi;
1399 UINT32 held;
1401 if(ioctl(stream->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
1402 TRACE("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
1403 held = 0;
1404 }else{
1405 if(bi.bytes <= bi.fragsize)
1406 held = 0;
1407 else
1408 held = bi.bytes / stream->fmt->nBlockAlign;
1411 *pos = stream->written_frames + held;
1414 stream->last_pos_frames = *pos;
1416 TRACE("returning: %s\n", wine_dbgstr_longlong(*pos));
1417 if(stream->share == AUDCLNT_SHAREMODE_SHARED)
1418 *pos *= stream->fmt->nBlockAlign;
1420 if(qpctime){
1421 LARGE_INTEGER stamp, freq;
1422 NtQueryPerformanceCounter(&stamp, &freq);
1423 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1426 return oss_unlock_result(stream, &params->result, S_OK);
1429 static NTSTATUS oss_set_volumes(void *args)
1431 struct set_volumes_params *params = args;
1432 struct oss_stream *stream = handle_get_stream(params->stream);
1433 UINT16 i;
1435 if (params->master_volume) {
1436 for (i = 0; i < stream->fmt->nChannels; ++i) {
1437 if (params->master_volume * params->volumes[i] * params->session_volumes[i] != 1.0f) {
1438 FIXME("Volume control is not implemented\n");
1439 break;
1444 oss_lock(stream);
1445 stream->mute = !params->master_volume;
1446 oss_unlock(stream);
1448 return STATUS_SUCCESS;
1451 static NTSTATUS oss_set_event_handle(void *args)
1453 struct set_event_handle_params *params = args;
1454 struct oss_stream *stream = handle_get_stream(params->stream);
1456 oss_lock(stream);
1458 if(!(stream->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK))
1459 return oss_unlock_result(stream, &params->result, AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED);
1461 if (stream->event){
1462 FIXME("called twice\n");
1463 return oss_unlock_result(stream, &params->result, HRESULT_FROM_WIN32(ERROR_INVALID_NAME));
1466 stream->event = params->event;
1468 return oss_unlock_result(stream, &params->result, S_OK);
1471 static NTSTATUS oss_is_started(void *args)
1473 struct is_started_params *params = args;
1474 struct oss_stream *stream = handle_get_stream(params->stream);
1476 oss_lock(stream);
1478 return oss_unlock_result(stream, &params->result, stream->playing ? S_OK : S_FALSE);
1481 /* Aux driver */
1483 static unsigned int num_aux;
1485 #define MIXER_DEV "/dev/mixer"
1487 static UINT aux_init(void)
1489 int mixer;
1491 TRACE("()\n");
1493 if ((mixer = open(MIXER_DEV, O_RDWR)) < 0)
1495 WARN("mixer device not available !\n");
1496 num_aux = 0;
1498 else
1500 close(mixer);
1501 num_aux = 6;
1503 return 0;
1506 static UINT aux_exit(void)
1508 TRACE("()\n");
1509 return 0;
1512 static UINT aux_get_devcaps(WORD dev_id, AUXCAPSW *caps, UINT size)
1514 int mixer, volume;
1515 static const WCHAR ini[] = {'O','S','S',' ','A','u','x',' ','#','0',0};
1517 TRACE("(%04X, %p, %u);\n", dev_id, caps, size);
1518 if (caps == NULL) return MMSYSERR_NOTENABLED;
1519 if (dev_id >= num_aux) return MMSYSERR_BADDEVICEID;
1520 if ((mixer = open(MIXER_DEV, O_RDWR)) < 0)
1522 WARN("mixer device not available !\n");
1523 return MMSYSERR_NOTENABLED;
1525 if (ioctl(mixer, SOUND_MIXER_READ_LINE, &volume) == -1)
1527 close(mixer);
1528 WARN("unable to read mixer !\n");
1529 return MMSYSERR_NOTENABLED;
1531 close(mixer);
1532 caps->wMid = 0xAA;
1533 caps->wPid = 0x55 + dev_id;
1534 caps->vDriverVersion = 0x0100;
1535 memcpy(caps->szPname, ini, sizeof(ini));
1536 caps->szPname[9] = '0' + dev_id; /* 6 at max */
1537 caps->wTechnology = (dev_id == 2) ? AUXCAPS_CDAUDIO : AUXCAPS_AUXIN;
1538 caps->wReserved1 = 0;
1539 caps->dwSupport = AUXCAPS_VOLUME | AUXCAPS_LRVOLUME;
1541 return MMSYSERR_NOERROR;
1544 static UINT aux_get_volume(WORD dev_id, UINT *vol)
1546 int mixer, volume, left, right, cmd;
1548 TRACE("(%04X, %p);\n", dev_id, vol);
1549 if (vol == NULL) return MMSYSERR_NOTENABLED;
1550 if ((mixer = open(MIXER_DEV, O_RDWR)) < 0)
1552 WARN("mixer device not available !\n");
1553 return MMSYSERR_NOTENABLED;
1555 switch(dev_id)
1557 case 0:
1558 TRACE("SOUND_MIXER_READ_PCM !\n");
1559 cmd = SOUND_MIXER_READ_PCM;
1560 break;
1561 case 1:
1562 TRACE("SOUND_MIXER_READ_SYNTH !\n");
1563 cmd = SOUND_MIXER_READ_SYNTH;
1564 break;
1565 case 2:
1566 TRACE("SOUND_MIXER_READ_CD !\n");
1567 cmd = SOUND_MIXER_READ_CD;
1568 break;
1569 case 3:
1570 TRACE("SOUND_MIXER_READ_LINE !\n");
1571 cmd = SOUND_MIXER_READ_LINE;
1572 break;
1573 case 4:
1574 TRACE("SOUND_MIXER_READ_MIC !\n");
1575 cmd = SOUND_MIXER_READ_MIC;
1576 break;
1577 case 5:
1578 TRACE("SOUND_MIXER_READ_VOLUME !\n");
1579 cmd = SOUND_MIXER_READ_VOLUME;
1580 break;
1581 default:
1582 WARN("invalid device id=%04X !\n", dev_id);
1583 close(mixer);
1584 return MMSYSERR_NOTENABLED;
1586 if (ioctl(mixer, cmd, &volume) == -1)
1588 WARN("unable to read mixer !\n");
1589 close(mixer);
1590 return MMSYSERR_NOTENABLED;
1592 close(mixer);
1593 left = LOBYTE(LOWORD(volume));
1594 right = HIBYTE(LOWORD(volume));
1595 TRACE("left=%d right=%d !\n", left, right);
1596 *vol = MAKELONG((left * 0xFFFFL) / 100, (right * 0xFFFFL) / 100);
1597 return MMSYSERR_NOERROR;
1600 static UINT aux_set_volume(WORD dev_id, UINT vol)
1602 int mixer;
1603 int volume, left, right;
1604 int cmd;
1606 TRACE("(%04X, %08X);\n", dev_id, vol);
1608 left = (LOWORD(vol) * 100) >> 16;
1609 right = (HIWORD(vol) * 100) >> 16;
1610 volume = (right << 8) | left;
1612 if ((mixer = open(MIXER_DEV, O_RDWR)) < 0)
1614 WARN("mixer device not available !\n");
1615 return MMSYSERR_NOTENABLED;
1618 switch(dev_id)
1620 case 0:
1621 TRACE("SOUND_MIXER_WRITE_PCM !\n");
1622 cmd = SOUND_MIXER_WRITE_PCM;
1623 break;
1624 case 1:
1625 TRACE("SOUND_MIXER_WRITE_SYNTH !\n");
1626 cmd = SOUND_MIXER_WRITE_SYNTH;
1627 break;
1628 case 2:
1629 TRACE("SOUND_MIXER_WRITE_CD !\n");
1630 cmd = SOUND_MIXER_WRITE_CD;
1631 break;
1632 case 3:
1633 TRACE("SOUND_MIXER_WRITE_LINE !\n");
1634 cmd = SOUND_MIXER_WRITE_LINE;
1635 break;
1636 case 4:
1637 TRACE("SOUND_MIXER_WRITE_MIC !\n");
1638 cmd = SOUND_MIXER_WRITE_MIC;
1639 break;
1640 case 5:
1641 TRACE("SOUND_MIXER_WRITE_VOLUME !\n");
1642 cmd = SOUND_MIXER_WRITE_VOLUME;
1643 break;
1644 default:
1645 WARN("invalid device id=%04X !\n", dev_id);
1646 close(mixer);
1647 return MMSYSERR_NOTENABLED;
1649 if (ioctl(mixer, cmd, &volume) == -1)
1651 WARN("unable to set mixer !\n");
1652 close(mixer);
1653 return MMSYSERR_NOTENABLED;
1655 close(mixer);
1656 return MMSYSERR_NOERROR;
1659 static NTSTATUS oss_aux_message(void *args)
1661 struct aux_message_params *params = args;
1663 switch (params->msg)
1665 case DRVM_INIT:
1666 *params->err = aux_init();
1667 break;
1668 case DRVM_EXIT:
1669 *params->err = aux_exit();
1670 break;
1671 case DRVM_ENABLE:
1672 case DRVM_DISABLE:
1673 /* FIXME: Pretend this is supported */
1674 *params->err = 0;
1675 break;
1676 case AUXDM_GETDEVCAPS:
1677 *params->err = aux_get_devcaps(params->dev_id, (AUXCAPSW *)params->param_1, params->param_2);
1678 break;
1679 case AUXDM_GETNUMDEVS:
1680 TRACE("return %d;\n", num_aux);
1681 *params->err = num_aux;
1682 break;
1683 case AUXDM_GETVOLUME:
1684 *params->err = aux_get_volume(params->dev_id, (UINT *)params->param_1);
1685 break;
1686 case AUXDM_SETVOLUME:
1687 *params->err = aux_set_volume(params->dev_id, params->param_1);
1688 break;
1689 default:
1690 WARN("unknown message !\n");
1691 *params->err = MMSYSERR_NOTSUPPORTED;
1692 break;
1695 return STATUS_SUCCESS;
1698 unixlib_entry_t __wine_unix_call_funcs[] =
1700 oss_process_attach,
1701 oss_not_implemented,
1702 oss_main_loop,
1703 oss_get_endpoint_ids,
1704 oss_create_stream,
1705 oss_release_stream,
1706 oss_start,
1707 oss_stop,
1708 oss_reset,
1709 oss_timer_loop,
1710 oss_get_render_buffer,
1711 oss_release_render_buffer,
1712 oss_get_capture_buffer,
1713 oss_release_capture_buffer,
1714 oss_is_format_supported,
1715 oss_get_mix_format,
1716 oss_get_device_period,
1717 oss_get_buffer_size,
1718 oss_get_latency,
1719 oss_get_current_padding,
1720 oss_get_next_packet_size,
1721 oss_get_frequency,
1722 oss_get_position,
1723 oss_set_volumes,
1724 oss_set_event_handle,
1725 oss_test_connect,
1726 oss_is_started,
1727 oss_not_implemented,
1728 oss_not_implemented,
1729 oss_midi_release,
1730 oss_midi_out_message,
1731 oss_midi_in_message,
1732 oss_midi_notify_wait,
1733 oss_aux_message,
1736 #ifdef _WIN64
1738 typedef UINT PTR32;
1740 static NTSTATUS oss_wow64_test_connect(void *args)
1742 struct
1744 PTR32 name;
1745 enum driver_priority priority;
1746 } *params32 = args;
1747 struct test_connect_params params =
1749 .name = ULongToPtr(params32->name),
1751 oss_test_connect(&params);
1752 params32->priority = params.priority;
1753 return STATUS_SUCCESS;
1756 static NTSTATUS oss_wow64_main_loop(void *args)
1758 struct
1760 PTR32 event;
1761 } *params32 = args;
1762 struct main_loop_params params =
1764 .event = ULongToHandle(params32->event)
1766 return oss_main_loop(&params);
1769 static NTSTATUS oss_wow64_get_endpoint_ids(void *args)
1771 struct
1773 EDataFlow flow;
1774 PTR32 endpoints;
1775 unsigned int size;
1776 HRESULT result;
1777 unsigned int num;
1778 unsigned int default_idx;
1779 } *params32 = args;
1780 struct get_endpoint_ids_params params =
1782 .flow = params32->flow,
1783 .endpoints = ULongToPtr(params32->endpoints),
1784 .size = params32->size
1786 oss_get_endpoint_ids(&params);
1787 params32->size = params.size;
1788 params32->result = params.result;
1789 params32->num = params.num;
1790 params32->default_idx = params.default_idx;
1791 return STATUS_SUCCESS;
1794 static NTSTATUS oss_wow64_create_stream(void *args)
1796 struct
1798 PTR32 name;
1799 PTR32 device;
1800 EDataFlow flow;
1801 AUDCLNT_SHAREMODE share;
1802 UINT flags;
1803 REFERENCE_TIME duration;
1804 REFERENCE_TIME period;
1805 PTR32 fmt;
1806 HRESULT result;
1807 PTR32 channel_count;
1808 PTR32 stream;
1809 } *params32 = args;
1810 struct create_stream_params params =
1812 .name = ULongToPtr(params32->name),
1813 .device = ULongToPtr(params32->device),
1814 .flow = params32->flow,
1815 .share = params32->share,
1816 .flags = params32->flags,
1817 .duration = params32->duration,
1818 .period = params32->period,
1819 .fmt = ULongToPtr(params32->fmt),
1820 .channel_count = ULongToPtr(params32->channel_count),
1821 .stream = ULongToPtr(params32->stream)
1823 oss_create_stream(&params);
1824 params32->result = params.result;
1825 return STATUS_SUCCESS;
1828 static NTSTATUS oss_wow64_release_stream(void *args)
1830 struct
1832 stream_handle stream;
1833 PTR32 timer_thread;
1834 HRESULT result;
1835 } *params32 = args;
1836 struct release_stream_params params =
1838 .stream = params32->stream,
1839 .timer_thread = ULongToHandle(params32->timer_thread)
1841 oss_release_stream(&params);
1842 params32->result = params.result;
1843 return STATUS_SUCCESS;
1846 static NTSTATUS oss_wow64_get_render_buffer(void *args)
1848 struct
1850 stream_handle stream;
1851 UINT32 frames;
1852 HRESULT result;
1853 PTR32 data;
1854 } *params32 = args;
1855 BYTE *data = NULL;
1856 struct get_render_buffer_params params =
1858 .stream = params32->stream,
1859 .frames = params32->frames,
1860 .data = &data
1862 oss_get_render_buffer(&params);
1863 params32->result = params.result;
1864 *(unsigned int *)ULongToPtr(params32->data) = PtrToUlong(data);
1865 return STATUS_SUCCESS;
1868 static NTSTATUS oss_wow64_get_capture_buffer(void *args)
1870 struct
1872 stream_handle stream;
1873 HRESULT result;
1874 PTR32 data;
1875 PTR32 frames;
1876 PTR32 flags;
1877 PTR32 devpos;
1878 PTR32 qpcpos;
1879 } *params32 = args;
1880 BYTE *data = NULL;
1881 struct get_capture_buffer_params params =
1883 .stream = params32->stream,
1884 .data = &data,
1885 .frames = ULongToPtr(params32->frames),
1886 .flags = ULongToPtr(params32->flags),
1887 .devpos = ULongToPtr(params32->devpos),
1888 .qpcpos = ULongToPtr(params32->qpcpos)
1890 oss_get_capture_buffer(&params);
1891 params32->result = params.result;
1892 *(unsigned int *)ULongToPtr(params32->data) = PtrToUlong(data);
1893 return STATUS_SUCCESS;
1896 static NTSTATUS oss_wow64_is_format_supported(void *args)
1898 struct
1900 PTR32 device;
1901 EDataFlow flow;
1902 AUDCLNT_SHAREMODE share;
1903 PTR32 fmt_in;
1904 PTR32 fmt_out;
1905 HRESULT result;
1906 } *params32 = args;
1907 struct is_format_supported_params params =
1909 .device = ULongToPtr(params32->device),
1910 .flow = params32->flow,
1911 .share = params32->share,
1912 .fmt_in = ULongToPtr(params32->fmt_in),
1913 .fmt_out = ULongToPtr(params32->fmt_out)
1915 oss_is_format_supported(&params);
1916 params32->result = params.result;
1917 return STATUS_SUCCESS;
1920 static NTSTATUS oss_wow64_get_mix_format(void *args)
1922 struct
1924 PTR32 device;
1925 EDataFlow flow;
1926 PTR32 fmt;
1927 HRESULT result;
1928 } *params32 = args;
1929 struct get_mix_format_params params =
1931 .device = ULongToPtr(params32->device),
1932 .flow = params32->flow,
1933 .fmt = ULongToPtr(params32->fmt)
1935 oss_get_mix_format(&params);
1936 params32->result = params.result;
1937 return STATUS_SUCCESS;
1940 static NTSTATUS oss_wow64_get_device_period(void *args)
1942 struct
1944 PTR32 device;
1945 EDataFlow flow;
1946 HRESULT result;
1947 PTR32 def_period;
1948 PTR32 min_period;
1949 } *params32 = args;
1950 struct get_device_period_params params =
1952 .device = ULongToPtr(params32->device),
1953 .flow = params32->flow,
1954 .def_period = ULongToPtr(params32->def_period),
1955 .min_period = ULongToPtr(params32->min_period),
1957 oss_get_device_period(&params);
1958 params32->result = params.result;
1959 return STATUS_SUCCESS;
1962 static NTSTATUS oss_wow64_get_buffer_size(void *args)
1964 struct
1966 stream_handle stream;
1967 HRESULT result;
1968 PTR32 frames;
1969 } *params32 = args;
1970 struct get_buffer_size_params params =
1972 .stream = params32->stream,
1973 .frames = ULongToPtr(params32->frames)
1975 oss_get_buffer_size(&params);
1976 params32->result = params.result;
1977 return STATUS_SUCCESS;
1980 static NTSTATUS oss_wow64_get_latency(void *args)
1982 struct
1984 stream_handle stream;
1985 HRESULT result;
1986 PTR32 latency;
1987 } *params32 = args;
1988 struct get_latency_params params =
1990 .stream = params32->stream,
1991 .latency = ULongToPtr(params32->latency)
1993 oss_get_latency(&params);
1994 params32->result = params.result;
1995 return STATUS_SUCCESS;
1998 static NTSTATUS oss_wow64_get_current_padding(void *args)
2000 struct
2002 stream_handle stream;
2003 HRESULT result;
2004 PTR32 padding;
2005 } *params32 = args;
2006 struct get_current_padding_params params =
2008 .stream = params32->stream,
2009 .padding = ULongToPtr(params32->padding)
2011 oss_get_current_padding(&params);
2012 params32->result = params.result;
2013 return STATUS_SUCCESS;
2016 static NTSTATUS oss_wow64_get_next_packet_size(void *args)
2018 struct
2020 stream_handle stream;
2021 HRESULT result;
2022 PTR32 frames;
2023 } *params32 = args;
2024 struct get_next_packet_size_params params =
2026 .stream = params32->stream,
2027 .frames = ULongToPtr(params32->frames)
2029 oss_get_next_packet_size(&params);
2030 params32->result = params.result;
2031 return STATUS_SUCCESS;
2034 static NTSTATUS oss_wow64_get_frequency(void *args)
2036 struct
2038 stream_handle stream;
2039 HRESULT result;
2040 PTR32 freq;
2041 } *params32 = args;
2042 struct get_frequency_params params =
2044 .stream = params32->stream,
2045 .freq = ULongToPtr(params32->freq)
2047 oss_get_frequency(&params);
2048 params32->result = params.result;
2049 return STATUS_SUCCESS;
2052 static NTSTATUS oss_wow64_get_position(void *args)
2054 struct
2056 stream_handle stream;
2057 BOOL device;
2058 HRESULT result;
2059 PTR32 pos;
2060 PTR32 qpctime;
2061 } *params32 = args;
2062 struct get_position_params params =
2064 .stream = params32->stream,
2065 .device = params32->device,
2066 .pos = ULongToPtr(params32->pos),
2067 .qpctime = ULongToPtr(params32->qpctime)
2069 oss_get_position(&params);
2070 params32->result = params.result;
2071 return STATUS_SUCCESS;
2074 static NTSTATUS oss_wow64_set_volumes(void *args)
2076 struct
2078 stream_handle stream;
2079 float master_volume;
2080 PTR32 volumes;
2081 PTR32 session_volumes;
2082 } *params32 = args;
2083 struct set_volumes_params params =
2085 .stream = params32->stream,
2086 .master_volume = params32->master_volume,
2087 .volumes = ULongToPtr(params32->volumes),
2088 .session_volumes = ULongToPtr(params32->session_volumes),
2090 return oss_set_volumes(&params);
2093 static NTSTATUS oss_wow64_set_event_handle(void *args)
2095 struct
2097 stream_handle stream;
2098 PTR32 event;
2099 HRESULT result;
2100 } *params32 = args;
2101 struct set_event_handle_params params =
2103 .stream = params32->stream,
2104 .event = ULongToHandle(params32->event)
2107 oss_set_event_handle(&params);
2108 params32->result = params.result;
2109 return STATUS_SUCCESS;
2112 static NTSTATUS oss_wow64_aux_message(void *args)
2114 struct
2116 UINT dev_id;
2117 UINT msg;
2118 UINT user;
2119 UINT param_1;
2120 UINT param_2;
2121 PTR32 err;
2122 } *params32 = args;
2123 struct aux_message_params params =
2125 .dev_id = params32->dev_id,
2126 .msg = params32->msg,
2127 .user = params32->user,
2128 .param_1 = params32->param_1,
2129 .param_2 = params32->param_2,
2130 .err = ULongToPtr(params32->err),
2132 return oss_aux_message(&params);
2135 unixlib_entry_t __wine_unix_call_wow64_funcs[] =
2137 oss_process_attach,
2138 oss_not_implemented,
2139 oss_wow64_main_loop,
2140 oss_wow64_get_endpoint_ids,
2141 oss_wow64_create_stream,
2142 oss_wow64_release_stream,
2143 oss_start,
2144 oss_stop,
2145 oss_reset,
2146 oss_timer_loop,
2147 oss_wow64_get_render_buffer,
2148 oss_release_render_buffer,
2149 oss_wow64_get_capture_buffer,
2150 oss_release_capture_buffer,
2151 oss_wow64_is_format_supported,
2152 oss_wow64_get_mix_format,
2153 oss_wow64_get_device_period,
2154 oss_wow64_get_buffer_size,
2155 oss_wow64_get_latency,
2156 oss_wow64_get_current_padding,
2157 oss_wow64_get_next_packet_size,
2158 oss_wow64_get_frequency,
2159 oss_wow64_get_position,
2160 oss_wow64_set_volumes,
2161 oss_wow64_set_event_handle,
2162 oss_wow64_test_connect,
2163 oss_is_started,
2164 oss_not_implemented,
2165 oss_not_implemented,
2166 oss_midi_release,
2167 oss_wow64_midi_out_message,
2168 oss_wow64_midi_in_message,
2169 oss_wow64_midi_notify_wait,
2170 oss_wow64_aux_message,
2173 #endif /* _WIN64 */