mmdevapi: Query MemoryWineUnixFuncs virtual memory and store the resulting handle.
[wine.git] / dlls / wineoss.drv / oss.c
blob65ca42c3182840228f25af794bfbed5287f34908
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 NTSTATUS oss_not_implemented(void *args)
74 return STATUS_SUCCESS;
77 /* copied from kernelbase */
78 static int muldiv( int a, int b, int c )
80 LONGLONG ret;
82 if (!c) return -1;
84 /* We want to deal with a positive divisor to simplify the logic. */
85 if (c < 0)
87 a = -a;
88 c = -c;
91 /* If the result is positive, we "add" to round. else, we subtract to round. */
92 if ((a < 0 && b < 0) || (a >= 0 && b >= 0))
93 ret = (((LONGLONG)a * b) + (c / 2)) / c;
94 else
95 ret = (((LONGLONG)a * b) - (c / 2)) / c;
97 if (ret > 2147483647 || ret < -2147483647) return -1;
98 return ret;
101 static void oss_lock(struct oss_stream *stream)
103 pthread_mutex_lock(&stream->lock);
106 static void oss_unlock(struct oss_stream *stream)
108 pthread_mutex_unlock(&stream->lock);
111 static NTSTATUS oss_unlock_result(struct oss_stream *stream,
112 HRESULT *result, HRESULT value)
114 *result = value;
115 oss_unlock(stream);
116 return STATUS_SUCCESS;
119 static struct oss_stream *handle_get_stream(stream_handle h)
121 return (struct oss_stream *)(UINT_PTR)h;
124 static NTSTATUS oss_test_connect(void *args)
126 struct test_connect_params *params = args;
127 int mixer_fd;
128 oss_sysinfo sysinfo;
130 /* Attempt to determine if we are running on OSS or ALSA's OSS
131 * compatibility layer. There is no official way to do that, so just check
132 * for validity as best as possible, without rejecting valid OSS
133 * implementations. */
135 mixer_fd = open("/dev/mixer", O_RDONLY, 0);
136 if(mixer_fd < 0){
137 TRACE("Priority_Unavailable: open failed\n");
138 params->priority = Priority_Unavailable;
139 return STATUS_SUCCESS;
142 sysinfo.version[0] = 0xFF;
143 sysinfo.versionnum = ~0;
144 if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){
145 TRACE("Priority_Unavailable: ioctl failed\n");
146 close(mixer_fd);
147 params->priority = Priority_Unavailable;
148 return STATUS_SUCCESS;
151 close(mixer_fd);
153 if(sysinfo.version[0] < '4' || sysinfo.version[0] > '9'){
154 TRACE("Priority_Low: sysinfo.version[0]: %x\n", sysinfo.version[0]);
155 params->priority = Priority_Low;
156 return STATUS_SUCCESS;
158 if(sysinfo.versionnum & 0x80000000){
159 TRACE("Priority_Low: sysinfo.versionnum: %x\n", sysinfo.versionnum);
160 params->priority = Priority_Low;
161 return STATUS_SUCCESS;
164 TRACE("Priority_Preferred: Seems like valid OSS!\n");
166 params->priority = Priority_Preferred;
167 return STATUS_SUCCESS;
170 /* dst must be large enough to hold devnode */
171 static void oss_clean_devnode(char *dest, const char *devnode)
173 const char *dot, *slash;
174 size_t len;
176 strcpy(dest, devnode);
177 dot = strrchr(dest, '.');
178 if(!dot)
179 return;
181 slash = strrchr(dest, '/');
182 if(slash && dot < slash)
183 return;
185 len = dot - dest;
186 dest[len] = '\0';
189 static int open_device(const char *device, EDataFlow flow)
191 int flags = ((flow == eRender) ? O_WRONLY : O_RDONLY) | O_NONBLOCK;
193 return open(device, flags, 0);
196 static void get_default_device(EDataFlow flow, char device[OSS_DEVNODE_SIZE])
198 int fd, err;
199 oss_audioinfo ai;
201 device[0] = '\0';
202 fd = open_device("/dev/dsp", flow);
203 if(fd < 0){
204 WARN("Couldn't open default device!\n");
205 return;
208 ai.dev = -1;
209 if((err = ioctl(fd, SNDCTL_ENGINEINFO, &ai)) < 0){
210 WARN("SNDCTL_ENGINEINFO failed: %d (%s)\n", err, strerror(errno));
211 close(fd);
212 return;
214 close(fd);
216 TRACE("Default devnode: %s\n", ai.devnode);
217 oss_clean_devnode(device, ai.devnode);
218 return;
221 static NTSTATUS oss_get_endpoint_ids(void *args)
223 struct get_endpoint_ids_params *params = args;
224 oss_sysinfo sysinfo;
225 oss_audioinfo ai;
226 static int print_once = 0;
227 static const WCHAR outW[] = {'O','u','t',':',' ',0};
228 static const WCHAR inW[] = {'I','n',':',' ',0};
229 struct endpoint_info
231 WCHAR name[ARRAY_SIZE(ai.name) + ARRAY_SIZE(outW)];
232 char device[OSS_DEVNODE_SIZE];
233 } *info;
234 unsigned int i, j, num, needed, name_len, device_len, offset, default_idx = 0;
235 char default_device[OSS_DEVNODE_SIZE];
236 struct endpoint *endpoint;
237 int mixer_fd;
239 mixer_fd = open("/dev/mixer", O_RDONLY, 0);
240 if(mixer_fd < 0){
241 ERR("OSS /dev/mixer doesn't seem to exist\n");
242 params->result = AUDCLNT_E_SERVICE_NOT_RUNNING;
243 return STATUS_SUCCESS;
246 if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){
247 close(mixer_fd);
248 if(errno == EINVAL){
249 ERR("OSS version too old, need at least OSSv4\n");
250 params->result = AUDCLNT_E_SERVICE_NOT_RUNNING;
251 return STATUS_SUCCESS;
254 ERR("Error getting SNDCTL_SYSINFO: %d (%s)\n", errno, strerror(errno));
255 params->result = E_FAIL;
256 return STATUS_SUCCESS;
259 if(!print_once){
260 TRACE("OSS sysinfo:\n");
261 TRACE("product: %s\n", sysinfo.product);
262 TRACE("version: %s\n", sysinfo.version);
263 TRACE("versionnum: %x\n", sysinfo.versionnum);
264 TRACE("numaudios: %d\n", sysinfo.numaudios);
265 TRACE("nummixers: %d\n", sysinfo.nummixers);
266 TRACE("numcards: %d\n", sysinfo.numcards);
267 TRACE("numaudioengines: %d\n", sysinfo.numaudioengines);
268 print_once = 1;
271 if(sysinfo.numaudios <= 0){
272 WARN("No audio devices!\n");
273 close(mixer_fd);
274 params->result = AUDCLNT_E_SERVICE_NOT_RUNNING;
275 return STATUS_SUCCESS;
278 info = malloc(sysinfo.numaudios * sizeof(*info));
279 if(!info){
280 close(mixer_fd);
281 params->result = E_OUTOFMEMORY;
282 return STATUS_SUCCESS;
285 get_default_device(params->flow, default_device);
287 num = 0;
288 for(i = 0; i < sysinfo.numaudios; ++i){
289 char devnode[OSS_DEVNODE_SIZE];
290 int fd, prefix_len;
291 const WCHAR *prefix;
293 memset(&ai, 0, sizeof(ai));
294 ai.dev = i;
295 if(ioctl(mixer_fd, SNDCTL_AUDIOINFO, &ai) < 0){
296 WARN("Error getting AUDIOINFO for dev %d: %d (%s)\n", i, errno,
297 strerror(errno));
298 continue;
301 oss_clean_devnode(devnode, ai.devnode);
303 /* check for duplicates */
304 for(j = 0; j < num; j++)
305 if(!strcmp(devnode, info[j].device))
306 break;
307 if(j < num)
308 continue;
310 fd = open_device(devnode, params->flow);
311 if(fd < 0){
312 WARN("Opening device \"%s\" failed, pretending it doesn't exist: %d (%s)\n",
313 devnode, errno, strerror(errno));
314 continue;
316 close(fd);
318 if((params->flow == eCapture && !(ai.caps & PCM_CAP_INPUT)) ||
319 (params->flow == eRender && !(ai.caps & PCM_CAP_OUTPUT)))
320 continue;
322 strcpy(info[num].device, devnode);
324 if(params->flow == eRender){
325 prefix = outW;
326 prefix_len = ARRAY_SIZE(outW) - 1;
327 }else{
328 prefix = inW;
329 prefix_len = ARRAY_SIZE(inW) - 1;
331 memcpy(info[num].name, prefix, prefix_len * sizeof(WCHAR));
332 ntdll_umbstowcs(ai.name, strlen(ai.name) + 1, info[num].name + prefix_len,
333 ARRAY_SIZE(info[num].name) - prefix_len);
334 if(!strcmp(default_device, info[num].device))
335 default_idx = num;
336 num++;
338 close(mixer_fd);
340 offset = needed = num * sizeof(*params->endpoints);
341 endpoint = params->endpoints;
343 for(i = 0; i < num; i++){
344 name_len = wcslen(info[i].name) + 1;
345 device_len = strlen(info[i].device) + 1;
346 needed += name_len * sizeof(WCHAR) + ((device_len + 1) & ~1);
348 if(needed <= params->size){
349 endpoint->name = offset;
350 memcpy((char *)params->endpoints + offset, info[i].name, name_len * sizeof(WCHAR));
351 offset += name_len * sizeof(WCHAR);
352 endpoint->device = offset;
353 memcpy((char *)params->endpoints + offset, info[i].device, device_len);
354 offset += (device_len + 1) & ~1;
355 endpoint++;
358 free(info);
360 params->num = num;
361 params->default_idx = default_idx;
363 if(needed > params->size){
364 params->size = needed;
365 params->result = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
366 } else
367 params->result = S_OK;
369 return STATUS_SUCCESS;
372 static UINT get_channel_mask(unsigned int channels)
374 switch(channels){
375 case 0:
376 return 0;
377 case 1:
378 return KSAUDIO_SPEAKER_MONO;
379 case 2:
380 return KSAUDIO_SPEAKER_STEREO;
381 case 3:
382 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
383 case 4:
384 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
385 case 5:
386 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
387 case 6:
388 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
389 case 7:
390 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
391 case 8:
392 return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
394 FIXME("Unknown speaker configuration: %u\n", channels);
395 return 0;
398 static int get_oss_format(const WAVEFORMATEX *fmt)
400 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)fmt;
402 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
403 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
404 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
405 switch(fmt->wBitsPerSample){
406 case 8:
407 return AFMT_U8;
408 case 16:
409 return AFMT_S16_LE;
410 case 24:
411 return AFMT_S24_LE;
412 case 32:
413 return AFMT_S32_LE;
415 return -1;
418 #ifdef AFMT_FLOAT
419 if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
420 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
421 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
422 if(fmt->wBitsPerSample != 32)
423 return -1;
425 return AFMT_FLOAT;
427 #endif
429 return -1;
432 static WAVEFORMATEXTENSIBLE *clone_format(const WAVEFORMATEX *fmt)
434 WAVEFORMATEXTENSIBLE *ret;
435 size_t size;
437 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
438 size = sizeof(WAVEFORMATEXTENSIBLE);
439 else
440 size = sizeof(WAVEFORMATEX);
442 ret = malloc(size);
443 if(!ret)
444 return NULL;
446 memcpy(ret, fmt, size);
448 ret->Format.cbSize = size - sizeof(WAVEFORMATEX);
450 return ret;
453 static HRESULT setup_oss_device(AUDCLNT_SHAREMODE share, int fd,
454 const WAVEFORMATEX *fmt, WAVEFORMATEXTENSIBLE *out)
456 const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
457 int tmp, oss_format;
458 double tenth;
459 HRESULT ret = S_OK;
460 WAVEFORMATEXTENSIBLE *closest;
462 tmp = oss_format = get_oss_format(fmt);
463 if(oss_format < 0)
464 return AUDCLNT_E_UNSUPPORTED_FORMAT;
465 if(ioctl(fd, SNDCTL_DSP_SETFMT, &tmp) < 0){
466 WARN("SETFMT failed: %d (%s)\n", errno, strerror(errno));
467 return E_FAIL;
469 if(tmp != oss_format){
470 TRACE("Format unsupported by this OSS version: %x\n", oss_format);
471 return AUDCLNT_E_UNSUPPORTED_FORMAT;
474 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
475 (fmtex->Format.nAvgBytesPerSec == 0 ||
476 fmtex->Format.nBlockAlign == 0 ||
477 fmtex->Samples.wValidBitsPerSample > fmtex->Format.wBitsPerSample))
478 return E_INVALIDARG;
480 if(fmt->nChannels == 0)
481 return AUDCLNT_E_UNSUPPORTED_FORMAT;
483 closest = clone_format(fmt);
484 if(!closest)
485 return E_OUTOFMEMORY;
487 tmp = fmt->nSamplesPerSec;
488 if(ioctl(fd, SNDCTL_DSP_SPEED, &tmp) < 0){
489 WARN("SPEED failed: %d (%s)\n", errno, strerror(errno));
490 free(closest);
491 return E_FAIL;
493 tenth = fmt->nSamplesPerSec * 0.1;
494 if(tmp > fmt->nSamplesPerSec + tenth || tmp < fmt->nSamplesPerSec - tenth){
495 ret = S_FALSE;
496 closest->Format.nSamplesPerSec = tmp;
499 tmp = fmt->nChannels;
500 if(ioctl(fd, SNDCTL_DSP_CHANNELS, &tmp) < 0){
501 WARN("CHANNELS failed: %d (%s)\n", errno, strerror(errno));
502 free(closest);
503 return E_FAIL;
505 if(tmp != fmt->nChannels){
506 ret = S_FALSE;
507 closest->Format.nChannels = tmp;
510 if(closest->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
511 closest->dwChannelMask = get_channel_mask(closest->Format.nChannels);
513 if(fmt->nBlockAlign != fmt->nChannels * fmt->wBitsPerSample / 8 ||
514 fmt->nAvgBytesPerSec != fmt->nBlockAlign * fmt->nSamplesPerSec ||
515 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
516 fmtex->Samples.wValidBitsPerSample < fmtex->Format.wBitsPerSample))
517 ret = S_FALSE;
519 if(share == AUDCLNT_SHAREMODE_EXCLUSIVE &&
520 fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
521 if(fmtex->dwChannelMask == 0 || fmtex->dwChannelMask & SPEAKER_RESERVED)
522 ret = S_FALSE;
525 if(ret == S_FALSE && !out)
526 ret = AUDCLNT_E_UNSUPPORTED_FORMAT;
528 if(ret == S_FALSE && out){
529 closest->Format.nBlockAlign =
530 closest->Format.nChannels * closest->Format.wBitsPerSample / 8;
531 closest->Format.nAvgBytesPerSec =
532 closest->Format.nBlockAlign * closest->Format.nSamplesPerSec;
533 if(closest->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
534 closest->Samples.wValidBitsPerSample = closest->Format.wBitsPerSample;
535 memcpy(out, closest, closest->Format.cbSize + sizeof(WAVEFORMATEX));
537 free(closest);
539 TRACE("returning: %08x\n", (unsigned)ret);
540 return ret;
543 static ULONG_PTR zero_bits(void)
545 #ifdef _WIN64
546 return !NtCurrentTeb()->WowTebOffset ? 0 : 0x7fffffff;
547 #else
548 return 0;
549 #endif
552 static NTSTATUS oss_create_stream(void *args)
554 struct create_stream_params *params = args;
555 WAVEFORMATEXTENSIBLE *fmtex;
556 struct oss_stream *stream;
557 oss_audioinfo ai;
558 SIZE_T size;
560 stream = calloc(1, sizeof(*stream));
561 if(!stream){
562 params->result = E_OUTOFMEMORY;
563 return STATUS_SUCCESS;
566 stream->flow = params->flow;
567 pthread_mutex_init(&stream->lock, NULL);
569 stream->fd = open_device(params->device, params->flow);
570 if(stream->fd < 0){
571 WARN("Unable to open device %s: %d (%s)\n", params->device, errno, strerror(errno));
572 params->result = AUDCLNT_E_DEVICE_INVALIDATED;
573 goto exit;
576 ai.dev = -1;
577 if(ioctl(stream->fd, SNDCTL_ENGINEINFO, &ai) < 0){
578 WARN("Unable to get audio info for device %s: %d (%s)\n", params->device, errno, strerror(errno));
579 params->result = E_FAIL;
580 goto exit;
583 TRACE("OSS audioinfo:\n");
584 TRACE("devnode: %s\n", ai.devnode);
585 TRACE("name: %s\n", ai.name);
586 TRACE("busy: %x\n", ai.busy);
587 TRACE("caps: %x\n", ai.caps);
588 TRACE("iformats: %x\n", ai.iformats);
589 TRACE("oformats: %x\n", ai.oformats);
590 TRACE("enabled: %d\n", ai.enabled);
591 TRACE("min_rate: %d\n", ai.min_rate);
592 TRACE("max_rate: %d\n", ai.max_rate);
593 TRACE("min_channels: %d\n", ai.min_channels);
594 TRACE("max_channels: %d\n", ai.max_channels);
596 params->result = setup_oss_device(params->share, stream->fd, params->fmt, NULL);
597 if(FAILED(params->result))
598 goto exit;
600 fmtex = clone_format(params->fmt);
601 if(!fmtex){
602 params->result = E_OUTOFMEMORY;
603 goto exit;
605 stream->fmt = &fmtex->Format;
607 stream->period = params->period;
608 stream->period_frames = muldiv(params->fmt->nSamplesPerSec, params->period, 10000000);
610 stream->bufsize_frames = muldiv(params->duration, params->fmt->nSamplesPerSec, 10000000);
611 if(params->share == AUDCLNT_SHAREMODE_EXCLUSIVE)
612 stream->bufsize_frames -= stream->bufsize_frames % stream->period_frames;
613 size = stream->bufsize_frames * params->fmt->nBlockAlign;
614 if(NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, zero_bits(),
615 &size, MEM_COMMIT, PAGE_READWRITE)){
616 params->result = E_OUTOFMEMORY;
617 goto exit;
620 stream->share = params->share;
621 stream->flags = params->flags;
622 stream->oss_bufsize_bytes = 0;
624 exit:
625 if(FAILED(params->result)){
626 if(stream->fd >= 0) close(stream->fd);
627 if(stream->local_buffer){
628 size = 0;
629 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, &size, MEM_RELEASE);
631 pthread_mutex_destroy(&stream->lock);
632 free(stream->fmt);
633 free(stream);
634 }else{
635 *params->stream = (stream_handle)(UINT_PTR)stream;
638 return STATUS_SUCCESS;
641 static NTSTATUS oss_release_stream(void *args)
643 struct release_stream_params *params = args;
644 struct oss_stream *stream = handle_get_stream(params->stream);
645 SIZE_T size;
647 if(params->timer_thread){
648 stream->please_quit = TRUE;
649 NtWaitForSingleObject(params->timer_thread, FALSE, NULL);
650 NtClose(params->timer_thread);
653 close(stream->fd);
654 if(stream->local_buffer){
655 size = 0;
656 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, &size, MEM_RELEASE);
658 if(stream->tmp_buffer){
659 size = 0;
660 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, &size, MEM_RELEASE);
662 free(stream->fmt);
663 pthread_mutex_destroy(&stream->lock);
664 free(stream);
666 params->result = S_OK;
667 return STATUS_SUCCESS;
670 static NTSTATUS oss_start(void *args)
672 struct start_params *params = args;
673 struct oss_stream *stream = handle_get_stream(params->stream);
675 oss_lock(stream);
677 if((stream->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !stream->event)
678 return oss_unlock_result(stream, &params->result, AUDCLNT_E_EVENTHANDLE_NOT_SET);
680 if(stream->playing)
681 return oss_unlock_result(stream, &params->result, AUDCLNT_E_NOT_STOPPED);
683 stream->playing = TRUE;
685 return oss_unlock_result(stream, &params->result, S_OK);
688 static NTSTATUS oss_stop(void *args)
690 struct stop_params *params = args;
691 struct oss_stream *stream = handle_get_stream(params->stream);
693 oss_lock(stream);
695 if(!stream->playing)
696 return oss_unlock_result(stream, &params->result, S_FALSE);
698 stream->playing = FALSE;
699 stream->in_oss_frames = 0;
701 return oss_unlock_result(stream, &params->result, S_OK);
704 static NTSTATUS oss_reset(void *args)
706 struct reset_params *params = args;
707 struct oss_stream *stream = handle_get_stream(params->stream);
709 oss_lock(stream);
711 if(stream->playing)
712 return oss_unlock_result(stream, &params->result, AUDCLNT_E_NOT_STOPPED);
714 if(stream->getbuf_last)
715 return oss_unlock_result(stream, &params->result, AUDCLNT_E_BUFFER_OPERATION_PENDING);
717 if(stream->flow == eRender){
718 stream->written_frames = 0;
719 stream->last_pos_frames = 0;
720 }else{
721 stream->written_frames += stream->held_frames;
723 stream->held_frames = 0;
724 stream->lcl_offs_frames = 0;
725 stream->in_oss_frames = 0;
727 return oss_unlock_result(stream, &params->result, S_OK);
730 static void silence_buffer(struct oss_stream *stream, BYTE *buffer, UINT32 frames)
732 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)stream->fmt;
733 if((stream->fmt->wFormatTag == WAVE_FORMAT_PCM ||
734 (stream->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
735 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
736 stream->fmt->wBitsPerSample == 8)
737 memset(buffer, 128, frames * stream->fmt->nBlockAlign);
738 else
739 memset(buffer, 0, frames * stream->fmt->nBlockAlign);
742 static void oss_write_data(struct oss_stream *stream)
744 ssize_t written_bytes;
745 UINT32 written_frames, in_oss_frames, write_limit, max_period, write_offs_frames, new_frames;
746 SIZE_T to_write_frames, to_write_bytes, advanced;
747 audio_buf_info bi;
748 BYTE *buf;
750 if(ioctl(stream->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0){
751 WARN("GETOSPACE failed: %d (%s)\n", errno, strerror(errno));
752 return;
755 max_period = max(bi.fragsize / stream->fmt->nBlockAlign, stream->period_frames);
757 if(bi.bytes > stream->oss_bufsize_bytes){
758 TRACE("New buffer size (%u) is larger than old buffer size (%u)\n",
759 bi.bytes, stream->oss_bufsize_bytes);
760 stream->oss_bufsize_bytes = bi.bytes;
761 in_oss_frames = 0;
762 }else
763 in_oss_frames = (stream->oss_bufsize_bytes - bi.bytes) / stream->fmt->nBlockAlign;
765 if(in_oss_frames > stream->in_oss_frames){
766 TRACE("Capping reported frames from %u to %u\n",
767 in_oss_frames, stream->in_oss_frames);
768 in_oss_frames = stream->in_oss_frames;
771 write_limit = 0;
772 while(write_limit + in_oss_frames < max_period * 3)
773 write_limit += max_period;
774 if(write_limit == 0)
775 return;
777 /* vvvvvv - in_oss_frames
778 * [--xxxxxxxxxx]
779 * [xxxxxxxxxx--]
780 * ^^^^^^^^^^ - held_frames
781 * ^ - lcl_offs_frames
783 advanced = stream->in_oss_frames - in_oss_frames;
784 if(advanced > stream->held_frames)
785 advanced = stream->held_frames;
786 stream->lcl_offs_frames += advanced;
787 stream->lcl_offs_frames %= stream->bufsize_frames;
788 stream->held_frames -= advanced;
789 stream->in_oss_frames = in_oss_frames;
790 TRACE("advanced by %lu, lcl_offs: %u, held: %u, in_oss: %u\n",
791 advanced, stream->lcl_offs_frames, stream->held_frames, stream->in_oss_frames);
794 if(stream->held_frames == stream->in_oss_frames)
795 return;
797 write_offs_frames = (stream->lcl_offs_frames + stream->in_oss_frames) % stream->bufsize_frames;
798 new_frames = stream->held_frames - stream->in_oss_frames;
800 if(write_offs_frames + new_frames > stream->bufsize_frames)
801 to_write_frames = stream->bufsize_frames - write_offs_frames;
802 else
803 to_write_frames = new_frames;
805 to_write_frames = min(to_write_frames, write_limit);
806 to_write_bytes = to_write_frames * stream->fmt->nBlockAlign;
807 TRACE("going to write %lu frames from %u (%lu of %u)\n", to_write_frames,
808 write_offs_frames, to_write_frames + write_offs_frames,
809 stream->bufsize_frames);
811 buf = stream->local_buffer + write_offs_frames * stream->fmt->nBlockAlign;
813 if(stream->mute)
814 silence_buffer(stream, buf, to_write_frames);
816 written_bytes = write(stream->fd, buf, to_write_bytes);
817 if(written_bytes < 0){
818 /* EAGAIN is OSS buffer full, log that too */
819 WARN("write failed: %d (%s)\n", errno, strerror(errno));
820 return;
822 written_frames = written_bytes / stream->fmt->nBlockAlign;
824 stream->in_oss_frames += written_frames;
826 if(written_frames < to_write_frames){
827 /* OSS buffer probably full */
828 return;
831 if(new_frames > written_frames && written_frames < write_limit){
832 /* wrapped and have some data back at the start to write */
834 to_write_frames = min(write_limit - written_frames, new_frames - written_frames);
835 to_write_bytes = to_write_frames * stream->fmt->nBlockAlign;
837 if(stream->mute)
838 silence_buffer(stream, stream->local_buffer, to_write_frames);
840 TRACE("wrapping to write %lu frames from beginning\n", to_write_frames);
842 written_bytes = write(stream->fd, stream->local_buffer, to_write_bytes);
843 if(written_bytes < 0){
844 WARN("write failed: %d (%s)\n", errno, strerror(errno));
845 return;
847 written_frames = written_bytes / stream->fmt->nBlockAlign;
848 stream->in_oss_frames += written_frames;
852 static void oss_read_data(struct oss_stream *stream)
854 UINT64 pos, readable;
855 ssize_t nread;
857 pos = (stream->held_frames + stream->lcl_offs_frames) % stream->bufsize_frames;
858 readable = (stream->bufsize_frames - pos) * stream->fmt->nBlockAlign;
860 nread = read(stream->fd, stream->local_buffer + pos * stream->fmt->nBlockAlign,
861 readable);
862 if(nread < 0){
863 WARN("read failed: %d (%s)\n", errno, strerror(errno));
864 return;
867 stream->held_frames += nread / stream->fmt->nBlockAlign;
869 if(stream->held_frames > stream->bufsize_frames){
870 WARN("Overflow of unread data\n");
871 stream->lcl_offs_frames += stream->held_frames;
872 stream->lcl_offs_frames %= stream->bufsize_frames;
873 stream->held_frames = stream->bufsize_frames;
877 static NTSTATUS oss_timer_loop(void *args)
879 struct timer_loop_params *params = args;
880 struct oss_stream *stream = handle_get_stream(params->stream);
881 LARGE_INTEGER delay, now, next;
882 int adjust;
884 oss_lock(stream);
886 delay.QuadPart = -stream->period;
887 NtQueryPerformanceCounter(&now, NULL);
888 next.QuadPart = now.QuadPart + stream->period;
890 while(!stream->please_quit){
891 if(stream->playing){
892 if(stream->flow == eRender && stream->held_frames)
893 oss_write_data(stream);
894 else if(stream->flow == eCapture)
895 oss_read_data(stream);
897 if(stream->event)
898 NtSetEvent(stream->event, NULL);
899 oss_unlock(stream);
901 NtDelayExecution(FALSE, &delay);
903 oss_lock(stream);
904 NtQueryPerformanceCounter(&now, NULL);
905 adjust = next.QuadPart - now.QuadPart;
906 if(adjust > stream->period / 2)
907 adjust = stream->period / 2;
908 else if(adjust < -stream->period / 2)
909 adjust = -stream->period / 2;
910 delay.QuadPart = -(stream->period + adjust);
911 next.QuadPart += stream->period;
914 oss_unlock(stream);
916 return STATUS_SUCCESS;
919 static NTSTATUS oss_get_render_buffer(void *args)
921 struct get_render_buffer_params *params = args;
922 struct oss_stream *stream = handle_get_stream(params->stream);
923 UINT32 write_pos, frames = params->frames;
924 BYTE **data = params->data;
925 SIZE_T size;
927 oss_lock(stream);
929 if(stream->getbuf_last)
930 return oss_unlock_result(stream, &params->result, AUDCLNT_E_OUT_OF_ORDER);
932 if(!frames)
933 return oss_unlock_result(stream, &params->result, S_OK);
935 if(stream->held_frames + frames > stream->bufsize_frames)
936 return oss_unlock_result(stream, &params->result, AUDCLNT_E_BUFFER_TOO_LARGE);
938 write_pos =
939 (stream->lcl_offs_frames + stream->held_frames) % stream->bufsize_frames;
940 if(write_pos + frames > stream->bufsize_frames){
941 if(stream->tmp_buffer_frames < frames){
942 if(stream->tmp_buffer){
943 size = 0;
944 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, &size, MEM_RELEASE);
945 stream->tmp_buffer = NULL;
947 size = frames * stream->fmt->nBlockAlign;
948 if(NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, zero_bits(),
949 &size, MEM_COMMIT, PAGE_READWRITE)){
950 stream->tmp_buffer_frames = 0;
951 return oss_unlock_result(stream, &params->result, E_OUTOFMEMORY);
953 stream->tmp_buffer_frames = frames;
955 *data = stream->tmp_buffer;
956 stream->getbuf_last = -frames;
957 }else{
958 *data = stream->local_buffer + write_pos * stream->fmt->nBlockAlign;
959 stream->getbuf_last = frames;
962 silence_buffer(stream, *data, frames);
964 return oss_unlock_result(stream, &params->result, S_OK);
967 static void oss_wrap_buffer(struct oss_stream *stream, BYTE *buffer, UINT32 written_frames)
969 UINT32 write_offs_frames =
970 (stream->lcl_offs_frames + stream->held_frames) % stream->bufsize_frames;
971 UINT32 write_offs_bytes = write_offs_frames * stream->fmt->nBlockAlign;
972 UINT32 chunk_frames = stream->bufsize_frames - write_offs_frames;
973 UINT32 chunk_bytes = chunk_frames * stream->fmt->nBlockAlign;
974 UINT32 written_bytes = written_frames * stream->fmt->nBlockAlign;
976 if(written_bytes <= chunk_bytes){
977 memcpy(stream->local_buffer + write_offs_bytes, buffer, written_bytes);
978 }else{
979 memcpy(stream->local_buffer + write_offs_bytes, buffer, chunk_bytes);
980 memcpy(stream->local_buffer, buffer + chunk_bytes,
981 written_bytes - chunk_bytes);
985 static NTSTATUS oss_release_render_buffer(void *args)
987 struct release_render_buffer_params *params = args;
988 struct oss_stream *stream = handle_get_stream(params->stream);
989 UINT32 written_frames = params->written_frames;
990 UINT flags = params->flags;
991 BYTE *buffer;
993 oss_lock(stream);
995 if(!written_frames){
996 stream->getbuf_last = 0;
997 return oss_unlock_result(stream, &params->result, S_OK);
1000 if(!stream->getbuf_last)
1001 return oss_unlock_result(stream, &params->result, AUDCLNT_E_OUT_OF_ORDER);
1003 if(written_frames > (stream->getbuf_last >= 0 ? stream->getbuf_last : -stream->getbuf_last))
1004 return oss_unlock_result(stream, &params->result, AUDCLNT_E_INVALID_SIZE);
1006 if(stream->getbuf_last >= 0)
1007 buffer = stream->local_buffer + stream->fmt->nBlockAlign *
1008 ((stream->lcl_offs_frames + stream->held_frames) % stream->bufsize_frames);
1009 else
1010 buffer = stream->tmp_buffer;
1012 if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
1013 silence_buffer(stream, buffer, written_frames);
1015 if(stream->getbuf_last < 0)
1016 oss_wrap_buffer(stream, buffer, written_frames);
1018 stream->held_frames += written_frames;
1019 stream->written_frames += written_frames;
1020 stream->getbuf_last = 0;
1022 return oss_unlock_result(stream, &params->result, S_OK);
1025 static NTSTATUS oss_get_capture_buffer(void *args)
1027 struct get_capture_buffer_params *params = args;
1028 struct oss_stream *stream = handle_get_stream(params->stream);
1029 UINT64 *devpos = params->devpos, *qpcpos = params->qpcpos;
1030 UINT32 *frames = params->frames;
1031 UINT *flags = params->flags;
1032 BYTE **data = params->data;
1033 SIZE_T size;
1035 oss_lock(stream);
1037 if(stream->getbuf_last)
1038 return oss_unlock_result(stream, &params->result, AUDCLNT_E_OUT_OF_ORDER);
1040 if(stream->held_frames < stream->period_frames){
1041 *frames = 0;
1042 return oss_unlock_result(stream, &params->result, AUDCLNT_S_BUFFER_EMPTY);
1045 *flags = 0;
1047 *frames = stream->period_frames;
1049 if(stream->lcl_offs_frames + *frames > stream->bufsize_frames){
1050 UINT32 chunk_bytes, offs_bytes, frames_bytes;
1051 if(stream->tmp_buffer_frames < *frames){
1052 if(stream->tmp_buffer){
1053 size = 0;
1054 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, &size, MEM_RELEASE);
1055 stream->tmp_buffer = NULL;
1057 size = *frames * stream->fmt->nBlockAlign;
1058 if(NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, zero_bits(),
1059 &size, MEM_COMMIT, PAGE_READWRITE)){
1060 stream->tmp_buffer_frames = 0;
1061 return oss_unlock_result(stream, &params->result, E_OUTOFMEMORY);
1063 stream->tmp_buffer_frames = *frames;
1066 *data = stream->tmp_buffer;
1067 chunk_bytes = (stream->bufsize_frames - stream->lcl_offs_frames) *
1068 stream->fmt->nBlockAlign;
1069 offs_bytes = stream->lcl_offs_frames * stream->fmt->nBlockAlign;
1070 frames_bytes = *frames * stream->fmt->nBlockAlign;
1071 memcpy(stream->tmp_buffer, stream->local_buffer + offs_bytes, chunk_bytes);
1072 memcpy(stream->tmp_buffer + chunk_bytes, stream->local_buffer,
1073 frames_bytes - chunk_bytes);
1074 }else
1075 *data = stream->local_buffer +
1076 stream->lcl_offs_frames * stream->fmt->nBlockAlign;
1078 stream->getbuf_last = *frames;
1080 if(devpos)
1081 *devpos = stream->written_frames;
1082 if(qpcpos){
1083 LARGE_INTEGER stamp, freq;
1084 NtQueryPerformanceCounter(&stamp, &freq);
1085 *qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1088 return oss_unlock_result(stream, &params->result, *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY);
1091 static NTSTATUS oss_release_capture_buffer(void *args)
1093 struct release_capture_buffer_params *params = args;
1094 struct oss_stream *stream = handle_get_stream(params->stream);
1095 UINT32 done = params->done;
1097 oss_lock(stream);
1099 if(!done){
1100 stream->getbuf_last = 0;
1101 return oss_unlock_result(stream, &params->result, S_OK);
1104 if(!stream->getbuf_last)
1105 return oss_unlock_result(stream, &params->result, AUDCLNT_E_OUT_OF_ORDER);
1107 if(stream->getbuf_last != done)
1108 return oss_unlock_result(stream, &params->result, AUDCLNT_E_INVALID_SIZE);
1110 stream->written_frames += done;
1111 stream->held_frames -= done;
1112 stream->lcl_offs_frames += done;
1113 stream->lcl_offs_frames %= stream->bufsize_frames;
1114 stream->getbuf_last = 0;
1116 return oss_unlock_result(stream, &params->result, S_OK);
1119 static NTSTATUS oss_is_format_supported(void *args)
1121 struct is_format_supported_params *params = args;
1122 int fd;
1124 params->result = S_OK;
1126 if(!params->fmt_in || (params->share == AUDCLNT_SHAREMODE_SHARED && !params->fmt_out))
1127 params->result = E_POINTER;
1128 else if(params->share != AUDCLNT_SHAREMODE_SHARED && params->share != AUDCLNT_SHAREMODE_EXCLUSIVE)
1129 params->result = E_INVALIDARG;
1130 else if(params->fmt_in->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1131 params->fmt_in->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1132 params->result = E_INVALIDARG;
1133 if(FAILED(params->result))
1134 return STATUS_SUCCESS;
1136 fd = open_device(params->device, params->flow);
1137 if(fd < 0){
1138 WARN("Unable to open device %s: %d (%s)\n", params->device, errno, strerror(errno));
1139 params->result = AUDCLNT_E_DEVICE_INVALIDATED;
1140 return STATUS_SUCCESS;
1142 params->result = setup_oss_device(params->share, fd, params->fmt_in, params->fmt_out);
1143 close(fd);
1145 return STATUS_SUCCESS;
1148 static NTSTATUS oss_get_mix_format(void *args)
1150 struct get_mix_format_params *params = args;
1151 WAVEFORMATEXTENSIBLE *fmt = params->fmt;
1152 oss_audioinfo ai;
1153 int formats, fd;
1155 if(params->flow != eRender && params->flow != eCapture){
1156 params->result = E_UNEXPECTED;
1157 return STATUS_SUCCESS;
1160 fd = open_device(params->device, params->flow);
1161 if(fd < 0){
1162 WARN("Unable to open device %s: %d (%s)\n", params->device, errno, strerror(errno));
1163 params->result = AUDCLNT_E_DEVICE_INVALIDATED;
1164 return STATUS_SUCCESS;
1167 ai.dev = -1;
1168 if(ioctl(fd, SNDCTL_ENGINEINFO, &ai) < 0){
1169 WARN("Unable to get audio info for device %s: %d (%s)\n", params->device, errno, strerror(errno));
1170 close(fd);
1171 params->result = E_FAIL;
1172 return STATUS_SUCCESS;
1174 close(fd);
1176 if(params->flow == eRender)
1177 formats = ai.oformats;
1178 else
1179 formats = ai.iformats;
1181 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1182 if(formats & AFMT_S16_LE){
1183 fmt->Format.wBitsPerSample = 16;
1184 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1185 #ifdef AFMT_FLOAT
1186 }else if(formats & AFMT_FLOAT){
1187 fmt->Format.wBitsPerSample = 32;
1188 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1189 #endif
1190 }else if(formats & AFMT_U8){
1191 fmt->Format.wBitsPerSample = 8;
1192 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1193 }else if(formats & AFMT_S32_LE){
1194 fmt->Format.wBitsPerSample = 32;
1195 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1196 }else if(formats & AFMT_S24_LE){
1197 fmt->Format.wBitsPerSample = 24;
1198 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1199 }else{
1200 WARN("Didn't recognize any available OSS formats: %x\n", formats);
1201 params->result = E_FAIL;
1202 return STATUS_SUCCESS;
1205 /* some OSS drivers are buggy, so set reasonable defaults if
1206 * the reported values seem wacky */
1207 fmt->Format.nChannels = max(ai.max_channels, ai.min_channels);
1208 if(fmt->Format.nChannels == 0 || fmt->Format.nChannels > 8)
1209 fmt->Format.nChannels = 2;
1211 /* For most hardware on Windows, users must choose a configuration with an even
1212 * number of channels (stereo, quad, 5.1, 7.1). Users can then disable
1213 * channels, but those channels are still reported to applications from
1214 * GetMixFormat! Some applications behave badly if given an odd number of
1215 * channels (e.g. 2.1). */
1216 if(fmt->Format.nChannels > 1 && (fmt->Format.nChannels & 0x1))
1218 if(fmt->Format.nChannels < ai.max_channels)
1219 fmt->Format.nChannels += 1;
1220 else
1221 /* We could "fake" more channels and downmix the emulated channels,
1222 * but at that point you really ought to tweak your OSS setup or
1223 * just use PulseAudio. */
1224 WARN("Some Windows applications behave badly with an odd number of channels (%u)!\n", fmt->Format.nChannels);
1227 if(ai.max_rate == 0)
1228 fmt->Format.nSamplesPerSec = 44100;
1229 else
1230 fmt->Format.nSamplesPerSec = min(ai.max_rate, 44100);
1231 if(fmt->Format.nSamplesPerSec < ai.min_rate)
1232 fmt->Format.nSamplesPerSec = ai.min_rate;
1234 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1236 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1237 fmt->Format.nChannels) / 8;
1238 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1239 fmt->Format.nBlockAlign;
1241 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1242 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1244 params->result = S_OK;
1245 return STATUS_SUCCESS;
1248 static NTSTATUS oss_get_buffer_size(void *args)
1250 struct get_buffer_size_params *params = args;
1251 struct oss_stream *stream = handle_get_stream(params->stream);
1253 oss_lock(stream);
1255 *params->frames = stream->bufsize_frames;
1257 return oss_unlock_result(stream, &params->result, S_OK);
1260 static NTSTATUS oss_get_latency(void *args)
1262 struct get_latency_params *params = args;
1263 struct oss_stream *stream = handle_get_stream(params->stream);
1265 oss_lock(stream);
1267 /* pretend we process audio in Period chunks, so max latency includes
1268 * the period time. Some native machines add .6666ms in shared mode. */
1269 *params->latency = stream->period + 6666;
1271 return oss_unlock_result(stream, &params->result, S_OK);
1274 static NTSTATUS oss_get_current_padding(void *args)
1276 struct get_current_padding_params *params = args;
1277 struct oss_stream *stream = handle_get_stream(params->stream);
1279 oss_lock(stream);
1281 *params->padding = stream->held_frames;
1283 return oss_unlock_result(stream, &params->result, S_OK);
1286 static NTSTATUS oss_get_next_packet_size(void *args)
1288 struct get_next_packet_size_params *params = args;
1289 struct oss_stream *stream = handle_get_stream(params->stream);
1290 UINT32 *frames = params->frames;
1292 oss_lock(stream);
1294 *frames = stream->held_frames < stream->period_frames ? 0 : stream->period_frames;
1296 return oss_unlock_result(stream, &params->result, S_OK);
1299 static NTSTATUS oss_get_frequency(void *args)
1301 struct get_frequency_params *params = args;
1302 struct oss_stream *stream = handle_get_stream(params->stream);
1303 UINT64 *freq = params->freq;
1305 oss_lock(stream);
1307 if(stream->share == AUDCLNT_SHAREMODE_SHARED)
1308 *freq = (UINT64)stream->fmt->nSamplesPerSec * stream->fmt->nBlockAlign;
1309 else
1310 *freq = stream->fmt->nSamplesPerSec;
1312 return oss_unlock_result(stream, &params->result, S_OK);
1315 static NTSTATUS oss_get_position(void *args)
1317 struct get_position_params *params = args;
1318 struct oss_stream *stream = handle_get_stream(params->stream);
1319 UINT64 *pos = params->pos, *qpctime = params->qpctime;
1321 oss_lock(stream);
1323 if(stream->flow == eRender){
1324 *pos = stream->written_frames - stream->held_frames;
1325 if(*pos < stream->last_pos_frames)
1326 *pos = stream->last_pos_frames;
1327 }else if(stream->flow == eCapture){
1328 audio_buf_info bi;
1329 UINT32 held;
1331 if(ioctl(stream->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
1332 TRACE("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
1333 held = 0;
1334 }else{
1335 if(bi.bytes <= bi.fragsize)
1336 held = 0;
1337 else
1338 held = bi.bytes / stream->fmt->nBlockAlign;
1341 *pos = stream->written_frames + held;
1344 stream->last_pos_frames = *pos;
1346 TRACE("returning: %s\n", wine_dbgstr_longlong(*pos));
1347 if(stream->share == AUDCLNT_SHAREMODE_SHARED)
1348 *pos *= stream->fmt->nBlockAlign;
1350 if(qpctime){
1351 LARGE_INTEGER stamp, freq;
1352 NtQueryPerformanceCounter(&stamp, &freq);
1353 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1356 return oss_unlock_result(stream, &params->result, S_OK);
1359 static NTSTATUS oss_set_volumes(void *args)
1361 struct set_volumes_params *params = args;
1362 struct oss_stream *stream = handle_get_stream(params->stream);
1364 oss_lock(stream);
1365 stream->mute = !params->master_volume;
1366 oss_unlock(stream);
1368 return STATUS_SUCCESS;
1371 static NTSTATUS oss_set_event_handle(void *args)
1373 struct set_event_handle_params *params = args;
1374 struct oss_stream *stream = handle_get_stream(params->stream);
1376 oss_lock(stream);
1378 if(!(stream->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK))
1379 return oss_unlock_result(stream, &params->result, AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED);
1381 if (stream->event){
1382 FIXME("called twice\n");
1383 return oss_unlock_result(stream, &params->result, HRESULT_FROM_WIN32(ERROR_INVALID_NAME));
1386 stream->event = params->event;
1388 return oss_unlock_result(stream, &params->result, S_OK);
1391 static NTSTATUS oss_is_started(void *args)
1393 struct is_started_params *params = args;
1394 struct oss_stream *stream = handle_get_stream(params->stream);
1396 oss_lock(stream);
1398 return oss_unlock_result(stream, &params->result, stream->playing ? S_OK : S_FALSE);
1401 /* Aux driver */
1403 static unsigned int num_aux;
1405 #define MIXER_DEV "/dev/mixer"
1407 static UINT aux_init(void)
1409 int mixer;
1411 TRACE("()\n");
1413 if ((mixer = open(MIXER_DEV, O_RDWR)) < 0)
1415 WARN("mixer device not available !\n");
1416 num_aux = 0;
1418 else
1420 close(mixer);
1421 num_aux = 6;
1423 return 0;
1426 static UINT aux_exit(void)
1428 TRACE("()\n");
1429 return 0;
1432 static UINT aux_get_devcaps(WORD dev_id, AUXCAPSW *caps, UINT size)
1434 int mixer, volume;
1435 static const WCHAR ini[] = {'O','S','S',' ','A','u','x',' ','#','0',0};
1437 TRACE("(%04X, %p, %u);\n", dev_id, caps, size);
1438 if (caps == NULL) return MMSYSERR_NOTENABLED;
1439 if (dev_id >= num_aux) return MMSYSERR_BADDEVICEID;
1440 if ((mixer = open(MIXER_DEV, O_RDWR)) < 0)
1442 WARN("mixer device not available !\n");
1443 return MMSYSERR_NOTENABLED;
1445 if (ioctl(mixer, SOUND_MIXER_READ_LINE, &volume) == -1)
1447 close(mixer);
1448 WARN("unable to read mixer !\n");
1449 return MMSYSERR_NOTENABLED;
1451 close(mixer);
1452 caps->wMid = 0xAA;
1453 caps->wPid = 0x55 + dev_id;
1454 caps->vDriverVersion = 0x0100;
1455 memcpy(caps->szPname, ini, sizeof(ini));
1456 caps->szPname[9] = '0' + dev_id; /* 6 at max */
1457 caps->wTechnology = (dev_id == 2) ? AUXCAPS_CDAUDIO : AUXCAPS_AUXIN;
1458 caps->wReserved1 = 0;
1459 caps->dwSupport = AUXCAPS_VOLUME | AUXCAPS_LRVOLUME;
1461 return MMSYSERR_NOERROR;
1464 static UINT aux_get_volume(WORD dev_id, UINT *vol)
1466 int mixer, volume, left, right, cmd;
1468 TRACE("(%04X, %p);\n", dev_id, vol);
1469 if (vol == NULL) return MMSYSERR_NOTENABLED;
1470 if ((mixer = open(MIXER_DEV, O_RDWR)) < 0)
1472 WARN("mixer device not available !\n");
1473 return MMSYSERR_NOTENABLED;
1475 switch(dev_id)
1477 case 0:
1478 TRACE("SOUND_MIXER_READ_PCM !\n");
1479 cmd = SOUND_MIXER_READ_PCM;
1480 break;
1481 case 1:
1482 TRACE("SOUND_MIXER_READ_SYNTH !\n");
1483 cmd = SOUND_MIXER_READ_SYNTH;
1484 break;
1485 case 2:
1486 TRACE("SOUND_MIXER_READ_CD !\n");
1487 cmd = SOUND_MIXER_READ_CD;
1488 break;
1489 case 3:
1490 TRACE("SOUND_MIXER_READ_LINE !\n");
1491 cmd = SOUND_MIXER_READ_LINE;
1492 break;
1493 case 4:
1494 TRACE("SOUND_MIXER_READ_MIC !\n");
1495 cmd = SOUND_MIXER_READ_MIC;
1496 break;
1497 case 5:
1498 TRACE("SOUND_MIXER_READ_VOLUME !\n");
1499 cmd = SOUND_MIXER_READ_VOLUME;
1500 break;
1501 default:
1502 WARN("invalid device id=%04X !\n", dev_id);
1503 close(mixer);
1504 return MMSYSERR_NOTENABLED;
1506 if (ioctl(mixer, cmd, &volume) == -1)
1508 WARN("unable to read mixer !\n");
1509 close(mixer);
1510 return MMSYSERR_NOTENABLED;
1512 close(mixer);
1513 left = LOBYTE(LOWORD(volume));
1514 right = HIBYTE(LOWORD(volume));
1515 TRACE("left=%d right=%d !\n", left, right);
1516 *vol = MAKELONG((left * 0xFFFFL) / 100, (right * 0xFFFFL) / 100);
1517 return MMSYSERR_NOERROR;
1520 static UINT aux_set_volume(WORD dev_id, UINT vol)
1522 int mixer;
1523 int volume, left, right;
1524 int cmd;
1526 TRACE("(%04X, %08X);\n", dev_id, vol);
1528 left = (LOWORD(vol) * 100) >> 16;
1529 right = (HIWORD(vol) * 100) >> 16;
1530 volume = (right << 8) | left;
1532 if ((mixer = open(MIXER_DEV, O_RDWR)) < 0)
1534 WARN("mixer device not available !\n");
1535 return MMSYSERR_NOTENABLED;
1538 switch(dev_id)
1540 case 0:
1541 TRACE("SOUND_MIXER_WRITE_PCM !\n");
1542 cmd = SOUND_MIXER_WRITE_PCM;
1543 break;
1544 case 1:
1545 TRACE("SOUND_MIXER_WRITE_SYNTH !\n");
1546 cmd = SOUND_MIXER_WRITE_SYNTH;
1547 break;
1548 case 2:
1549 TRACE("SOUND_MIXER_WRITE_CD !\n");
1550 cmd = SOUND_MIXER_WRITE_CD;
1551 break;
1552 case 3:
1553 TRACE("SOUND_MIXER_WRITE_LINE !\n");
1554 cmd = SOUND_MIXER_WRITE_LINE;
1555 break;
1556 case 4:
1557 TRACE("SOUND_MIXER_WRITE_MIC !\n");
1558 cmd = SOUND_MIXER_WRITE_MIC;
1559 break;
1560 case 5:
1561 TRACE("SOUND_MIXER_WRITE_VOLUME !\n");
1562 cmd = SOUND_MIXER_WRITE_VOLUME;
1563 break;
1564 default:
1565 WARN("invalid device id=%04X !\n", dev_id);
1566 close(mixer);
1567 return MMSYSERR_NOTENABLED;
1569 if (ioctl(mixer, cmd, &volume) == -1)
1571 WARN("unable to set mixer !\n");
1572 close(mixer);
1573 return MMSYSERR_NOTENABLED;
1575 close(mixer);
1576 return MMSYSERR_NOERROR;
1579 static NTSTATUS oss_aux_message(void *args)
1581 struct aux_message_params *params = args;
1583 switch (params->msg)
1585 case DRVM_INIT:
1586 *params->err = aux_init();
1587 break;
1588 case DRVM_EXIT:
1589 *params->err = aux_exit();
1590 break;
1591 case DRVM_ENABLE:
1592 case DRVM_DISABLE:
1593 /* FIXME: Pretend this is supported */
1594 *params->err = 0;
1595 break;
1596 case AUXDM_GETDEVCAPS:
1597 *params->err = aux_get_devcaps(params->dev_id, (AUXCAPSW *)params->param_1, params->param_2);
1598 break;
1599 case AUXDM_GETNUMDEVS:
1600 TRACE("return %d;\n", num_aux);
1601 *params->err = num_aux;
1602 break;
1603 case AUXDM_GETVOLUME:
1604 *params->err = aux_get_volume(params->dev_id, (UINT *)params->param_1);
1605 break;
1606 case AUXDM_SETVOLUME:
1607 *params->err = aux_set_volume(params->dev_id, params->param_1);
1608 break;
1609 default:
1610 WARN("unknown message !\n");
1611 *params->err = MMSYSERR_NOTSUPPORTED;
1612 break;
1615 return STATUS_SUCCESS;
1618 unixlib_entry_t __wine_unix_call_funcs[] =
1620 oss_not_implemented,
1621 oss_not_implemented,
1622 oss_not_implemented,
1623 oss_get_endpoint_ids,
1624 oss_create_stream,
1625 oss_release_stream,
1626 oss_start,
1627 oss_stop,
1628 oss_reset,
1629 oss_timer_loop,
1630 oss_get_render_buffer,
1631 oss_release_render_buffer,
1632 oss_get_capture_buffer,
1633 oss_release_capture_buffer,
1634 oss_is_format_supported,
1635 oss_get_mix_format,
1636 oss_not_implemented,
1637 oss_get_buffer_size,
1638 oss_get_latency,
1639 oss_get_current_padding,
1640 oss_get_next_packet_size,
1641 oss_get_frequency,
1642 oss_get_position,
1643 oss_set_volumes,
1644 oss_set_event_handle,
1645 oss_test_connect,
1646 oss_is_started,
1647 oss_not_implemented,
1648 oss_not_implemented,
1649 oss_midi_release,
1650 oss_midi_out_message,
1651 oss_midi_in_message,
1652 oss_midi_notify_wait,
1653 oss_aux_message,
1656 #ifdef _WIN64
1658 typedef UINT PTR32;
1660 static NTSTATUS oss_wow64_test_connect(void *args)
1662 struct
1664 PTR32 name;
1665 enum driver_priority priority;
1666 } *params32 = args;
1667 struct test_connect_params params =
1669 .name = ULongToPtr(params32->name),
1671 oss_test_connect(&params);
1672 params32->priority = params.priority;
1673 return STATUS_SUCCESS;
1676 static NTSTATUS oss_wow64_get_endpoint_ids(void *args)
1678 struct
1680 EDataFlow flow;
1681 PTR32 endpoints;
1682 unsigned int size;
1683 HRESULT result;
1684 unsigned int num;
1685 unsigned int default_idx;
1686 } *params32 = args;
1687 struct get_endpoint_ids_params params =
1689 .flow = params32->flow,
1690 .endpoints = ULongToPtr(params32->endpoints),
1691 .size = params32->size
1693 oss_get_endpoint_ids(&params);
1694 params32->size = params.size;
1695 params32->result = params.result;
1696 params32->num = params.num;
1697 params32->default_idx = params.default_idx;
1698 return STATUS_SUCCESS;
1701 static NTSTATUS oss_wow64_create_stream(void *args)
1703 struct
1705 PTR32 name;
1706 PTR32 device;
1707 EDataFlow flow;
1708 AUDCLNT_SHAREMODE share;
1709 UINT flags;
1710 REFERENCE_TIME duration;
1711 REFERENCE_TIME period;
1712 PTR32 fmt;
1713 HRESULT result;
1714 PTR32 channel_count;
1715 PTR32 stream;
1716 } *params32 = args;
1717 struct create_stream_params params =
1719 .name = ULongToPtr(params32->name),
1720 .device = ULongToPtr(params32->device),
1721 .flow = params32->flow,
1722 .share = params32->share,
1723 .flags = params32->flags,
1724 .duration = params32->duration,
1725 .period = params32->period,
1726 .fmt = ULongToPtr(params32->fmt),
1727 .channel_count = ULongToPtr(params32->channel_count),
1728 .stream = ULongToPtr(params32->stream)
1730 oss_create_stream(&params);
1731 params32->result = params.result;
1732 return STATUS_SUCCESS;
1735 static NTSTATUS oss_wow64_release_stream(void *args)
1737 struct
1739 stream_handle stream;
1740 PTR32 timer_thread;
1741 HRESULT result;
1742 } *params32 = args;
1743 struct release_stream_params params =
1745 .stream = params32->stream,
1746 .timer_thread = ULongToHandle(params32->timer_thread)
1748 oss_release_stream(&params);
1749 params32->result = params.result;
1750 return STATUS_SUCCESS;
1753 static NTSTATUS oss_wow64_get_render_buffer(void *args)
1755 struct
1757 stream_handle stream;
1758 UINT32 frames;
1759 HRESULT result;
1760 PTR32 data;
1761 } *params32 = args;
1762 BYTE *data = NULL;
1763 struct get_render_buffer_params params =
1765 .stream = params32->stream,
1766 .frames = params32->frames,
1767 .data = &data
1769 oss_get_render_buffer(&params);
1770 params32->result = params.result;
1771 *(unsigned int *)ULongToPtr(params32->data) = PtrToUlong(data);
1772 return STATUS_SUCCESS;
1775 static NTSTATUS oss_wow64_get_capture_buffer(void *args)
1777 struct
1779 stream_handle stream;
1780 HRESULT result;
1781 PTR32 data;
1782 PTR32 frames;
1783 PTR32 flags;
1784 PTR32 devpos;
1785 PTR32 qpcpos;
1786 } *params32 = args;
1787 BYTE *data = NULL;
1788 struct get_capture_buffer_params params =
1790 .stream = params32->stream,
1791 .data = &data,
1792 .frames = ULongToPtr(params32->frames),
1793 .flags = ULongToPtr(params32->flags),
1794 .devpos = ULongToPtr(params32->devpos),
1795 .qpcpos = ULongToPtr(params32->qpcpos)
1797 oss_get_capture_buffer(&params);
1798 params32->result = params.result;
1799 *(unsigned int *)ULongToPtr(params32->data) = PtrToUlong(data);
1800 return STATUS_SUCCESS;
1803 static NTSTATUS oss_wow64_is_format_supported(void *args)
1805 struct
1807 PTR32 device;
1808 EDataFlow flow;
1809 AUDCLNT_SHAREMODE share;
1810 PTR32 fmt_in;
1811 PTR32 fmt_out;
1812 HRESULT result;
1813 } *params32 = args;
1814 struct is_format_supported_params params =
1816 .device = ULongToPtr(params32->device),
1817 .flow = params32->flow,
1818 .share = params32->share,
1819 .fmt_in = ULongToPtr(params32->fmt_in),
1820 .fmt_out = ULongToPtr(params32->fmt_out)
1822 oss_is_format_supported(&params);
1823 params32->result = params.result;
1824 return STATUS_SUCCESS;
1827 static NTSTATUS oss_wow64_get_mix_format(void *args)
1829 struct
1831 PTR32 device;
1832 EDataFlow flow;
1833 PTR32 fmt;
1834 HRESULT result;
1835 } *params32 = args;
1836 struct get_mix_format_params params =
1838 .device = ULongToPtr(params32->device),
1839 .flow = params32->flow,
1840 .fmt = ULongToPtr(params32->fmt)
1842 oss_get_mix_format(&params);
1843 params32->result = params.result;
1844 return STATUS_SUCCESS;
1847 static NTSTATUS oss_wow64_get_buffer_size(void *args)
1849 struct
1851 stream_handle stream;
1852 HRESULT result;
1853 PTR32 frames;
1854 } *params32 = args;
1855 struct get_buffer_size_params params =
1857 .stream = params32->stream,
1858 .frames = ULongToPtr(params32->frames)
1860 oss_get_buffer_size(&params);
1861 params32->result = params.result;
1862 return STATUS_SUCCESS;
1865 static NTSTATUS oss_wow64_get_latency(void *args)
1867 struct
1869 stream_handle stream;
1870 HRESULT result;
1871 PTR32 latency;
1872 } *params32 = args;
1873 struct get_latency_params params =
1875 .stream = params32->stream,
1876 .latency = ULongToPtr(params32->latency)
1878 oss_get_latency(&params);
1879 params32->result = params.result;
1880 return STATUS_SUCCESS;
1883 static NTSTATUS oss_wow64_get_current_padding(void *args)
1885 struct
1887 stream_handle stream;
1888 HRESULT result;
1889 PTR32 padding;
1890 } *params32 = args;
1891 struct get_current_padding_params params =
1893 .stream = params32->stream,
1894 .padding = ULongToPtr(params32->padding)
1896 oss_get_current_padding(&params);
1897 params32->result = params.result;
1898 return STATUS_SUCCESS;
1901 static NTSTATUS oss_wow64_get_next_packet_size(void *args)
1903 struct
1905 stream_handle stream;
1906 HRESULT result;
1907 PTR32 frames;
1908 } *params32 = args;
1909 struct get_next_packet_size_params params =
1911 .stream = params32->stream,
1912 .frames = ULongToPtr(params32->frames)
1914 oss_get_next_packet_size(&params);
1915 params32->result = params.result;
1916 return STATUS_SUCCESS;
1919 static NTSTATUS oss_wow64_get_frequency(void *args)
1921 struct
1923 stream_handle stream;
1924 HRESULT result;
1925 PTR32 freq;
1926 } *params32 = args;
1927 struct get_frequency_params params =
1929 .stream = params32->stream,
1930 .freq = ULongToPtr(params32->freq)
1932 oss_get_frequency(&params);
1933 params32->result = params.result;
1934 return STATUS_SUCCESS;
1937 static NTSTATUS oss_wow64_get_position(void *args)
1939 struct
1941 stream_handle stream;
1942 BOOL device;
1943 HRESULT result;
1944 PTR32 pos;
1945 PTR32 qpctime;
1946 } *params32 = args;
1947 struct get_position_params params =
1949 .stream = params32->stream,
1950 .device = params32->device,
1951 .pos = ULongToPtr(params32->pos),
1952 .qpctime = ULongToPtr(params32->qpctime)
1954 oss_get_position(&params);
1955 params32->result = params.result;
1956 return STATUS_SUCCESS;
1959 static NTSTATUS oss_wow64_set_volumes(void *args)
1961 struct
1963 stream_handle stream;
1964 float master_volume;
1965 PTR32 volumes;
1966 PTR32 session_volumes;
1967 int channel;
1968 } *params32 = args;
1969 struct set_volumes_params params =
1971 .stream = params32->stream,
1972 .master_volume = params32->master_volume,
1973 .volumes = ULongToPtr(params32->volumes),
1974 .session_volumes = ULongToPtr(params32->session_volumes),
1975 .channel = params32->channel
1977 return oss_set_volumes(&params);
1980 static NTSTATUS oss_wow64_set_event_handle(void *args)
1982 struct
1984 stream_handle stream;
1985 PTR32 event;
1986 HRESULT result;
1987 } *params32 = args;
1988 struct set_event_handle_params params =
1990 .stream = params32->stream,
1991 .event = ULongToHandle(params32->event)
1994 oss_set_event_handle(&params);
1995 params32->result = params.result;
1996 return STATUS_SUCCESS;
1999 static NTSTATUS oss_wow64_aux_message(void *args)
2001 struct
2003 UINT dev_id;
2004 UINT msg;
2005 UINT user;
2006 UINT param_1;
2007 UINT param_2;
2008 PTR32 err;
2009 } *params32 = args;
2010 struct aux_message_params params =
2012 .dev_id = params32->dev_id,
2013 .msg = params32->msg,
2014 .user = params32->user,
2015 .param_1 = params32->param_1,
2016 .param_2 = params32->param_2,
2017 .err = ULongToPtr(params32->err),
2019 return oss_aux_message(&params);
2022 unixlib_entry_t __wine_unix_call_wow64_funcs[] =
2024 oss_not_implemented,
2025 oss_not_implemented,
2026 oss_not_implemented,
2027 oss_wow64_get_endpoint_ids,
2028 oss_wow64_create_stream,
2029 oss_wow64_release_stream,
2030 oss_start,
2031 oss_stop,
2032 oss_reset,
2033 oss_timer_loop,
2034 oss_wow64_get_render_buffer,
2035 oss_release_render_buffer,
2036 oss_wow64_get_capture_buffer,
2037 oss_release_capture_buffer,
2038 oss_wow64_is_format_supported,
2039 oss_wow64_get_mix_format,
2040 oss_not_implemented,
2041 oss_wow64_get_buffer_size,
2042 oss_wow64_get_latency,
2043 oss_wow64_get_current_padding,
2044 oss_wow64_get_next_packet_size,
2045 oss_wow64_get_frequency,
2046 oss_wow64_get_position,
2047 oss_wow64_set_volumes,
2048 oss_wow64_set_event_handle,
2049 oss_wow64_test_connect,
2050 oss_is_started,
2051 oss_not_implemented,
2052 oss_not_implemented,
2053 oss_midi_release,
2054 oss_wow64_midi_out_message,
2055 oss_wow64_midi_in_message,
2056 oss_wow64_midi_notify_wait,
2057 oss_wow64_aux_message,
2060 #endif /* _WIN64 */