2 This file is part of PulseAudio.
4 Copyright 2006 Lennart Poettering
5 Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
30 #include <pulse/mainloop-api.h>
32 #include <pulse/xmalloc.h>
33 #include <pulse/timeval.h>
35 #include <pulsecore/sink.h>
36 #include <pulsecore/source.h>
37 #include <pulsecore/module.h>
38 #include <pulsecore/modargs.h>
39 #include <pulsecore/sample-util.h>
40 #include <pulsecore/core-util.h>
41 #include <pulsecore/log.h>
43 #include "module-waveout-symdef.h"
45 PA_MODULE_AUTHOR("Pierre Ossman")
46 PA_MODULE_DESCRIPTION("Windows waveOut Sink/Source")
47 PA_MODULE_VERSION(PACKAGE_VERSION
)
49 "sink_name=<name for the sink> "
50 "source_name=<name for the source> "
51 "device=<device number> "
52 "record=<enable source?> "
53 "playback=<enable sink?> "
54 "format=<sample format> "
55 "channels=<number of channels> "
57 "fragments=<number of fragments> "
58 "fragment_size=<fragment size> "
59 "channel_map=<channel map>")
61 #define DEFAULT_SINK_NAME "wave_output"
62 #define DEFAULT_SOURCE_NAME "wave_input"
64 #define WAVEOUT_MAX_VOLUME 0xFFFF
71 pa_defer_event
*defer
;
72 pa_usec_t poll_timeout
;
74 uint32_t fragments
, fragment_size
;
76 uint32_t free_ofrags
, free_ifrags
;
81 int cur_ohdr
, cur_ihdr
;
82 WAVEHDR
*ohdrs
, *ihdrs
;
88 CRITICAL_SECTION crit
;
91 static const char* const valid_modargs
[] = {
106 static void update_usage(struct userdata
*u
) {
107 pa_module_set_used(u
->module
,
108 (u
->sink
? pa_sink_used_by(u
->sink
) : 0) +
109 (u
->source
? pa_source_used_by(u
->source
) : 0));
112 static void do_write(struct userdata
*u
)
115 pa_memchunk memchunk
;
122 EnterCriticalSection(&u
->crit
);
123 free_frags
= u
->free_ofrags
;
124 LeaveCriticalSection(&u
->crit
);
126 if (!u
->sink_underflow
&& (free_frags
== u
->fragments
))
127 pa_log_debug("WaveOut underflow!");
130 hdr
= &u
->ohdrs
[u
->cur_ohdr
];
131 if (hdr
->dwFlags
& WHDR_PREPARED
)
132 waveOutUnprepareHeader(u
->hwo
, hdr
, sizeof(WAVEHDR
));
134 hdr
->dwBufferLength
= 0;
135 while (hdr
->dwBufferLength
< u
->fragment_size
) {
138 len
= u
->fragment_size
- hdr
->dwBufferLength
;
140 if (pa_sink_render(u
->sink
, len
, &memchunk
) < 0)
143 assert(memchunk
.memblock
);
144 assert(memchunk
.memblock
->data
);
145 assert(memchunk
.length
);
147 if (memchunk
.length
< len
)
148 len
= memchunk
.length
;
150 memcpy(hdr
->lpData
+ hdr
->dwBufferLength
,
151 (char*)memchunk
.memblock
->data
+ memchunk
.index
, len
);
153 hdr
->dwBufferLength
+= len
;
155 pa_memblock_unref(memchunk
.memblock
);
156 memchunk
.memblock
= NULL
;
159 /* Insufficient data in sink buffer? */
160 if (hdr
->dwBufferLength
== 0) {
161 u
->sink_underflow
= 1;
165 u
->sink_underflow
= 0;
167 res
= waveOutPrepareHeader(u
->hwo
, hdr
, sizeof(WAVEHDR
));
168 if (res
!= MMSYSERR_NOERROR
) {
169 pa_log_error(__FILE__
": ERROR: Unable to prepare waveOut block: %d",
172 res
= waveOutWrite(u
->hwo
, hdr
, sizeof(WAVEHDR
));
173 if (res
!= MMSYSERR_NOERROR
) {
174 pa_log_error(__FILE__
": ERROR: Unable to write waveOut block: %d",
178 u
->written_bytes
+= hdr
->dwBufferLength
;
180 EnterCriticalSection(&u
->crit
);
182 LeaveCriticalSection(&u
->crit
);
186 u
->cur_ohdr
%= u
->fragments
;
190 static void do_read(struct userdata
*u
)
193 pa_memchunk memchunk
;
200 EnterCriticalSection(&u
->crit
);
202 free_frags
= u
->free_ifrags
;
205 LeaveCriticalSection(&u
->crit
);
207 if (free_frags
== u
->fragments
)
208 pa_log_debug("WaveIn overflow!");
211 hdr
= &u
->ihdrs
[u
->cur_ihdr
];
212 if (hdr
->dwFlags
& WHDR_PREPARED
)
213 waveInUnprepareHeader(u
->hwi
, hdr
, sizeof(WAVEHDR
));
215 if (hdr
->dwBytesRecorded
) {
216 memchunk
.memblock
= pa_memblock_new(u
->core
->mempool
, hdr
->dwBytesRecorded
);
217 assert(memchunk
.memblock
);
219 memcpy((char*)memchunk
.memblock
->data
, hdr
->lpData
, hdr
->dwBytesRecorded
);
221 memchunk
.length
= memchunk
.memblock
->length
= hdr
->dwBytesRecorded
;
224 pa_source_post(u
->source
, &memchunk
);
225 pa_memblock_unref(memchunk
.memblock
);
228 res
= waveInPrepareHeader(u
->hwi
, hdr
, sizeof(WAVEHDR
));
229 if (res
!= MMSYSERR_NOERROR
) {
230 pa_log_error(__FILE__
": ERROR: Unable to prepare waveIn block: %d",
233 res
= waveInAddBuffer(u
->hwi
, hdr
, sizeof(WAVEHDR
));
234 if (res
!= MMSYSERR_NOERROR
) {
235 pa_log_error(__FILE__
": ERROR: Unable to add waveIn block: %d",
241 u
->cur_ihdr
%= u
->fragments
;
245 static void poll_cb(pa_mainloop_api
*a
, pa_time_event
*e
, const struct timeval
*tv
, void *userdata
) {
246 struct userdata
*u
= userdata
;
256 pa_gettimeofday(&ntv
);
257 pa_timeval_add(&ntv
, u
->poll_timeout
);
259 a
->rtclock_time_restart(e
, &ntv
);
262 static void defer_cb(pa_mainloop_api
*a
, pa_defer_event
*e
, void *userdata
) {
263 struct userdata
*u
= userdata
;
267 a
->defer_enable(e
, 0);
273 static void CALLBACK
chunk_done_cb(HWAVEOUT hwo
, UINT msg
, DWORD_PTR inst
, DWORD param1
, DWORD param2
) {
274 struct userdata
*u
= (struct userdata
*)inst
;
279 EnterCriticalSection(&u
->crit
);
282 assert(u
->free_ofrags
<= u
->fragments
);
284 LeaveCriticalSection(&u
->crit
);
287 static void CALLBACK
chunk_ready_cb(HWAVEIN hwi
, UINT msg
, DWORD_PTR inst
, DWORD param1
, DWORD param2
) {
288 struct userdata
*u
= (struct userdata
*)inst
;
293 EnterCriticalSection(&u
->crit
);
296 assert(u
->free_ifrags
<= u
->fragments
);
298 LeaveCriticalSection(&u
->crit
);
301 static pa_usec_t
sink_get_latency_cb(pa_sink
*s
) {
302 struct userdata
*u
= s
->userdata
;
305 assert(s
&& u
&& u
->sink
);
307 memset(&mmt
, 0, sizeof(mmt
));
308 mmt
.wType
= TIME_BYTES
;
309 if (waveOutGetPosition(u
->hwo
, &mmt
, sizeof(mmt
)) == MMSYSERR_NOERROR
)
310 return pa_bytes_to_usec(u
->written_bytes
- mmt
.u
.cb
, &s
->sample_spec
);
312 EnterCriticalSection(&u
->crit
);
314 free_frags
= u
->free_ofrags
;
316 LeaveCriticalSection(&u
->crit
);
318 return pa_bytes_to_usec((u
->fragments
- free_frags
) * u
->fragment_size
,
323 static pa_usec_t
source_get_latency_cb(pa_source
*s
) {
325 struct userdata
*u
= s
->userdata
;
327 assert(s
&& u
&& u
->sink
);
329 EnterCriticalSection(&u
->crit
);
331 free_frags
= u
->free_ifrags
;
333 LeaveCriticalSection(&u
->crit
);
335 r
+= pa_bytes_to_usec((free_frags
+ 1) * u
->fragment_size
, &s
->sample_spec
);
340 static void notify_sink_cb(pa_sink
*s
) {
341 struct userdata
*u
= s
->userdata
;
344 u
->core
->mainloop
->defer_enable(u
->defer
, 1);
347 static void notify_source_cb(pa_source
*s
) {
348 struct userdata
*u
= s
->userdata
;
351 u
->core
->mainloop
->defer_enable(u
->defer
, 1);
354 static int sink_get_hw_volume_cb(pa_sink
*s
) {
355 struct userdata
*u
= s
->userdata
;
357 pa_volume_t left
, right
;
359 if (waveOutGetVolume(u
->hwo
, &vol
) != MMSYSERR_NOERROR
)
362 left
= (vol
& 0xFFFF) * PA_VOLUME_NORM
/ WAVEOUT_MAX_VOLUME
;
363 right
= ((vol
>> 16) & 0xFFFF) * PA_VOLUME_NORM
/ WAVEOUT_MAX_VOLUME
;
365 /* Windows supports > 2 channels, except for volume control */
366 if (s
->hw_volume
.channels
> 2)
367 pa_cvolume_set(&s
->hw_volume
, s
->hw_volume
.channels
, (left
+ right
)/2);
369 s
->hw_volume
.values
[0] = left
;
370 if (s
->hw_volume
.channels
> 1)
371 s
->hw_volume
.values
[1] = right
;
376 static int sink_set_hw_volume_cb(pa_sink
*s
) {
377 struct userdata
*u
= s
->userdata
;
380 vol
= s
->hw_volume
.values
[0] * WAVEOUT_MAX_VOLUME
/ PA_VOLUME_NORM
;
381 if (s
->hw_volume
.channels
> 1)
382 vol
|= (s
->hw_volume
.values
[0] * WAVEOUT_MAX_VOLUME
/ PA_VOLUME_NORM
) << 16;
384 if (waveOutSetVolume(u
->hwo
, vol
) != MMSYSERR_NOERROR
)
390 static int ss_to_waveformat(pa_sample_spec
*ss
, LPWAVEFORMATEX wf
) {
391 wf
->wFormatTag
= WAVE_FORMAT_PCM
;
393 if (ss
->channels
> 2) {
394 pa_log_error("ERROR: More than two channels not supported.");
398 wf
->nChannels
= ss
->channels
;
407 pa_log_error("ERROR: Unsupported sample rate.");
411 wf
->nSamplesPerSec
= ss
->rate
;
413 if (ss
->format
== PA_SAMPLE_U8
)
414 wf
->wBitsPerSample
= 8;
415 else if (ss
->format
== PA_SAMPLE_S16NE
)
416 wf
->wBitsPerSample
= 16;
418 pa_log_error("ERROR: Unsupported sample format.");
422 wf
->nBlockAlign
= wf
->nChannels
* wf
->wBitsPerSample
/8;
423 wf
->nAvgBytesPerSec
= wf
->nSamplesPerSec
* wf
->nBlockAlign
;
430 int pa__init(pa_core
*c
, pa_module
*m
) {
431 struct userdata
*u
= NULL
;
432 HWAVEOUT hwo
= INVALID_HANDLE_VALUE
;
433 HWAVEIN hwi
= INVALID_HANDLE_VALUE
;
435 int nfrags
, frag_size
;
436 int record
= 1, playback
= 1;
440 pa_modargs
*ma
= NULL
;
446 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
447 pa_log("failed to parse module arguments.");
451 if (pa_modargs_get_value_boolean(ma
, "record", &record
) < 0 || pa_modargs_get_value_boolean(ma
, "playback", &playback
) < 0) {
452 pa_log("record= and playback= expect boolean argument.");
456 if (!playback
&& !record
) {
457 pa_log("neither playback nor record enabled for device.");
461 device
= WAVE_MAPPER
;
462 if (pa_modargs_get_value_u32(ma
, "device", &device
) < 0) {
463 pa_log("failed to parse device argument");
469 if (pa_modargs_get_value_s32(ma
, "fragments", &nfrags
) < 0 || pa_modargs_get_value_s32(ma
, "fragment_size", &frag_size
) < 0) {
470 pa_log("failed to parse fragments arguments");
474 ss
= c
->default_sample_spec
;
475 if (pa_modargs_get_sample_spec_and_channel_map(ma
, &ss
, &map
, PA_CHANNEL_MAP_WAVEEX
) < 0) {
476 pa_log("failed to parse sample specification");
480 if (ss_to_waveformat(&ss
, &wf
) < 0)
483 u
= pa_xmalloc(sizeof(struct userdata
));
486 if (waveInOpen(&hwi
, device
, &wf
, (DWORD_PTR
)chunk_ready_cb
, (DWORD_PTR
)u
, CALLBACK_FUNCTION
) != MMSYSERR_NOERROR
) {
487 pa_log("failed to open waveIn");
490 if (waveInStart(hwi
) != MMSYSERR_NOERROR
) {
491 pa_log("failed to start waveIn");
494 pa_log_debug("Opened waveIn subsystem.");
498 if (waveOutOpen(&hwo
, device
, &wf
, (DWORD_PTR
)chunk_done_cb
, (DWORD_PTR
)u
, CALLBACK_FUNCTION
) != MMSYSERR_NOERROR
) {
499 pa_log("failed to open waveOut");
502 pa_log_debug("Opened waveOut subsystem.");
505 InitializeCriticalSection(&u
->crit
);
507 if (hwi
!= INVALID_HANDLE_VALUE
) {
508 u
->source
= pa_source_new(c
, __FILE__
, pa_modargs_get_value(ma
, "source_name", DEFAULT_SOURCE_NAME
), 0, &ss
, &map
);
510 u
->source
->userdata
= u
;
511 u
->source
->notify
= notify_source_cb
;
512 u
->source
->get_latency
= source_get_latency_cb
;
513 pa_source_set_owner(u
->source
, m
);
514 pa_source_set_description(u
->source
, "Windows waveIn PCM");
515 u
->source
->is_hardware
= 1;
519 if (hwo
!= INVALID_HANDLE_VALUE
) {
520 u
->sink
= pa_sink_new(c
, __FILE__
, pa_modargs_get_value(ma
, "sink_name", DEFAULT_SINK_NAME
), 0, &ss
, &map
);
522 u
->sink
->notify
= notify_sink_cb
;
523 u
->sink
->get_latency
= sink_get_latency_cb
;
524 u
->sink
->get_hw_volume
= sink_get_hw_volume_cb
;
525 u
->sink
->set_hw_volume
= sink_set_hw_volume_cb
;
526 u
->sink
->userdata
= u
;
527 pa_sink_set_owner(u
->sink
, m
);
528 pa_sink_set_description(u
->sink
, "Windows waveOut PCM");
529 u
->sink
->is_hardware
= 1;
533 assert(u
->source
|| u
->sink
);
539 u
->fragments
= nfrags
;
540 u
->free_ifrags
= u
->fragments
;
541 u
->free_ofrags
= u
->fragments
;
542 u
->fragment_size
= frag_size
- (frag_size
% pa_frame_size(&ss
));
544 u
->written_bytes
= 0;
545 u
->sink_underflow
= 1;
547 u
->poll_timeout
= pa_bytes_to_usec(u
->fragments
* u
->fragment_size
/ 10, &ss
);
549 pa_gettimeofday(&tv
);
550 pa_timeval_add(&tv
, u
->poll_timeout
);
552 u
->event
= c
->mainloop
->rtclock_time_new(c
->mainloop
, &tv
, poll_cb
, u
);
555 u
->defer
= c
->mainloop
->defer_new(c
->mainloop
, defer_cb
, u
);
557 c
->mainloop
->defer_enable(u
->defer
, 0);
561 u
->ihdrs
= pa_xmalloc0(sizeof(WAVEHDR
) * u
->fragments
);
563 u
->ohdrs
= pa_xmalloc0(sizeof(WAVEHDR
) * u
->fragments
);
565 for (i
= 0;i
< u
->fragments
;i
++) {
566 u
->ihdrs
[i
].dwBufferLength
= u
->fragment_size
;
567 u
->ohdrs
[i
].dwBufferLength
= u
->fragment_size
;
568 u
->ihdrs
[i
].lpData
= pa_xmalloc(u
->fragment_size
);
570 u
->ohdrs
[i
].lpData
= pa_xmalloc(u
->fragment_size
);
579 /* Read mixer settings */
581 sink_get_hw_volume_cb(u
->sink
);
586 if (hwi
!= INVALID_HANDLE_VALUE
)
589 if (hwo
!= INVALID_HANDLE_VALUE
)
601 void pa__done(pa_core
*c
, pa_module
*m
) {
607 if (!(u
= m
->userdata
))
611 c
->mainloop
->time_free(u
->event
);
614 c
->mainloop
->defer_free(u
->defer
);
617 pa_sink_disconnect(u
->sink
);
618 pa_sink_unref(u
->sink
);
622 pa_source_disconnect(u
->source
);
623 pa_source_unref(u
->source
);
626 if (u
->hwi
!= INVALID_HANDLE_VALUE
) {
631 if (u
->hwo
!= INVALID_HANDLE_VALUE
) {
632 waveOutReset(u
->hwo
);
633 waveOutClose(u
->hwo
);
636 for (i
= 0;i
< u
->fragments
;i
++) {
637 pa_xfree(u
->ihdrs
[i
].lpData
);
638 pa_xfree(u
->ohdrs
[i
].lpData
);
644 DeleteCriticalSection(&u
->crit
);