4 * Copyright 2011 Andrew Eikum for CodeWeavers
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
27 #include <sys/types.h>
29 #include <sys/ioctl.h>
33 #include <sys/soundcard.h>
37 #define WIN32_NO_STATUS
40 #include "audioclient.h"
43 #include "wine/debug.h"
44 #include "wine/unixlib.h"
53 AUDCLNT_SHAREMODE share
;
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 */
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
)
84 /* We want to deal with a positive divisor to simplify the logic. */
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
;
95 ret
= (((LONGLONG
)a
* b
) - (c
/ 2)) / c
;
97 if (ret
> 2147483647 || ret
< -2147483647) return -1;
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
)
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
;
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);
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");
147 params
->priority
= Priority_Unavailable
;
148 return STATUS_SUCCESS
;
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
;
176 strcpy(dest
, devnode
);
177 dot
= strrchr(dest
, '.');
181 slash
= strrchr(dest
, '/');
182 if(slash
&& dot
< slash
)
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
])
202 fd
= open_device("/dev/dsp", flow
);
204 WARN("Couldn't open default device!\n");
209 if((err
= ioctl(fd
, SNDCTL_ENGINEINFO
, &ai
)) < 0){
210 WARN("SNDCTL_ENGINEINFO failed: %d (%s)\n", err
, strerror(errno
));
216 TRACE("Default devnode: %s\n", ai
.devnode
);
217 oss_clean_devnode(device
, ai
.devnode
);
221 static NTSTATUS
oss_get_endpoint_ids(void *args
)
223 struct get_endpoint_ids_params
*params
= args
;
226 static int print_once
= 0;
227 static const WCHAR outW
[] = {'O','u','t',':',' ',0};
228 static const WCHAR inW
[] = {'I','n',':',' ',0};
231 WCHAR name
[ARRAY_SIZE(ai
.name
) + ARRAY_SIZE(outW
)];
232 char device
[OSS_DEVNODE_SIZE
];
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
;
239 mixer_fd
= open("/dev/mixer", O_RDONLY
, 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){
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
;
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
);
271 if(sysinfo
.numaudios
<= 0){
272 WARN("No audio devices!\n");
274 params
->result
= AUDCLNT_E_SERVICE_NOT_RUNNING
;
275 return STATUS_SUCCESS
;
278 info
= malloc(sysinfo
.numaudios
* sizeof(*info
));
281 params
->result
= E_OUTOFMEMORY
;
282 return STATUS_SUCCESS
;
285 get_default_device(params
->flow
, default_device
);
288 for(i
= 0; i
< sysinfo
.numaudios
; ++i
){
289 char devnode
[OSS_DEVNODE_SIZE
];
293 memset(&ai
, 0, sizeof(ai
));
295 if(ioctl(mixer_fd
, SNDCTL_AUDIOINFO
, &ai
) < 0){
296 WARN("Error getting AUDIOINFO for dev %d: %d (%s)\n", i
, errno
,
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
))
310 fd
= open_device(devnode
, params
->flow
);
312 WARN("Opening device \"%s\" failed, pretending it doesn't exist: %d (%s)\n",
313 devnode
, errno
, strerror(errno
));
318 if((params
->flow
== eCapture
&& !(ai
.caps
& PCM_CAP_INPUT
)) ||
319 (params
->flow
== eRender
&& !(ai
.caps
& PCM_CAP_OUTPUT
)))
322 strcpy(info
[num
].device
, devnode
);
324 if(params
->flow
== eRender
){
326 prefix_len
= ARRAY_SIZE(outW
) - 1;
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
))
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;
361 params
->default_idx
= default_idx
;
363 if(needed
> params
->size
){
364 params
->size
= needed
;
365 params
->result
= HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER
);
367 params
->result
= S_OK
;
369 return STATUS_SUCCESS
;
372 static UINT
get_channel_mask(unsigned int channels
)
378 return KSAUDIO_SPEAKER_MONO
;
380 return KSAUDIO_SPEAKER_STEREO
;
382 return KSAUDIO_SPEAKER_STEREO
| SPEAKER_LOW_FREQUENCY
;
384 return KSAUDIO_SPEAKER_QUAD
; /* not _SURROUND */
386 return KSAUDIO_SPEAKER_QUAD
| SPEAKER_LOW_FREQUENCY
;
388 return KSAUDIO_SPEAKER_5POINT1
; /* not 5POINT1_SURROUND */
390 return KSAUDIO_SPEAKER_5POINT1
| SPEAKER_BACK_CENTER
;
392 return KSAUDIO_SPEAKER_7POINT1_SURROUND
; /* Vista deprecates 7POINT1 */
394 FIXME("Unknown speaker configuration: %u\n", channels
);
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
){
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)
432 static WAVEFORMATEXTENSIBLE
*clone_format(const WAVEFORMATEX
*fmt
)
434 WAVEFORMATEXTENSIBLE
*ret
;
437 if(fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
438 size
= sizeof(WAVEFORMATEXTENSIBLE
);
440 size
= sizeof(WAVEFORMATEX
);
446 memcpy(ret
, fmt
, size
);
448 ret
->Format
.cbSize
= size
- sizeof(WAVEFORMATEX
);
453 static HRESULT
setup_oss_device(AUDCLNT_SHAREMODE share
, int fd
,
454 const WAVEFORMATEX
*fmt
, WAVEFORMATEXTENSIBLE
*out
)
456 const WAVEFORMATEXTENSIBLE
*fmtex
= (const WAVEFORMATEXTENSIBLE
*)fmt
;
460 WAVEFORMATEXTENSIBLE
*closest
;
462 tmp
= oss_format
= get_oss_format(fmt
);
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
));
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
))
480 if(fmt
->nChannels
== 0)
481 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
483 closest
= clone_format(fmt
);
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
));
493 tenth
= fmt
->nSamplesPerSec
* 0.1;
494 if(tmp
> fmt
->nSamplesPerSec
+ tenth
|| tmp
< fmt
->nSamplesPerSec
- tenth
){
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
));
505 if(tmp
!= fmt
->nChannels
){
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
))
519 if(share
== AUDCLNT_SHAREMODE_EXCLUSIVE
&&
520 fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
){
521 if(fmtex
->dwChannelMask
== 0 || fmtex
->dwChannelMask
& SPEAKER_RESERVED
)
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
));
539 TRACE("returning: %08x\n", (unsigned)ret
);
543 static ULONG_PTR
zero_bits(void)
546 return !NtCurrentTeb()->WowTebOffset
? 0 : 0x7fffffff;
552 static NTSTATUS
oss_create_stream(void *args
)
554 struct create_stream_params
*params
= args
;
555 WAVEFORMATEXTENSIBLE
*fmtex
;
556 struct oss_stream
*stream
;
560 stream
= calloc(1, sizeof(*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
);
571 WARN("Unable to open device %s: %d (%s)\n", params
->device
, errno
, strerror(errno
));
572 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
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
;
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
))
600 fmtex
= clone_format(params
->fmt
);
602 params
->result
= E_OUTOFMEMORY
;
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
;
620 stream
->share
= params
->share
;
621 stream
->flags
= params
->flags
;
622 stream
->oss_bufsize_bytes
= 0;
625 if(FAILED(params
->result
)){
626 if(stream
->fd
>= 0) close(stream
->fd
);
627 if(stream
->local_buffer
){
629 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream
->local_buffer
, &size
, MEM_RELEASE
);
631 pthread_mutex_destroy(&stream
->lock
);
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
);
647 if(params
->timer_thread
){
648 stream
->please_quit
= TRUE
;
649 NtWaitForSingleObject(params
->timer_thread
, FALSE
, NULL
);
650 NtClose(params
->timer_thread
);
654 if(stream
->local_buffer
){
656 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream
->local_buffer
, &size
, MEM_RELEASE
);
658 if(stream
->tmp_buffer
){
660 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream
->tmp_buffer
, &size
, MEM_RELEASE
);
663 pthread_mutex_destroy(&stream
->lock
);
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
);
677 if((stream
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
) && !stream
->event
)
678 return oss_unlock_result(stream
, ¶ms
->result
, AUDCLNT_E_EVENTHANDLE_NOT_SET
);
681 return oss_unlock_result(stream
, ¶ms
->result
, AUDCLNT_E_NOT_STOPPED
);
683 stream
->playing
= TRUE
;
685 return oss_unlock_result(stream
, ¶ms
->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
);
696 return oss_unlock_result(stream
, ¶ms
->result
, S_FALSE
);
698 stream
->playing
= FALSE
;
699 stream
->in_oss_frames
= 0;
701 return oss_unlock_result(stream
, ¶ms
->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
);
712 return oss_unlock_result(stream
, ¶ms
->result
, AUDCLNT_E_NOT_STOPPED
);
714 if(stream
->getbuf_last
)
715 return oss_unlock_result(stream
, ¶ms
->result
, AUDCLNT_E_BUFFER_OPERATION_PENDING
);
717 if(stream
->flow
== eRender
){
718 stream
->written_frames
= 0;
719 stream
->last_pos_frames
= 0;
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
, ¶ms
->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
);
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
;
750 if(ioctl(stream
->fd
, SNDCTL_DSP_GETOSPACE
, &bi
) < 0){
751 WARN("GETOSPACE failed: %d (%s)\n", errno
, strerror(errno
));
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
;
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
;
772 while(write_limit
+ in_oss_frames
< max_period
* 3)
773 write_limit
+= max_period
;
777 /* vvvvvv - in_oss_frames
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
)
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
;
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
;
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
));
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 */
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
;
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
));
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
;
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
,
863 WARN("read failed: %d (%s)\n", errno
, strerror(errno
));
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
;
886 delay
.QuadPart
= -stream
->period
;
887 NtQueryPerformanceCounter(&now
, NULL
);
888 next
.QuadPart
= now
.QuadPart
+ stream
->period
;
890 while(!stream
->please_quit
){
892 if(stream
->flow
== eRender
&& stream
->held_frames
)
893 oss_write_data(stream
);
894 else if(stream
->flow
== eCapture
)
895 oss_read_data(stream
);
898 NtSetEvent(stream
->event
, NULL
);
901 NtDelayExecution(FALSE
, &delay
);
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
;
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
;
929 if(stream
->getbuf_last
)
930 return oss_unlock_result(stream
, ¶ms
->result
, AUDCLNT_E_OUT_OF_ORDER
);
933 return oss_unlock_result(stream
, ¶ms
->result
, S_OK
);
935 if(stream
->held_frames
+ frames
> stream
->bufsize_frames
)
936 return oss_unlock_result(stream
, ¶ms
->result
, AUDCLNT_E_BUFFER_TOO_LARGE
);
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
){
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
, ¶ms
->result
, E_OUTOFMEMORY
);
953 stream
->tmp_buffer_frames
= frames
;
955 *data
= stream
->tmp_buffer
;
956 stream
->getbuf_last
= -frames
;
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
, ¶ms
->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
);
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
;
996 stream
->getbuf_last
= 0;
997 return oss_unlock_result(stream
, ¶ms
->result
, S_OK
);
1000 if(!stream
->getbuf_last
)
1001 return oss_unlock_result(stream
, ¶ms
->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
, ¶ms
->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
);
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
, ¶ms
->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
;
1037 if(stream
->getbuf_last
)
1038 return oss_unlock_result(stream
, ¶ms
->result
, AUDCLNT_E_OUT_OF_ORDER
);
1040 if(stream
->held_frames
< stream
->period_frames
){
1042 return oss_unlock_result(stream
, ¶ms
->result
, AUDCLNT_S_BUFFER_EMPTY
);
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
){
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
, ¶ms
->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
);
1075 *data
= stream
->local_buffer
+
1076 stream
->lcl_offs_frames
* stream
->fmt
->nBlockAlign
;
1078 stream
->getbuf_last
= *frames
;
1081 *devpos
= stream
->written_frames
;
1083 LARGE_INTEGER stamp
, freq
;
1084 NtQueryPerformanceCounter(&stamp
, &freq
);
1085 *qpcpos
= (stamp
.QuadPart
* (INT64
)10000000) / freq
.QuadPart
;
1088 return oss_unlock_result(stream
, ¶ms
->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
;
1100 stream
->getbuf_last
= 0;
1101 return oss_unlock_result(stream
, ¶ms
->result
, S_OK
);
1104 if(!stream
->getbuf_last
)
1105 return oss_unlock_result(stream
, ¶ms
->result
, AUDCLNT_E_OUT_OF_ORDER
);
1107 if(stream
->getbuf_last
!= done
)
1108 return oss_unlock_result(stream
, ¶ms
->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
, ¶ms
->result
, S_OK
);
1119 static NTSTATUS
oss_is_format_supported(void *args
)
1121 struct is_format_supported_params
*params
= args
;
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
);
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
);
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
;
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
);
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
;
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
));
1171 params
->result
= E_FAIL
;
1172 return STATUS_SUCCESS
;
1176 if(params
->flow
== eRender
)
1177 formats
= ai
.oformats
;
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
;
1186 }else if(formats
& AFMT_FLOAT
){
1187 fmt
->Format
.wBitsPerSample
= 32;
1188 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
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
;
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;
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;
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
);
1255 *params
->frames
= stream
->bufsize_frames
;
1257 return oss_unlock_result(stream
, ¶ms
->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
);
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
, ¶ms
->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
);
1281 *params
->padding
= stream
->held_frames
;
1283 return oss_unlock_result(stream
, ¶ms
->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
;
1294 *frames
= stream
->held_frames
< stream
->period_frames
? 0 : stream
->period_frames
;
1296 return oss_unlock_result(stream
, ¶ms
->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
;
1307 if(stream
->share
== AUDCLNT_SHAREMODE_SHARED
)
1308 *freq
= (UINT64
)stream
->fmt
->nSamplesPerSec
* stream
->fmt
->nBlockAlign
;
1310 *freq
= stream
->fmt
->nSamplesPerSec
;
1312 return oss_unlock_result(stream
, ¶ms
->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
;
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
){
1331 if(ioctl(stream
->fd
, SNDCTL_DSP_GETISPACE
, &bi
) < 0){
1332 TRACE("GETISPACE failed: %d (%s)\n", errno
, strerror(errno
));
1335 if(bi
.bytes
<= bi
.fragsize
)
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
;
1351 LARGE_INTEGER stamp
, freq
;
1352 NtQueryPerformanceCounter(&stamp
, &freq
);
1353 *qpctime
= (stamp
.QuadPart
* (INT64
)10000000) / freq
.QuadPart
;
1356 return oss_unlock_result(stream
, ¶ms
->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
);
1365 stream
->mute
= !params
->master_volume
;
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
);
1378 if(!(stream
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
))
1379 return oss_unlock_result(stream
, ¶ms
->result
, AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED
);
1382 FIXME("called twice\n");
1383 return oss_unlock_result(stream
, ¶ms
->result
, HRESULT_FROM_WIN32(ERROR_INVALID_NAME
));
1386 stream
->event
= params
->event
;
1388 return oss_unlock_result(stream
, ¶ms
->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
);
1398 return oss_unlock_result(stream
, ¶ms
->result
, stream
->playing
? S_OK
: S_FALSE
);
1403 static unsigned int num_aux
;
1405 #define MIXER_DEV "/dev/mixer"
1407 static UINT
aux_init(void)
1413 if ((mixer
= open(MIXER_DEV
, O_RDWR
)) < 0)
1415 WARN("mixer device not available !\n");
1426 static UINT
aux_exit(void)
1432 static UINT
aux_get_devcaps(WORD dev_id
, AUXCAPSW
*caps
, UINT size
)
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)
1448 WARN("unable to read mixer !\n");
1449 return MMSYSERR_NOTENABLED
;
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
;
1478 TRACE("SOUND_MIXER_READ_PCM !\n");
1479 cmd
= SOUND_MIXER_READ_PCM
;
1482 TRACE("SOUND_MIXER_READ_SYNTH !\n");
1483 cmd
= SOUND_MIXER_READ_SYNTH
;
1486 TRACE("SOUND_MIXER_READ_CD !\n");
1487 cmd
= SOUND_MIXER_READ_CD
;
1490 TRACE("SOUND_MIXER_READ_LINE !\n");
1491 cmd
= SOUND_MIXER_READ_LINE
;
1494 TRACE("SOUND_MIXER_READ_MIC !\n");
1495 cmd
= SOUND_MIXER_READ_MIC
;
1498 TRACE("SOUND_MIXER_READ_VOLUME !\n");
1499 cmd
= SOUND_MIXER_READ_VOLUME
;
1502 WARN("invalid device id=%04X !\n", dev_id
);
1504 return MMSYSERR_NOTENABLED
;
1506 if (ioctl(mixer
, cmd
, &volume
) == -1)
1508 WARN("unable to read mixer !\n");
1510 return MMSYSERR_NOTENABLED
;
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
)
1523 int volume
, left
, right
;
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
;
1541 TRACE("SOUND_MIXER_WRITE_PCM !\n");
1542 cmd
= SOUND_MIXER_WRITE_PCM
;
1545 TRACE("SOUND_MIXER_WRITE_SYNTH !\n");
1546 cmd
= SOUND_MIXER_WRITE_SYNTH
;
1549 TRACE("SOUND_MIXER_WRITE_CD !\n");
1550 cmd
= SOUND_MIXER_WRITE_CD
;
1553 TRACE("SOUND_MIXER_WRITE_LINE !\n");
1554 cmd
= SOUND_MIXER_WRITE_LINE
;
1557 TRACE("SOUND_MIXER_WRITE_MIC !\n");
1558 cmd
= SOUND_MIXER_WRITE_MIC
;
1561 TRACE("SOUND_MIXER_WRITE_VOLUME !\n");
1562 cmd
= SOUND_MIXER_WRITE_VOLUME
;
1565 WARN("invalid device id=%04X !\n", dev_id
);
1567 return MMSYSERR_NOTENABLED
;
1569 if (ioctl(mixer
, cmd
, &volume
) == -1)
1571 WARN("unable to set mixer !\n");
1573 return MMSYSERR_NOTENABLED
;
1576 return MMSYSERR_NOERROR
;
1579 static NTSTATUS
oss_aux_message(void *args
)
1581 struct aux_message_params
*params
= args
;
1583 switch (params
->msg
)
1586 *params
->err
= aux_init();
1589 *params
->err
= aux_exit();
1593 /* FIXME: Pretend this is supported */
1596 case AUXDM_GETDEVCAPS
:
1597 *params
->err
= aux_get_devcaps(params
->dev_id
, (AUXCAPSW
*)params
->param_1
, params
->param_2
);
1599 case AUXDM_GETNUMDEVS
:
1600 TRACE("return %d;\n", num_aux
);
1601 *params
->err
= num_aux
;
1603 case AUXDM_GETVOLUME
:
1604 *params
->err
= aux_get_volume(params
->dev_id
, (UINT
*)params
->param_1
);
1606 case AUXDM_SETVOLUME
:
1607 *params
->err
= aux_set_volume(params
->dev_id
, params
->param_1
);
1610 WARN("unknown message !\n");
1611 *params
->err
= MMSYSERR_NOTSUPPORTED
;
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
,
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
,
1636 oss_not_implemented
,
1637 oss_get_buffer_size
,
1639 oss_get_current_padding
,
1640 oss_get_next_packet_size
,
1644 oss_set_event_handle
,
1647 oss_not_implemented
,
1648 oss_not_implemented
,
1650 oss_midi_out_message
,
1651 oss_midi_in_message
,
1652 oss_midi_notify_wait
,
1660 static NTSTATUS
oss_wow64_test_connect(void *args
)
1665 enum driver_priority priority
;
1667 struct test_connect_params params
=
1669 .name
= ULongToPtr(params32
->name
),
1671 oss_test_connect(¶ms
);
1672 params32
->priority
= params
.priority
;
1673 return STATUS_SUCCESS
;
1676 static NTSTATUS
oss_wow64_get_endpoint_ids(void *args
)
1685 unsigned int default_idx
;
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(¶ms
);
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
)
1708 AUDCLNT_SHAREMODE share
;
1710 REFERENCE_TIME duration
;
1711 REFERENCE_TIME period
;
1714 PTR32 channel_count
;
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(¶ms
);
1731 params32
->result
= params
.result
;
1732 return STATUS_SUCCESS
;
1735 static NTSTATUS
oss_wow64_release_stream(void *args
)
1739 stream_handle stream
;
1743 struct release_stream_params params
=
1745 .stream
= params32
->stream
,
1746 .timer_thread
= ULongToHandle(params32
->timer_thread
)
1748 oss_release_stream(¶ms
);
1749 params32
->result
= params
.result
;
1750 return STATUS_SUCCESS
;
1753 static NTSTATUS
oss_wow64_get_render_buffer(void *args
)
1757 stream_handle stream
;
1763 struct get_render_buffer_params params
=
1765 .stream
= params32
->stream
,
1766 .frames
= params32
->frames
,
1769 oss_get_render_buffer(¶ms
);
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
)
1779 stream_handle stream
;
1788 struct get_capture_buffer_params params
=
1790 .stream
= params32
->stream
,
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(¶ms
);
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
)
1809 AUDCLNT_SHAREMODE share
;
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(¶ms
);
1823 params32
->result
= params
.result
;
1824 return STATUS_SUCCESS
;
1827 static NTSTATUS
oss_wow64_get_mix_format(void *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(¶ms
);
1843 params32
->result
= params
.result
;
1844 return STATUS_SUCCESS
;
1847 static NTSTATUS
oss_wow64_get_buffer_size(void *args
)
1851 stream_handle stream
;
1855 struct get_buffer_size_params params
=
1857 .stream
= params32
->stream
,
1858 .frames
= ULongToPtr(params32
->frames
)
1860 oss_get_buffer_size(¶ms
);
1861 params32
->result
= params
.result
;
1862 return STATUS_SUCCESS
;
1865 static NTSTATUS
oss_wow64_get_latency(void *args
)
1869 stream_handle stream
;
1873 struct get_latency_params params
=
1875 .stream
= params32
->stream
,
1876 .latency
= ULongToPtr(params32
->latency
)
1878 oss_get_latency(¶ms
);
1879 params32
->result
= params
.result
;
1880 return STATUS_SUCCESS
;
1883 static NTSTATUS
oss_wow64_get_current_padding(void *args
)
1887 stream_handle stream
;
1891 struct get_current_padding_params params
=
1893 .stream
= params32
->stream
,
1894 .padding
= ULongToPtr(params32
->padding
)
1896 oss_get_current_padding(¶ms
);
1897 params32
->result
= params
.result
;
1898 return STATUS_SUCCESS
;
1901 static NTSTATUS
oss_wow64_get_next_packet_size(void *args
)
1905 stream_handle stream
;
1909 struct get_next_packet_size_params params
=
1911 .stream
= params32
->stream
,
1912 .frames
= ULongToPtr(params32
->frames
)
1914 oss_get_next_packet_size(¶ms
);
1915 params32
->result
= params
.result
;
1916 return STATUS_SUCCESS
;
1919 static NTSTATUS
oss_wow64_get_frequency(void *args
)
1923 stream_handle stream
;
1927 struct get_frequency_params params
=
1929 .stream
= params32
->stream
,
1930 .freq
= ULongToPtr(params32
->freq
)
1932 oss_get_frequency(¶ms
);
1933 params32
->result
= params
.result
;
1934 return STATUS_SUCCESS
;
1937 static NTSTATUS
oss_wow64_get_position(void *args
)
1941 stream_handle stream
;
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(¶ms
);
1955 params32
->result
= params
.result
;
1956 return STATUS_SUCCESS
;
1959 static NTSTATUS
oss_wow64_set_volumes(void *args
)
1963 stream_handle stream
;
1964 float master_volume
;
1966 PTR32 session_volumes
;
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(¶ms
);
1980 static NTSTATUS
oss_wow64_set_event_handle(void *args
)
1984 stream_handle stream
;
1988 struct set_event_handle_params params
=
1990 .stream
= params32
->stream
,
1991 .event
= ULongToHandle(params32
->event
)
1994 oss_set_event_handle(¶ms
);
1995 params32
->result
= params
.result
;
1996 return STATUS_SUCCESS
;
1999 static NTSTATUS
oss_wow64_aux_message(void *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(¶ms
);
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
,
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
,
2051 oss_not_implemented
,
2052 oss_not_implemented
,
2054 oss_wow64_midi_out_message
,
2055 oss_wow64_midi_in_message
,
2056 oss_wow64_midi_notify_wait
,
2057 oss_wow64_aux_message
,