wineoss: Switch to mmdevapi's unixlib.h.
[wine.git] / dlls / wineoss.drv / oss.c
blob221e4e2ff713b59c486f613cde99cc1c11e2888c
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 /* copied from kernelbase */
73 static int muldiv( int a, int b, int c )
75 LONGLONG ret;
77 if (!c) return -1;
79 /* We want to deal with a positive divisor to simplify the logic. */
80 if (c < 0)
82 a = -a;
83 c = -c;
86 /* If the result is positive, we "add" to round. else, we subtract to round. */
87 if ((a < 0 && b < 0) || (a >= 0 && b >= 0))
88 ret = (((LONGLONG)a * b) + (c / 2)) / c;
89 else
90 ret = (((LONGLONG)a * b) - (c / 2)) / c;
92 if (ret > 2147483647 || ret < -2147483647) return -1;
93 return ret;
96 static void oss_lock(struct oss_stream *stream)
98 pthread_mutex_lock(&stream->lock);
101 static void oss_unlock(struct oss_stream *stream)
103 pthread_mutex_unlock(&stream->lock);
106 static NTSTATUS oss_unlock_result(struct oss_stream *stream,
107 HRESULT *result, HRESULT value)
109 *result = value;
110 oss_unlock(stream);
111 return STATUS_SUCCESS;
114 static struct oss_stream *handle_get_stream(stream_handle h)
116 return (struct oss_stream *)(UINT_PTR)h;
119 static NTSTATUS oss_test_connect(void *args)
121 struct test_connect_params *params = args;
122 int mixer_fd;
123 oss_sysinfo sysinfo;
125 /* Attempt to determine if we are running on OSS or ALSA's OSS
126 * compatibility layer. There is no official way to do that, so just check
127 * for validity as best as possible, without rejecting valid OSS
128 * implementations. */
130 mixer_fd = open("/dev/mixer", O_RDONLY, 0);
131 if(mixer_fd < 0){
132 TRACE("Priority_Unavailable: open failed\n");
133 params->priority = Priority_Unavailable;
134 return STATUS_SUCCESS;
137 sysinfo.version[0] = 0xFF;
138 sysinfo.versionnum = ~0;
139 if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){
140 TRACE("Priority_Unavailable: ioctl failed\n");
141 close(mixer_fd);
142 params->priority = Priority_Unavailable;
143 return STATUS_SUCCESS;
146 close(mixer_fd);
148 if(sysinfo.version[0] < '4' || sysinfo.version[0] > '9'){
149 TRACE("Priority_Low: sysinfo.version[0]: %x\n", sysinfo.version[0]);
150 params->priority = Priority_Low;
151 return STATUS_SUCCESS;
153 if(sysinfo.versionnum & 0x80000000){
154 TRACE("Priority_Low: sysinfo.versionnum: %x\n", sysinfo.versionnum);
155 params->priority = Priority_Low;
156 return STATUS_SUCCESS;
159 TRACE("Priority_Preferred: Seems like valid OSS!\n");
161 params->priority = Priority_Preferred;
162 return STATUS_SUCCESS;
165 /* dst must be large enough to hold devnode */
166 static void oss_clean_devnode(char *dest, const char *devnode)
168 const char *dot, *slash;
169 size_t len;
171 strcpy(dest, devnode);
172 dot = strrchr(dest, '.');
173 if(!dot)
174 return;
176 slash = strrchr(dest, '/');
177 if(slash && dot < slash)
178 return;
180 len = dot - dest;
181 dest[len] = '\0';
184 static int open_device(const char *device, EDataFlow flow)
186 int flags = ((flow == eRender) ? O_WRONLY : O_RDONLY) | O_NONBLOCK;
188 return open(device, flags, 0);
191 static void get_default_device(EDataFlow flow, char device[OSS_DEVNODE_SIZE])
193 int fd, err;
194 oss_audioinfo ai;
196 device[0] = '\0';
197 fd = open_device("/dev/dsp", flow);
198 if(fd < 0){
199 WARN("Couldn't open default device!\n");
200 return;
203 ai.dev = -1;
204 if((err = ioctl(fd, SNDCTL_ENGINEINFO, &ai)) < 0){
205 WARN("SNDCTL_ENGINEINFO failed: %d (%s)\n", err, strerror(errno));
206 close(fd);
207 return;
209 close(fd);
211 TRACE("Default devnode: %s\n", ai.devnode);
212 oss_clean_devnode(device, ai.devnode);
213 return;
216 static NTSTATUS oss_get_endpoint_ids(void *args)
218 struct get_endpoint_ids_params *params = args;
219 oss_sysinfo sysinfo;
220 oss_audioinfo ai;
221 static int print_once = 0;
222 static const WCHAR outW[] = {'O','u','t',':',' ',0};
223 static const WCHAR inW[] = {'I','n',':',' ',0};
224 struct endpoint_info
226 WCHAR name[ARRAY_SIZE(ai.name) + ARRAY_SIZE(outW)];
227 char device[OSS_DEVNODE_SIZE];
228 } *info;
229 unsigned int i, j, num, needed, name_len, device_len, offset, default_idx = 0;
230 char default_device[OSS_DEVNODE_SIZE];
231 struct endpoint *endpoint;
232 int mixer_fd;
234 mixer_fd = open("/dev/mixer", O_RDONLY, 0);
235 if(mixer_fd < 0){
236 ERR("OSS /dev/mixer doesn't seem to exist\n");
237 params->result = AUDCLNT_E_SERVICE_NOT_RUNNING;
238 return STATUS_SUCCESS;
241 if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){
242 close(mixer_fd);
243 if(errno == EINVAL){
244 ERR("OSS version too old, need at least OSSv4\n");
245 params->result = AUDCLNT_E_SERVICE_NOT_RUNNING;
246 return STATUS_SUCCESS;
249 ERR("Error getting SNDCTL_SYSINFO: %d (%s)\n", errno, strerror(errno));
250 params->result = E_FAIL;
251 return STATUS_SUCCESS;
254 if(!print_once){
255 TRACE("OSS sysinfo:\n");
256 TRACE("product: %s\n", sysinfo.product);
257 TRACE("version: %s\n", sysinfo.version);
258 TRACE("versionnum: %x\n", sysinfo.versionnum);
259 TRACE("numaudios: %d\n", sysinfo.numaudios);
260 TRACE("nummixers: %d\n", sysinfo.nummixers);
261 TRACE("numcards: %d\n", sysinfo.numcards);
262 TRACE("numaudioengines: %d\n", sysinfo.numaudioengines);
263 print_once = 1;
266 if(sysinfo.numaudios <= 0){
267 WARN("No audio devices!\n");
268 close(mixer_fd);
269 params->result = AUDCLNT_E_SERVICE_NOT_RUNNING;
270 return STATUS_SUCCESS;
273 info = malloc(sysinfo.numaudios * sizeof(*info));
274 if(!info){
275 close(mixer_fd);
276 params->result = E_OUTOFMEMORY;
277 return STATUS_SUCCESS;
280 get_default_device(params->flow, default_device);
282 num = 0;
283 for(i = 0; i < sysinfo.numaudios; ++i){
284 char devnode[OSS_DEVNODE_SIZE];
285 int fd, prefix_len;
286 const WCHAR *prefix;
288 memset(&ai, 0, sizeof(ai));
289 ai.dev = i;
290 if(ioctl(mixer_fd, SNDCTL_AUDIOINFO, &ai) < 0){
291 WARN("Error getting AUDIOINFO for dev %d: %d (%s)\n", i, errno,
292 strerror(errno));
293 continue;
296 oss_clean_devnode(devnode, ai.devnode);
298 /* check for duplicates */
299 for(j = 0; j < num; j++)
300 if(!strcmp(devnode, info[j].device))
301 break;
302 if(j < num)
303 continue;
305 fd = open_device(devnode, params->flow);
306 if(fd < 0){
307 WARN("Opening device \"%s\" failed, pretending it doesn't exist: %d (%s)\n",
308 devnode, errno, strerror(errno));
309 continue;
311 close(fd);
313 if((params->flow == eCapture && !(ai.caps & PCM_CAP_INPUT)) ||
314 (params->flow == eRender && !(ai.caps & PCM_CAP_OUTPUT)))
315 continue;
317 strcpy(info[num].device, devnode);
319 if(params->flow == eRender){
320 prefix = outW;
321 prefix_len = ARRAY_SIZE(outW) - 1;
322 }else{
323 prefix = inW;
324 prefix_len = ARRAY_SIZE(inW) - 1;
326 memcpy(info[num].name, prefix, prefix_len * sizeof(WCHAR));
327 ntdll_umbstowcs(ai.name, strlen(ai.name) + 1, info[num].name + prefix_len,
328 ARRAY_SIZE(info[num].name) - prefix_len);
329 if(!strcmp(default_device, info[num].device))
330 default_idx = num;
331 num++;
333 close(mixer_fd);
335 offset = needed = num * sizeof(*params->endpoints);
336 endpoint = params->endpoints;
338 for(i = 0; i < num; i++){
339 name_len = wcslen(info[i].name) + 1;
340 device_len = strlen(info[i].device) + 1;
341 needed += name_len * sizeof(WCHAR) + ((device_len + 1) & ~1);
343 if(needed <= params->size){
344 endpoint->name = offset;
345 memcpy((char *)params->endpoints + offset, info[i].name, name_len * sizeof(WCHAR));
346 offset += name_len * sizeof(WCHAR);
347 endpoint->device = offset;
348 memcpy((char *)params->endpoints + offset, info[i].device, device_len);
349 offset += (device_len + 1) & ~1;
350 endpoint++;
353 free(info);
355 params->num = num;
356 params->default_idx = default_idx;
358 if(needed > params->size){
359 params->size = needed;
360 params->result = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
361 } else
362 params->result = S_OK;
364 return STATUS_SUCCESS;
367 static UINT get_channel_mask(unsigned int channels)
369 switch(channels){
370 case 0:
371 return 0;
372 case 1:
373 return KSAUDIO_SPEAKER_MONO;
374 case 2:
375 return KSAUDIO_SPEAKER_STEREO;
376 case 3:
377 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
378 case 4:
379 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
380 case 5:
381 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
382 case 6:
383 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
384 case 7:
385 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
386 case 8:
387 return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
389 FIXME("Unknown speaker configuration: %u\n", channels);
390 return 0;
393 static int get_oss_format(const WAVEFORMATEX *fmt)
395 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)fmt;
397 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
398 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
399 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
400 switch(fmt->wBitsPerSample){
401 case 8:
402 return AFMT_U8;
403 case 16:
404 return AFMT_S16_LE;
405 case 24:
406 return AFMT_S24_LE;
407 case 32:
408 return AFMT_S32_LE;
410 return -1;
413 #ifdef AFMT_FLOAT
414 if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
415 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
416 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
417 if(fmt->wBitsPerSample != 32)
418 return -1;
420 return AFMT_FLOAT;
422 #endif
424 return -1;
427 static WAVEFORMATEXTENSIBLE *clone_format(const WAVEFORMATEX *fmt)
429 WAVEFORMATEXTENSIBLE *ret;
430 size_t size;
432 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
433 size = sizeof(WAVEFORMATEXTENSIBLE);
434 else
435 size = sizeof(WAVEFORMATEX);
437 ret = malloc(size);
438 if(!ret)
439 return NULL;
441 memcpy(ret, fmt, size);
443 ret->Format.cbSize = size - sizeof(WAVEFORMATEX);
445 return ret;
448 static HRESULT setup_oss_device(AUDCLNT_SHAREMODE share, int fd,
449 const WAVEFORMATEX *fmt, WAVEFORMATEXTENSIBLE *out)
451 const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
452 int tmp, oss_format;
453 double tenth;
454 HRESULT ret = S_OK;
455 WAVEFORMATEXTENSIBLE *closest;
457 tmp = oss_format = get_oss_format(fmt);
458 if(oss_format < 0)
459 return AUDCLNT_E_UNSUPPORTED_FORMAT;
460 if(ioctl(fd, SNDCTL_DSP_SETFMT, &tmp) < 0){
461 WARN("SETFMT failed: %d (%s)\n", errno, strerror(errno));
462 return E_FAIL;
464 if(tmp != oss_format){
465 TRACE("Format unsupported by this OSS version: %x\n", oss_format);
466 return AUDCLNT_E_UNSUPPORTED_FORMAT;
469 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
470 (fmtex->Format.nAvgBytesPerSec == 0 ||
471 fmtex->Format.nBlockAlign == 0 ||
472 fmtex->Samples.wValidBitsPerSample > fmtex->Format.wBitsPerSample))
473 return E_INVALIDARG;
475 if(fmt->nChannels == 0)
476 return AUDCLNT_E_UNSUPPORTED_FORMAT;
478 closest = clone_format(fmt);
479 if(!closest)
480 return E_OUTOFMEMORY;
482 tmp = fmt->nSamplesPerSec;
483 if(ioctl(fd, SNDCTL_DSP_SPEED, &tmp) < 0){
484 WARN("SPEED failed: %d (%s)\n", errno, strerror(errno));
485 free(closest);
486 return E_FAIL;
488 tenth = fmt->nSamplesPerSec * 0.1;
489 if(tmp > fmt->nSamplesPerSec + tenth || tmp < fmt->nSamplesPerSec - tenth){
490 ret = S_FALSE;
491 closest->Format.nSamplesPerSec = tmp;
494 tmp = fmt->nChannels;
495 if(ioctl(fd, SNDCTL_DSP_CHANNELS, &tmp) < 0){
496 WARN("CHANNELS failed: %d (%s)\n", errno, strerror(errno));
497 free(closest);
498 return E_FAIL;
500 if(tmp != fmt->nChannels){
501 ret = S_FALSE;
502 closest->Format.nChannels = tmp;
505 if(closest->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
506 closest->dwChannelMask = get_channel_mask(closest->Format.nChannels);
508 if(fmt->nBlockAlign != fmt->nChannels * fmt->wBitsPerSample / 8 ||
509 fmt->nAvgBytesPerSec != fmt->nBlockAlign * fmt->nSamplesPerSec ||
510 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
511 fmtex->Samples.wValidBitsPerSample < fmtex->Format.wBitsPerSample))
512 ret = S_FALSE;
514 if(share == AUDCLNT_SHAREMODE_EXCLUSIVE &&
515 fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
516 if(fmtex->dwChannelMask == 0 || fmtex->dwChannelMask & SPEAKER_RESERVED)
517 ret = S_FALSE;
520 if(ret == S_FALSE && !out)
521 ret = AUDCLNT_E_UNSUPPORTED_FORMAT;
523 if(ret == S_FALSE && out){
524 closest->Format.nBlockAlign =
525 closest->Format.nChannels * closest->Format.wBitsPerSample / 8;
526 closest->Format.nAvgBytesPerSec =
527 closest->Format.nBlockAlign * closest->Format.nSamplesPerSec;
528 if(closest->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
529 closest->Samples.wValidBitsPerSample = closest->Format.wBitsPerSample;
530 memcpy(out, closest, closest->Format.cbSize + sizeof(WAVEFORMATEX));
532 free(closest);
534 TRACE("returning: %08x\n", (unsigned)ret);
535 return ret;
538 static ULONG_PTR zero_bits(void)
540 #ifdef _WIN64
541 return !NtCurrentTeb()->WowTebOffset ? 0 : 0x7fffffff;
542 #else
543 return 0;
544 #endif
547 static NTSTATUS oss_create_stream(void *args)
549 struct create_stream_params *params = args;
550 WAVEFORMATEXTENSIBLE *fmtex;
551 struct oss_stream *stream;
552 oss_audioinfo ai;
553 SIZE_T size;
555 stream = calloc(1, sizeof(*stream));
556 if(!stream){
557 params->result = E_OUTOFMEMORY;
558 return STATUS_SUCCESS;
561 stream->flow = params->flow;
562 pthread_mutex_init(&stream->lock, NULL);
564 stream->fd = open_device(params->device, params->flow);
565 if(stream->fd < 0){
566 WARN("Unable to open device %s: %d (%s)\n", params->device, errno, strerror(errno));
567 params->result = AUDCLNT_E_DEVICE_INVALIDATED;
568 goto exit;
571 ai.dev = -1;
572 if(ioctl(stream->fd, SNDCTL_ENGINEINFO, &ai) < 0){
573 WARN("Unable to get audio info for device %s: %d (%s)\n", params->device, errno, strerror(errno));
574 params->result = E_FAIL;
575 goto exit;
578 TRACE("OSS audioinfo:\n");
579 TRACE("devnode: %s\n", ai.devnode);
580 TRACE("name: %s\n", ai.name);
581 TRACE("busy: %x\n", ai.busy);
582 TRACE("caps: %x\n", ai.caps);
583 TRACE("iformats: %x\n", ai.iformats);
584 TRACE("oformats: %x\n", ai.oformats);
585 TRACE("enabled: %d\n", ai.enabled);
586 TRACE("min_rate: %d\n", ai.min_rate);
587 TRACE("max_rate: %d\n", ai.max_rate);
588 TRACE("min_channels: %d\n", ai.min_channels);
589 TRACE("max_channels: %d\n", ai.max_channels);
591 params->result = setup_oss_device(params->share, stream->fd, params->fmt, NULL);
592 if(FAILED(params->result))
593 goto exit;
595 fmtex = clone_format(params->fmt);
596 if(!fmtex){
597 params->result = E_OUTOFMEMORY;
598 goto exit;
600 stream->fmt = &fmtex->Format;
602 stream->period = params->period;
603 stream->period_frames = muldiv(params->fmt->nSamplesPerSec, params->period, 10000000);
605 stream->bufsize_frames = muldiv(params->duration, params->fmt->nSamplesPerSec, 10000000);
606 if(params->share == AUDCLNT_SHAREMODE_EXCLUSIVE)
607 stream->bufsize_frames -= stream->bufsize_frames % stream->period_frames;
608 size = stream->bufsize_frames * params->fmt->nBlockAlign;
609 if(NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, zero_bits(),
610 &size, MEM_COMMIT, PAGE_READWRITE)){
611 params->result = E_OUTOFMEMORY;
612 goto exit;
615 stream->share = params->share;
616 stream->flags = params->flags;
617 stream->oss_bufsize_bytes = 0;
619 exit:
620 if(FAILED(params->result)){
621 if(stream->fd >= 0) close(stream->fd);
622 if(stream->local_buffer){
623 size = 0;
624 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, &size, MEM_RELEASE);
626 pthread_mutex_destroy(&stream->lock);
627 free(stream->fmt);
628 free(stream);
629 }else{
630 *params->stream = (stream_handle)(UINT_PTR)stream;
633 return STATUS_SUCCESS;
636 static NTSTATUS oss_release_stream(void *args)
638 struct release_stream_params *params = args;
639 struct oss_stream *stream = handle_get_stream(params->stream);
640 SIZE_T size;
642 if(params->timer_thread){
643 stream->please_quit = TRUE;
644 NtWaitForSingleObject(params->timer_thread, FALSE, NULL);
645 NtClose(params->timer_thread);
648 close(stream->fd);
649 if(stream->local_buffer){
650 size = 0;
651 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, &size, MEM_RELEASE);
653 if(stream->tmp_buffer){
654 size = 0;
655 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, &size, MEM_RELEASE);
657 free(stream->fmt);
658 pthread_mutex_destroy(&stream->lock);
659 free(stream);
661 params->result = S_OK;
662 return STATUS_SUCCESS;
665 static NTSTATUS oss_start(void *args)
667 struct start_params *params = args;
668 struct oss_stream *stream = handle_get_stream(params->stream);
670 oss_lock(stream);
672 if((stream->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !stream->event)
673 return oss_unlock_result(stream, &params->result, AUDCLNT_E_EVENTHANDLE_NOT_SET);
675 if(stream->playing)
676 return oss_unlock_result(stream, &params->result, AUDCLNT_E_NOT_STOPPED);
678 stream->playing = TRUE;
680 return oss_unlock_result(stream, &params->result, S_OK);
683 static NTSTATUS oss_stop(void *args)
685 struct stop_params *params = args;
686 struct oss_stream *stream = handle_get_stream(params->stream);
688 oss_lock(stream);
690 if(!stream->playing)
691 return oss_unlock_result(stream, &params->result, S_FALSE);
693 stream->playing = FALSE;
694 stream->in_oss_frames = 0;
696 return oss_unlock_result(stream, &params->result, S_OK);
699 static NTSTATUS oss_reset(void *args)
701 struct reset_params *params = args;
702 struct oss_stream *stream = handle_get_stream(params->stream);
704 oss_lock(stream);
706 if(stream->playing)
707 return oss_unlock_result(stream, &params->result, AUDCLNT_E_NOT_STOPPED);
709 if(stream->getbuf_last)
710 return oss_unlock_result(stream, &params->result, AUDCLNT_E_BUFFER_OPERATION_PENDING);
712 if(stream->flow == eRender){
713 stream->written_frames = 0;
714 stream->last_pos_frames = 0;
715 }else{
716 stream->written_frames += stream->held_frames;
718 stream->held_frames = 0;
719 stream->lcl_offs_frames = 0;
720 stream->in_oss_frames = 0;
722 return oss_unlock_result(stream, &params->result, S_OK);
725 static void silence_buffer(struct oss_stream *stream, BYTE *buffer, UINT32 frames)
727 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)stream->fmt;
728 if((stream->fmt->wFormatTag == WAVE_FORMAT_PCM ||
729 (stream->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
730 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
731 stream->fmt->wBitsPerSample == 8)
732 memset(buffer, 128, frames * stream->fmt->nBlockAlign);
733 else
734 memset(buffer, 0, frames * stream->fmt->nBlockAlign);
737 static void oss_write_data(struct oss_stream *stream)
739 ssize_t written_bytes;
740 UINT32 written_frames, in_oss_frames, write_limit, max_period, write_offs_frames, new_frames;
741 SIZE_T to_write_frames, to_write_bytes, advanced;
742 audio_buf_info bi;
743 BYTE *buf;
745 if(ioctl(stream->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0){
746 WARN("GETOSPACE failed: %d (%s)\n", errno, strerror(errno));
747 return;
750 max_period = max(bi.fragsize / stream->fmt->nBlockAlign, stream->period_frames);
752 if(bi.bytes > stream->oss_bufsize_bytes){
753 TRACE("New buffer size (%u) is larger than old buffer size (%u)\n",
754 bi.bytes, stream->oss_bufsize_bytes);
755 stream->oss_bufsize_bytes = bi.bytes;
756 in_oss_frames = 0;
757 }else
758 in_oss_frames = (stream->oss_bufsize_bytes - bi.bytes) / stream->fmt->nBlockAlign;
760 if(in_oss_frames > stream->in_oss_frames){
761 TRACE("Capping reported frames from %u to %u\n",
762 in_oss_frames, stream->in_oss_frames);
763 in_oss_frames = stream->in_oss_frames;
766 write_limit = 0;
767 while(write_limit + in_oss_frames < max_period * 3)
768 write_limit += max_period;
769 if(write_limit == 0)
770 return;
772 /* vvvvvv - in_oss_frames
773 * [--xxxxxxxxxx]
774 * [xxxxxxxxxx--]
775 * ^^^^^^^^^^ - held_frames
776 * ^ - lcl_offs_frames
778 advanced = stream->in_oss_frames - in_oss_frames;
779 if(advanced > stream->held_frames)
780 advanced = stream->held_frames;
781 stream->lcl_offs_frames += advanced;
782 stream->lcl_offs_frames %= stream->bufsize_frames;
783 stream->held_frames -= advanced;
784 stream->in_oss_frames = in_oss_frames;
785 TRACE("advanced by %lu, lcl_offs: %u, held: %u, in_oss: %u\n",
786 advanced, stream->lcl_offs_frames, stream->held_frames, stream->in_oss_frames);
789 if(stream->held_frames == stream->in_oss_frames)
790 return;
792 write_offs_frames = (stream->lcl_offs_frames + stream->in_oss_frames) % stream->bufsize_frames;
793 new_frames = stream->held_frames - stream->in_oss_frames;
795 if(write_offs_frames + new_frames > stream->bufsize_frames)
796 to_write_frames = stream->bufsize_frames - write_offs_frames;
797 else
798 to_write_frames = new_frames;
800 to_write_frames = min(to_write_frames, write_limit);
801 to_write_bytes = to_write_frames * stream->fmt->nBlockAlign;
802 TRACE("going to write %lu frames from %u (%lu of %u)\n", to_write_frames,
803 write_offs_frames, to_write_frames + write_offs_frames,
804 stream->bufsize_frames);
806 buf = stream->local_buffer + write_offs_frames * stream->fmt->nBlockAlign;
808 if(stream->mute)
809 silence_buffer(stream, buf, to_write_frames);
811 written_bytes = write(stream->fd, buf, to_write_bytes);
812 if(written_bytes < 0){
813 /* EAGAIN is OSS buffer full, log that too */
814 WARN("write failed: %d (%s)\n", errno, strerror(errno));
815 return;
817 written_frames = written_bytes / stream->fmt->nBlockAlign;
819 stream->in_oss_frames += written_frames;
821 if(written_frames < to_write_frames){
822 /* OSS buffer probably full */
823 return;
826 if(new_frames > written_frames && written_frames < write_limit){
827 /* wrapped and have some data back at the start to write */
829 to_write_frames = min(write_limit - written_frames, new_frames - written_frames);
830 to_write_bytes = to_write_frames * stream->fmt->nBlockAlign;
832 if(stream->mute)
833 silence_buffer(stream, stream->local_buffer, to_write_frames);
835 TRACE("wrapping to write %lu frames from beginning\n", to_write_frames);
837 written_bytes = write(stream->fd, stream->local_buffer, to_write_bytes);
838 if(written_bytes < 0){
839 WARN("write failed: %d (%s)\n", errno, strerror(errno));
840 return;
842 written_frames = written_bytes / stream->fmt->nBlockAlign;
843 stream->in_oss_frames += written_frames;
847 static void oss_read_data(struct oss_stream *stream)
849 UINT64 pos, readable;
850 ssize_t nread;
852 pos = (stream->held_frames + stream->lcl_offs_frames) % stream->bufsize_frames;
853 readable = (stream->bufsize_frames - pos) * stream->fmt->nBlockAlign;
855 nread = read(stream->fd, stream->local_buffer + pos * stream->fmt->nBlockAlign,
856 readable);
857 if(nread < 0){
858 WARN("read failed: %d (%s)\n", errno, strerror(errno));
859 return;
862 stream->held_frames += nread / stream->fmt->nBlockAlign;
864 if(stream->held_frames > stream->bufsize_frames){
865 WARN("Overflow of unread data\n");
866 stream->lcl_offs_frames += stream->held_frames;
867 stream->lcl_offs_frames %= stream->bufsize_frames;
868 stream->held_frames = stream->bufsize_frames;
872 static NTSTATUS oss_timer_loop(void *args)
874 struct timer_loop_params *params = args;
875 struct oss_stream *stream = handle_get_stream(params->stream);
876 LARGE_INTEGER delay, now, next;
877 int adjust;
879 oss_lock(stream);
881 delay.QuadPart = -stream->period;
882 NtQueryPerformanceCounter(&now, NULL);
883 next.QuadPart = now.QuadPart + stream->period;
885 while(!stream->please_quit){
886 if(stream->playing){
887 if(stream->flow == eRender && stream->held_frames)
888 oss_write_data(stream);
889 else if(stream->flow == eCapture)
890 oss_read_data(stream);
892 if(stream->event)
893 NtSetEvent(stream->event, NULL);
894 oss_unlock(stream);
896 NtDelayExecution(FALSE, &delay);
898 oss_lock(stream);
899 NtQueryPerformanceCounter(&now, NULL);
900 adjust = next.QuadPart - now.QuadPart;
901 if(adjust > stream->period / 2)
902 adjust = stream->period / 2;
903 else if(adjust < -stream->period / 2)
904 adjust = -stream->period / 2;
905 delay.QuadPart = -(stream->period + adjust);
906 next.QuadPart += stream->period;
909 oss_unlock(stream);
911 return STATUS_SUCCESS;
914 static NTSTATUS oss_get_render_buffer(void *args)
916 struct get_render_buffer_params *params = args;
917 struct oss_stream *stream = handle_get_stream(params->stream);
918 UINT32 write_pos, frames = params->frames;
919 BYTE **data = params->data;
920 SIZE_T size;
922 oss_lock(stream);
924 if(stream->getbuf_last)
925 return oss_unlock_result(stream, &params->result, AUDCLNT_E_OUT_OF_ORDER);
927 if(!frames)
928 return oss_unlock_result(stream, &params->result, S_OK);
930 if(stream->held_frames + frames > stream->bufsize_frames)
931 return oss_unlock_result(stream, &params->result, AUDCLNT_E_BUFFER_TOO_LARGE);
933 write_pos =
934 (stream->lcl_offs_frames + stream->held_frames) % stream->bufsize_frames;
935 if(write_pos + frames > stream->bufsize_frames){
936 if(stream->tmp_buffer_frames < frames){
937 if(stream->tmp_buffer){
938 size = 0;
939 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, &size, MEM_RELEASE);
940 stream->tmp_buffer = NULL;
942 size = frames * stream->fmt->nBlockAlign;
943 if(NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, zero_bits(),
944 &size, MEM_COMMIT, PAGE_READWRITE)){
945 stream->tmp_buffer_frames = 0;
946 return oss_unlock_result(stream, &params->result, E_OUTOFMEMORY);
948 stream->tmp_buffer_frames = frames;
950 *data = stream->tmp_buffer;
951 stream->getbuf_last = -frames;
952 }else{
953 *data = stream->local_buffer + write_pos * stream->fmt->nBlockAlign;
954 stream->getbuf_last = frames;
957 silence_buffer(stream, *data, frames);
959 return oss_unlock_result(stream, &params->result, S_OK);
962 static void oss_wrap_buffer(struct oss_stream *stream, BYTE *buffer, UINT32 written_frames)
964 UINT32 write_offs_frames =
965 (stream->lcl_offs_frames + stream->held_frames) % stream->bufsize_frames;
966 UINT32 write_offs_bytes = write_offs_frames * stream->fmt->nBlockAlign;
967 UINT32 chunk_frames = stream->bufsize_frames - write_offs_frames;
968 UINT32 chunk_bytes = chunk_frames * stream->fmt->nBlockAlign;
969 UINT32 written_bytes = written_frames * stream->fmt->nBlockAlign;
971 if(written_bytes <= chunk_bytes){
972 memcpy(stream->local_buffer + write_offs_bytes, buffer, written_bytes);
973 }else{
974 memcpy(stream->local_buffer + write_offs_bytes, buffer, chunk_bytes);
975 memcpy(stream->local_buffer, buffer + chunk_bytes,
976 written_bytes - chunk_bytes);
980 static NTSTATUS oss_release_render_buffer(void *args)
982 struct release_render_buffer_params *params = args;
983 struct oss_stream *stream = handle_get_stream(params->stream);
984 UINT32 written_frames = params->written_frames;
985 UINT flags = params->flags;
986 BYTE *buffer;
988 oss_lock(stream);
990 if(!written_frames){
991 stream->getbuf_last = 0;
992 return oss_unlock_result(stream, &params->result, S_OK);
995 if(!stream->getbuf_last)
996 return oss_unlock_result(stream, &params->result, AUDCLNT_E_OUT_OF_ORDER);
998 if(written_frames > (stream->getbuf_last >= 0 ? stream->getbuf_last : -stream->getbuf_last))
999 return oss_unlock_result(stream, &params->result, AUDCLNT_E_INVALID_SIZE);
1001 if(stream->getbuf_last >= 0)
1002 buffer = stream->local_buffer + stream->fmt->nBlockAlign *
1003 ((stream->lcl_offs_frames + stream->held_frames) % stream->bufsize_frames);
1004 else
1005 buffer = stream->tmp_buffer;
1007 if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
1008 silence_buffer(stream, buffer, written_frames);
1010 if(stream->getbuf_last < 0)
1011 oss_wrap_buffer(stream, buffer, written_frames);
1013 stream->held_frames += written_frames;
1014 stream->written_frames += written_frames;
1015 stream->getbuf_last = 0;
1017 return oss_unlock_result(stream, &params->result, S_OK);
1020 static NTSTATUS oss_get_capture_buffer(void *args)
1022 struct get_capture_buffer_params *params = args;
1023 struct oss_stream *stream = handle_get_stream(params->stream);
1024 UINT64 *devpos = params->devpos, *qpcpos = params->qpcpos;
1025 UINT32 *frames = params->frames;
1026 UINT *flags = params->flags;
1027 BYTE **data = params->data;
1028 SIZE_T size;
1030 oss_lock(stream);
1032 if(stream->getbuf_last)
1033 return oss_unlock_result(stream, &params->result, AUDCLNT_E_OUT_OF_ORDER);
1035 if(stream->held_frames < stream->period_frames){
1036 *frames = 0;
1037 return oss_unlock_result(stream, &params->result, AUDCLNT_S_BUFFER_EMPTY);
1040 *flags = 0;
1042 *frames = stream->period_frames;
1044 if(stream->lcl_offs_frames + *frames > stream->bufsize_frames){
1045 UINT32 chunk_bytes, offs_bytes, frames_bytes;
1046 if(stream->tmp_buffer_frames < *frames){
1047 if(stream->tmp_buffer){
1048 size = 0;
1049 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, &size, MEM_RELEASE);
1050 stream->tmp_buffer = NULL;
1052 size = *frames * stream->fmt->nBlockAlign;
1053 if(NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, zero_bits(),
1054 &size, MEM_COMMIT, PAGE_READWRITE)){
1055 stream->tmp_buffer_frames = 0;
1056 return oss_unlock_result(stream, &params->result, E_OUTOFMEMORY);
1058 stream->tmp_buffer_frames = *frames;
1061 *data = stream->tmp_buffer;
1062 chunk_bytes = (stream->bufsize_frames - stream->lcl_offs_frames) *
1063 stream->fmt->nBlockAlign;
1064 offs_bytes = stream->lcl_offs_frames * stream->fmt->nBlockAlign;
1065 frames_bytes = *frames * stream->fmt->nBlockAlign;
1066 memcpy(stream->tmp_buffer, stream->local_buffer + offs_bytes, chunk_bytes);
1067 memcpy(stream->tmp_buffer + chunk_bytes, stream->local_buffer,
1068 frames_bytes - chunk_bytes);
1069 }else
1070 *data = stream->local_buffer +
1071 stream->lcl_offs_frames * stream->fmt->nBlockAlign;
1073 stream->getbuf_last = *frames;
1075 if(devpos)
1076 *devpos = stream->written_frames;
1077 if(qpcpos){
1078 LARGE_INTEGER stamp, freq;
1079 NtQueryPerformanceCounter(&stamp, &freq);
1080 *qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1083 return oss_unlock_result(stream, &params->result, *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY);
1086 static NTSTATUS oss_release_capture_buffer(void *args)
1088 struct release_capture_buffer_params *params = args;
1089 struct oss_stream *stream = handle_get_stream(params->stream);
1090 UINT32 done = params->done;
1092 oss_lock(stream);
1094 if(!done){
1095 stream->getbuf_last = 0;
1096 return oss_unlock_result(stream, &params->result, S_OK);
1099 if(!stream->getbuf_last)
1100 return oss_unlock_result(stream, &params->result, AUDCLNT_E_OUT_OF_ORDER);
1102 if(stream->getbuf_last != done)
1103 return oss_unlock_result(stream, &params->result, AUDCLNT_E_INVALID_SIZE);
1105 stream->written_frames += done;
1106 stream->held_frames -= done;
1107 stream->lcl_offs_frames += done;
1108 stream->lcl_offs_frames %= stream->bufsize_frames;
1109 stream->getbuf_last = 0;
1111 return oss_unlock_result(stream, &params->result, S_OK);
1114 static NTSTATUS oss_is_format_supported(void *args)
1116 struct is_format_supported_params *params = args;
1117 int fd;
1119 params->result = S_OK;
1121 if(!params->fmt_in || (params->share == AUDCLNT_SHAREMODE_SHARED && !params->fmt_out))
1122 params->result = E_POINTER;
1123 else if(params->share != AUDCLNT_SHAREMODE_SHARED && params->share != AUDCLNT_SHAREMODE_EXCLUSIVE)
1124 params->result = E_INVALIDARG;
1125 else if(params->fmt_in->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1126 params->fmt_in->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1127 params->result = E_INVALIDARG;
1128 if(FAILED(params->result))
1129 return STATUS_SUCCESS;
1131 fd = open_device(params->device, params->flow);
1132 if(fd < 0){
1133 WARN("Unable to open device %s: %d (%s)\n", params->device, errno, strerror(errno));
1134 params->result = AUDCLNT_E_DEVICE_INVALIDATED;
1135 return STATUS_SUCCESS;
1137 params->result = setup_oss_device(params->share, fd, params->fmt_in, params->fmt_out);
1138 close(fd);
1140 return STATUS_SUCCESS;
1143 static NTSTATUS oss_get_mix_format(void *args)
1145 struct get_mix_format_params *params = args;
1146 WAVEFORMATEXTENSIBLE *fmt = params->fmt;
1147 oss_audioinfo ai;
1148 int formats, fd;
1150 if(params->flow != eRender && params->flow != eCapture){
1151 params->result = E_UNEXPECTED;
1152 return STATUS_SUCCESS;
1155 fd = open_device(params->device, params->flow);
1156 if(fd < 0){
1157 WARN("Unable to open device %s: %d (%s)\n", params->device, errno, strerror(errno));
1158 params->result = AUDCLNT_E_DEVICE_INVALIDATED;
1159 return STATUS_SUCCESS;
1162 ai.dev = -1;
1163 if(ioctl(fd, SNDCTL_ENGINEINFO, &ai) < 0){
1164 WARN("Unable to get audio info for device %s: %d (%s)\n", params->device, errno, strerror(errno));
1165 close(fd);
1166 params->result = E_FAIL;
1167 return STATUS_SUCCESS;
1169 close(fd);
1171 if(params->flow == eRender)
1172 formats = ai.oformats;
1173 else
1174 formats = ai.iformats;
1176 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1177 if(formats & AFMT_S16_LE){
1178 fmt->Format.wBitsPerSample = 16;
1179 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1180 #ifdef AFMT_FLOAT
1181 }else if(formats & AFMT_FLOAT){
1182 fmt->Format.wBitsPerSample = 32;
1183 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1184 #endif
1185 }else if(formats & AFMT_U8){
1186 fmt->Format.wBitsPerSample = 8;
1187 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1188 }else if(formats & AFMT_S32_LE){
1189 fmt->Format.wBitsPerSample = 32;
1190 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1191 }else if(formats & AFMT_S24_LE){
1192 fmt->Format.wBitsPerSample = 24;
1193 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1194 }else{
1195 WARN("Didn't recognize any available OSS formats: %x\n", formats);
1196 params->result = E_FAIL;
1197 return STATUS_SUCCESS;
1200 /* some OSS drivers are buggy, so set reasonable defaults if
1201 * the reported values seem wacky */
1202 fmt->Format.nChannels = max(ai.max_channels, ai.min_channels);
1203 if(fmt->Format.nChannels == 0 || fmt->Format.nChannels > 8)
1204 fmt->Format.nChannels = 2;
1206 /* For most hardware on Windows, users must choose a configuration with an even
1207 * number of channels (stereo, quad, 5.1, 7.1). Users can then disable
1208 * channels, but those channels are still reported to applications from
1209 * GetMixFormat! Some applications behave badly if given an odd number of
1210 * channels (e.g. 2.1). */
1211 if(fmt->Format.nChannels > 1 && (fmt->Format.nChannels & 0x1))
1213 if(fmt->Format.nChannels < ai.max_channels)
1214 fmt->Format.nChannels += 1;
1215 else
1216 /* We could "fake" more channels and downmix the emulated channels,
1217 * but at that point you really ought to tweak your OSS setup or
1218 * just use PulseAudio. */
1219 WARN("Some Windows applications behave badly with an odd number of channels (%u)!\n", fmt->Format.nChannels);
1222 if(ai.max_rate == 0)
1223 fmt->Format.nSamplesPerSec = 44100;
1224 else
1225 fmt->Format.nSamplesPerSec = min(ai.max_rate, 44100);
1226 if(fmt->Format.nSamplesPerSec < ai.min_rate)
1227 fmt->Format.nSamplesPerSec = ai.min_rate;
1229 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1231 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1232 fmt->Format.nChannels) / 8;
1233 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1234 fmt->Format.nBlockAlign;
1236 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1237 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1239 params->result = S_OK;
1240 return STATUS_SUCCESS;
1243 static NTSTATUS oss_get_buffer_size(void *args)
1245 struct get_buffer_size_params *params = args;
1246 struct oss_stream *stream = handle_get_stream(params->stream);
1248 oss_lock(stream);
1250 *params->size = stream->bufsize_frames;
1252 return oss_unlock_result(stream, &params->result, S_OK);
1255 static NTSTATUS oss_get_latency(void *args)
1257 struct get_latency_params *params = args;
1258 struct oss_stream *stream = handle_get_stream(params->stream);
1260 oss_lock(stream);
1262 /* pretend we process audio in Period chunks, so max latency includes
1263 * the period time. Some native machines add .6666ms in shared mode. */
1264 *params->latency = stream->period + 6666;
1266 return oss_unlock_result(stream, &params->result, S_OK);
1269 static NTSTATUS oss_get_current_padding(void *args)
1271 struct get_current_padding_params *params = args;
1272 struct oss_stream *stream = handle_get_stream(params->stream);
1274 oss_lock(stream);
1276 *params->padding = stream->held_frames;
1278 return oss_unlock_result(stream, &params->result, S_OK);
1281 static NTSTATUS oss_get_next_packet_size(void *args)
1283 struct get_next_packet_size_params *params = args;
1284 struct oss_stream *stream = handle_get_stream(params->stream);
1285 UINT32 *frames = params->frames;
1287 oss_lock(stream);
1289 *frames = stream->held_frames < stream->period_frames ? 0 : stream->period_frames;
1291 return oss_unlock_result(stream, &params->result, S_OK);
1294 static NTSTATUS oss_get_frequency(void *args)
1296 struct get_frequency_params *params = args;
1297 struct oss_stream *stream = handle_get_stream(params->stream);
1298 UINT64 *freq = params->freq;
1300 oss_lock(stream);
1302 if(stream->share == AUDCLNT_SHAREMODE_SHARED)
1303 *freq = (UINT64)stream->fmt->nSamplesPerSec * stream->fmt->nBlockAlign;
1304 else
1305 *freq = stream->fmt->nSamplesPerSec;
1307 return oss_unlock_result(stream, &params->result, S_OK);
1310 static NTSTATUS oss_get_position(void *args)
1312 struct get_position_params *params = args;
1313 struct oss_stream *stream = handle_get_stream(params->stream);
1314 UINT64 *pos = params->pos, *qpctime = params->qpctime;
1316 oss_lock(stream);
1318 if(stream->flow == eRender){
1319 *pos = stream->written_frames - stream->held_frames;
1320 if(*pos < stream->last_pos_frames)
1321 *pos = stream->last_pos_frames;
1322 }else if(stream->flow == eCapture){
1323 audio_buf_info bi;
1324 UINT32 held;
1326 if(ioctl(stream->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
1327 TRACE("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
1328 held = 0;
1329 }else{
1330 if(bi.bytes <= bi.fragsize)
1331 held = 0;
1332 else
1333 held = bi.bytes / stream->fmt->nBlockAlign;
1336 *pos = stream->written_frames + held;
1339 stream->last_pos_frames = *pos;
1341 TRACE("returning: %s\n", wine_dbgstr_longlong(*pos));
1342 if(stream->share == AUDCLNT_SHAREMODE_SHARED)
1343 *pos *= stream->fmt->nBlockAlign;
1345 if(qpctime){
1346 LARGE_INTEGER stamp, freq;
1347 NtQueryPerformanceCounter(&stamp, &freq);
1348 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1351 return oss_unlock_result(stream, &params->result, S_OK);
1354 static NTSTATUS oss_set_volumes(void *args)
1356 struct set_volumes_params *params = args;
1357 struct oss_stream *stream = handle_get_stream(params->stream);
1359 oss_lock(stream);
1360 stream->mute = !params->master_volume;
1361 oss_unlock(stream);
1363 return STATUS_SUCCESS;
1366 static NTSTATUS oss_set_event_handle(void *args)
1368 struct set_event_handle_params *params = args;
1369 struct oss_stream *stream = handle_get_stream(params->stream);
1371 oss_lock(stream);
1373 if(!(stream->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK))
1374 return oss_unlock_result(stream, &params->result, AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED);
1376 if (stream->event){
1377 FIXME("called twice\n");
1378 return oss_unlock_result(stream, &params->result, HRESULT_FROM_WIN32(ERROR_INVALID_NAME));
1381 stream->event = params->event;
1383 return oss_unlock_result(stream, &params->result, S_OK);
1386 static NTSTATUS oss_is_started(void *args)
1388 struct is_started_params *params = args;
1389 struct oss_stream *stream = handle_get_stream(params->stream);
1391 oss_lock(stream);
1393 return oss_unlock_result(stream, &params->result, stream->playing ? S_OK : S_FALSE);
1396 /* Aux driver */
1398 static unsigned int num_aux;
1400 #define MIXER_DEV "/dev/mixer"
1402 static UINT aux_init(void)
1404 int mixer;
1406 TRACE("()\n");
1408 if ((mixer = open(MIXER_DEV, O_RDWR)) < 0)
1410 WARN("mixer device not available !\n");
1411 num_aux = 0;
1413 else
1415 close(mixer);
1416 num_aux = 6;
1418 return 0;
1421 static UINT aux_exit(void)
1423 TRACE("()\n");
1424 return 0;
1427 static UINT aux_get_devcaps(WORD dev_id, AUXCAPSW *caps, UINT size)
1429 int mixer, volume;
1430 static const WCHAR ini[] = {'O','S','S',' ','A','u','x',' ','#','0',0};
1432 TRACE("(%04X, %p, %u);\n", dev_id, caps, size);
1433 if (caps == NULL) return MMSYSERR_NOTENABLED;
1434 if (dev_id >= num_aux) return MMSYSERR_BADDEVICEID;
1435 if ((mixer = open(MIXER_DEV, O_RDWR)) < 0)
1437 WARN("mixer device not available !\n");
1438 return MMSYSERR_NOTENABLED;
1440 if (ioctl(mixer, SOUND_MIXER_READ_LINE, &volume) == -1)
1442 close(mixer);
1443 WARN("unable to read mixer !\n");
1444 return MMSYSERR_NOTENABLED;
1446 close(mixer);
1447 caps->wMid = 0xAA;
1448 caps->wPid = 0x55 + dev_id;
1449 caps->vDriverVersion = 0x0100;
1450 memcpy(caps->szPname, ini, sizeof(ini));
1451 caps->szPname[9] = '0' + dev_id; /* 6 at max */
1452 caps->wTechnology = (dev_id == 2) ? AUXCAPS_CDAUDIO : AUXCAPS_AUXIN;
1453 caps->wReserved1 = 0;
1454 caps->dwSupport = AUXCAPS_VOLUME | AUXCAPS_LRVOLUME;
1456 return MMSYSERR_NOERROR;
1459 static UINT aux_get_volume(WORD dev_id, UINT *vol)
1461 int mixer, volume, left, right, cmd;
1463 TRACE("(%04X, %p);\n", dev_id, vol);
1464 if (vol == NULL) return MMSYSERR_NOTENABLED;
1465 if ((mixer = open(MIXER_DEV, O_RDWR)) < 0)
1467 WARN("mixer device not available !\n");
1468 return MMSYSERR_NOTENABLED;
1470 switch(dev_id)
1472 case 0:
1473 TRACE("SOUND_MIXER_READ_PCM !\n");
1474 cmd = SOUND_MIXER_READ_PCM;
1475 break;
1476 case 1:
1477 TRACE("SOUND_MIXER_READ_SYNTH !\n");
1478 cmd = SOUND_MIXER_READ_SYNTH;
1479 break;
1480 case 2:
1481 TRACE("SOUND_MIXER_READ_CD !\n");
1482 cmd = SOUND_MIXER_READ_CD;
1483 break;
1484 case 3:
1485 TRACE("SOUND_MIXER_READ_LINE !\n");
1486 cmd = SOUND_MIXER_READ_LINE;
1487 break;
1488 case 4:
1489 TRACE("SOUND_MIXER_READ_MIC !\n");
1490 cmd = SOUND_MIXER_READ_MIC;
1491 break;
1492 case 5:
1493 TRACE("SOUND_MIXER_READ_VOLUME !\n");
1494 cmd = SOUND_MIXER_READ_VOLUME;
1495 break;
1496 default:
1497 WARN("invalid device id=%04X !\n", dev_id);
1498 close(mixer);
1499 return MMSYSERR_NOTENABLED;
1501 if (ioctl(mixer, cmd, &volume) == -1)
1503 WARN("unable to read mixer !\n");
1504 close(mixer);
1505 return MMSYSERR_NOTENABLED;
1507 close(mixer);
1508 left = LOBYTE(LOWORD(volume));
1509 right = HIBYTE(LOWORD(volume));
1510 TRACE("left=%d right=%d !\n", left, right);
1511 *vol = MAKELONG((left * 0xFFFFL) / 100, (right * 0xFFFFL) / 100);
1512 return MMSYSERR_NOERROR;
1515 static UINT aux_set_volume(WORD dev_id, UINT vol)
1517 int mixer;
1518 int volume, left, right;
1519 int cmd;
1521 TRACE("(%04X, %08X);\n", dev_id, vol);
1523 left = (LOWORD(vol) * 100) >> 16;
1524 right = (HIWORD(vol) * 100) >> 16;
1525 volume = (right << 8) | left;
1527 if ((mixer = open(MIXER_DEV, O_RDWR)) < 0)
1529 WARN("mixer device not available !\n");
1530 return MMSYSERR_NOTENABLED;
1533 switch(dev_id)
1535 case 0:
1536 TRACE("SOUND_MIXER_WRITE_PCM !\n");
1537 cmd = SOUND_MIXER_WRITE_PCM;
1538 break;
1539 case 1:
1540 TRACE("SOUND_MIXER_WRITE_SYNTH !\n");
1541 cmd = SOUND_MIXER_WRITE_SYNTH;
1542 break;
1543 case 2:
1544 TRACE("SOUND_MIXER_WRITE_CD !\n");
1545 cmd = SOUND_MIXER_WRITE_CD;
1546 break;
1547 case 3:
1548 TRACE("SOUND_MIXER_WRITE_LINE !\n");
1549 cmd = SOUND_MIXER_WRITE_LINE;
1550 break;
1551 case 4:
1552 TRACE("SOUND_MIXER_WRITE_MIC !\n");
1553 cmd = SOUND_MIXER_WRITE_MIC;
1554 break;
1555 case 5:
1556 TRACE("SOUND_MIXER_WRITE_VOLUME !\n");
1557 cmd = SOUND_MIXER_WRITE_VOLUME;
1558 break;
1559 default:
1560 WARN("invalid device id=%04X !\n", dev_id);
1561 close(mixer);
1562 return MMSYSERR_NOTENABLED;
1564 if (ioctl(mixer, cmd, &volume) == -1)
1566 WARN("unable to set mixer !\n");
1567 close(mixer);
1568 return MMSYSERR_NOTENABLED;
1570 close(mixer);
1571 return MMSYSERR_NOERROR;
1574 static NTSTATUS oss_aux_message(void *args)
1576 struct aux_message_params *params = args;
1578 switch (params->msg)
1580 case DRVM_INIT:
1581 *params->err = aux_init();
1582 break;
1583 case DRVM_EXIT:
1584 *params->err = aux_exit();
1585 break;
1586 case DRVM_ENABLE:
1587 case DRVM_DISABLE:
1588 /* FIXME: Pretend this is supported */
1589 *params->err = 0;
1590 break;
1591 case AUXDM_GETDEVCAPS:
1592 *params->err = aux_get_devcaps(params->dev_id, (AUXCAPSW *)params->param_1, params->param_2);
1593 break;
1594 case AUXDM_GETNUMDEVS:
1595 TRACE("return %d;\n", num_aux);
1596 *params->err = num_aux;
1597 break;
1598 case AUXDM_GETVOLUME:
1599 *params->err = aux_get_volume(params->dev_id, (UINT *)params->param_1);
1600 break;
1601 case AUXDM_SETVOLUME:
1602 *params->err = aux_set_volume(params->dev_id, params->param_1);
1603 break;
1604 default:
1605 WARN("unknown message !\n");
1606 *params->err = MMSYSERR_NOTSUPPORTED;
1607 break;
1610 return STATUS_SUCCESS;
1613 unixlib_entry_t __wine_unix_call_funcs[] =
1615 NULL,
1616 NULL,
1617 NULL,
1618 oss_get_endpoint_ids,
1619 oss_create_stream,
1620 oss_release_stream,
1621 oss_start,
1622 oss_stop,
1623 oss_reset,
1624 oss_timer_loop,
1625 oss_get_render_buffer,
1626 oss_release_render_buffer,
1627 oss_get_capture_buffer,
1628 oss_release_capture_buffer,
1629 oss_is_format_supported,
1630 oss_get_mix_format,
1631 NULL,
1632 oss_get_buffer_size,
1633 oss_get_latency,
1634 oss_get_current_padding,
1635 oss_get_next_packet_size,
1636 oss_get_frequency,
1637 oss_get_position,
1638 oss_set_volumes,
1639 oss_set_event_handle,
1640 oss_test_connect,
1641 oss_is_started,
1642 NULL,
1643 oss_midi_release,
1644 oss_midi_out_message,
1645 oss_midi_in_message,
1646 oss_midi_notify_wait,
1647 oss_aux_message,
1650 #ifdef _WIN64
1652 typedef UINT PTR32;
1654 static NTSTATUS oss_wow64_test_connect(void *args)
1656 struct
1658 PTR32 name;
1659 enum driver_priority priority;
1660 } *params32 = args;
1661 struct test_connect_params params =
1663 .name = ULongToPtr(params32->name),
1665 oss_test_connect(&params);
1666 params32->priority = params.priority;
1667 return STATUS_SUCCESS;
1670 static NTSTATUS oss_wow64_get_endpoint_ids(void *args)
1672 struct
1674 EDataFlow flow;
1675 PTR32 endpoints;
1676 unsigned int size;
1677 HRESULT result;
1678 unsigned int num;
1679 unsigned int default_idx;
1680 } *params32 = args;
1681 struct get_endpoint_ids_params params =
1683 .flow = params32->flow,
1684 .endpoints = ULongToPtr(params32->endpoints),
1685 .size = params32->size
1687 oss_get_endpoint_ids(&params);
1688 params32->size = params.size;
1689 params32->result = params.result;
1690 params32->num = params.num;
1691 params32->default_idx = params.default_idx;
1692 return STATUS_SUCCESS;
1695 static NTSTATUS oss_wow64_create_stream(void *args)
1697 struct
1699 PTR32 name;
1700 PTR32 device;
1701 EDataFlow flow;
1702 AUDCLNT_SHAREMODE share;
1703 UINT flags;
1704 REFERENCE_TIME duration;
1705 REFERENCE_TIME period;
1706 PTR32 fmt;
1707 HRESULT result;
1708 PTR32 channel_count;
1709 PTR32 stream;
1710 } *params32 = args;
1711 struct create_stream_params params =
1713 .name = ULongToPtr(params32->name),
1714 .device = ULongToPtr(params32->device),
1715 .flow = params32->flow,
1716 .share = params32->share,
1717 .flags = params32->flags,
1718 .duration = params32->duration,
1719 .period = params32->period,
1720 .fmt = ULongToPtr(params32->fmt),
1721 .channel_count = ULongToPtr(params32->channel_count),
1722 .stream = ULongToPtr(params32->stream)
1724 oss_create_stream(&params);
1725 params32->result = params.result;
1726 return STATUS_SUCCESS;
1729 static NTSTATUS oss_wow64_release_stream(void *args)
1731 struct
1733 stream_handle stream;
1734 PTR32 timer_thread;
1735 HRESULT result;
1736 } *params32 = args;
1737 struct release_stream_params params =
1739 .stream = params32->stream,
1740 .timer_thread = ULongToHandle(params32->timer_thread)
1742 oss_release_stream(&params);
1743 params32->result = params.result;
1744 return STATUS_SUCCESS;
1747 static NTSTATUS oss_wow64_get_render_buffer(void *args)
1749 struct
1751 stream_handle stream;
1752 UINT32 frames;
1753 HRESULT result;
1754 PTR32 data;
1755 } *params32 = args;
1756 BYTE *data = NULL;
1757 struct get_render_buffer_params params =
1759 .stream = params32->stream,
1760 .frames = params32->frames,
1761 .data = &data
1763 oss_get_render_buffer(&params);
1764 params32->result = params.result;
1765 *(unsigned int *)ULongToPtr(params32->data) = PtrToUlong(data);
1766 return STATUS_SUCCESS;
1769 static NTSTATUS oss_wow64_get_capture_buffer(void *args)
1771 struct
1773 stream_handle stream;
1774 HRESULT result;
1775 PTR32 data;
1776 PTR32 frames;
1777 PTR32 flags;
1778 PTR32 devpos;
1779 PTR32 qpcpos;
1780 } *params32 = args;
1781 BYTE *data = NULL;
1782 struct get_capture_buffer_params params =
1784 .stream = params32->stream,
1785 .data = &data,
1786 .frames = ULongToPtr(params32->frames),
1787 .flags = ULongToPtr(params32->flags),
1788 .devpos = ULongToPtr(params32->devpos),
1789 .qpcpos = ULongToPtr(params32->qpcpos)
1791 oss_get_capture_buffer(&params);
1792 params32->result = params.result;
1793 *(unsigned int *)ULongToPtr(params32->data) = PtrToUlong(data);
1794 return STATUS_SUCCESS;
1797 static NTSTATUS oss_wow64_is_format_supported(void *args)
1799 struct
1801 PTR32 device;
1802 EDataFlow flow;
1803 AUDCLNT_SHAREMODE share;
1804 PTR32 fmt_in;
1805 PTR32 fmt_out;
1806 HRESULT result;
1807 } *params32 = args;
1808 struct is_format_supported_params params =
1810 .device = ULongToPtr(params32->device),
1811 .flow = params32->flow,
1812 .share = params32->share,
1813 .fmt_in = ULongToPtr(params32->fmt_in),
1814 .fmt_out = ULongToPtr(params32->fmt_out)
1816 oss_is_format_supported(&params);
1817 params32->result = params.result;
1818 return STATUS_SUCCESS;
1821 static NTSTATUS oss_wow64_get_mix_format(void *args)
1823 struct
1825 PTR32 device;
1826 EDataFlow flow;
1827 PTR32 fmt;
1828 HRESULT result;
1829 } *params32 = args;
1830 struct get_mix_format_params params =
1832 .device = ULongToPtr(params32->device),
1833 .flow = params32->flow,
1834 .fmt = ULongToPtr(params32->fmt)
1836 oss_get_mix_format(&params);
1837 params32->result = params.result;
1838 return STATUS_SUCCESS;
1841 static NTSTATUS oss_wow64_get_buffer_size(void *args)
1843 struct
1845 stream_handle stream;
1846 HRESULT result;
1847 PTR32 size;
1848 } *params32 = args;
1849 struct get_buffer_size_params params =
1851 .stream = params32->stream,
1852 .size = ULongToPtr(params32->size)
1854 oss_get_buffer_size(&params);
1855 params32->result = params.result;
1856 return STATUS_SUCCESS;
1859 static NTSTATUS oss_wow64_get_latency(void *args)
1861 struct
1863 stream_handle stream;
1864 HRESULT result;
1865 PTR32 latency;
1866 } *params32 = args;
1867 struct get_latency_params params =
1869 .stream = params32->stream,
1870 .latency = ULongToPtr(params32->latency)
1872 oss_get_latency(&params);
1873 params32->result = params.result;
1874 return STATUS_SUCCESS;
1877 static NTSTATUS oss_wow64_get_current_padding(void *args)
1879 struct
1881 stream_handle stream;
1882 HRESULT result;
1883 PTR32 padding;
1884 } *params32 = args;
1885 struct get_current_padding_params params =
1887 .stream = params32->stream,
1888 .padding = ULongToPtr(params32->padding)
1890 oss_get_current_padding(&params);
1891 params32->result = params.result;
1892 return STATUS_SUCCESS;
1895 static NTSTATUS oss_wow64_get_next_packet_size(void *args)
1897 struct
1899 stream_handle stream;
1900 HRESULT result;
1901 PTR32 frames;
1902 } *params32 = args;
1903 struct get_next_packet_size_params params =
1905 .stream = params32->stream,
1906 .frames = ULongToPtr(params32->frames)
1908 oss_get_next_packet_size(&params);
1909 params32->result = params.result;
1910 return STATUS_SUCCESS;
1913 static NTSTATUS oss_wow64_get_frequency(void *args)
1915 struct
1917 stream_handle stream;
1918 HRESULT result;
1919 PTR32 freq;
1920 } *params32 = args;
1921 struct get_frequency_params params =
1923 .stream = params32->stream,
1924 .freq = ULongToPtr(params32->freq)
1926 oss_get_frequency(&params);
1927 params32->result = params.result;
1928 return STATUS_SUCCESS;
1931 static NTSTATUS oss_wow64_get_position(void *args)
1933 struct
1935 stream_handle stream;
1936 BOOL device;
1937 HRESULT result;
1938 PTR32 pos;
1939 PTR32 qpctime;
1940 } *params32 = args;
1941 struct get_position_params params =
1943 .stream = params32->stream,
1944 .device = params32->device,
1945 .pos = ULongToPtr(params32->pos),
1946 .qpctime = ULongToPtr(params32->qpctime)
1948 oss_get_position(&params);
1949 params32->result = params.result;
1950 return STATUS_SUCCESS;
1953 static NTSTATUS oss_wow64_set_volumes(void *args)
1955 struct
1957 stream_handle stream;
1958 float master_volume;
1959 PTR32 volumes;
1960 PTR32 session_volumes;
1961 } *params32 = args;
1962 struct set_volumes_params params =
1964 .stream = params32->stream,
1965 .master_volume = params32->master_volume,
1966 .volumes = ULongToPtr(params32->volumes),
1967 .session_volumes = ULongToPtr(params32->session_volumes)
1969 return oss_set_volumes(&params);
1972 static NTSTATUS oss_wow64_set_event_handle(void *args)
1974 struct
1976 stream_handle stream;
1977 PTR32 event;
1978 HRESULT result;
1979 } *params32 = args;
1980 struct set_event_handle_params params =
1982 .stream = params32->stream,
1983 .event = ULongToHandle(params32->event)
1986 oss_set_event_handle(&params);
1987 params32->result = params.result;
1988 return STATUS_SUCCESS;
1991 static NTSTATUS oss_wow64_aux_message(void *args)
1993 struct
1995 UINT dev_id;
1996 UINT msg;
1997 UINT user;
1998 UINT param_1;
1999 UINT param_2;
2000 PTR32 err;
2001 } *params32 = args;
2002 struct aux_message_params params =
2004 .dev_id = params32->dev_id,
2005 .msg = params32->msg,
2006 .user = params32->user,
2007 .param_1 = params32->param_1,
2008 .param_2 = params32->param_2,
2009 .err = ULongToPtr(params32->err),
2011 return oss_aux_message(&params);
2014 unixlib_entry_t __wine_unix_call_wow64_funcs[] =
2016 NULL,
2017 NULL,
2018 NULL,
2019 oss_wow64_get_endpoint_ids,
2020 oss_wow64_create_stream,
2021 oss_wow64_release_stream,
2022 oss_start,
2023 oss_stop,
2024 oss_reset,
2025 oss_timer_loop,
2026 oss_wow64_get_render_buffer,
2027 oss_release_render_buffer,
2028 oss_wow64_get_capture_buffer,
2029 oss_release_capture_buffer,
2030 oss_wow64_is_format_supported,
2031 oss_wow64_get_mix_format,
2032 NULL,
2033 oss_wow64_get_buffer_size,
2034 oss_wow64_get_latency,
2035 oss_wow64_get_current_padding,
2036 oss_wow64_get_next_packet_size,
2037 oss_wow64_get_frequency,
2038 oss_wow64_get_position,
2039 oss_wow64_set_volumes,
2040 oss_wow64_set_event_handle,
2041 oss_wow64_test_connect,
2042 oss_is_started,
2043 NULL,
2044 oss_midi_release,
2045 oss_wow64_midi_out_message,
2046 oss_wow64_midi_in_message,
2047 oss_wow64_midi_notify_wait,
2048 oss_wow64_aux_message,
2051 #endif /* _WIN64 */