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>
34 #include <pulse/rtclock.h>
36 #include <pulsecore/sink.h>
37 #include <pulsecore/source.h>
38 #include <pulsecore/module.h>
39 #include <pulsecore/modargs.h>
40 #include <pulsecore/sample-util.h>
41 #include <pulsecore/core-util.h>
42 #include <pulsecore/log.h>
43 #include <pulsecore/thread.h>
44 #include <pulsecore/thread-mq.h>
46 #include "module-waveout-symdef.h"
48 PA_MODULE_AUTHOR("Pierre Ossman");
49 PA_MODULE_DESCRIPTION("Windows waveOut Sink/Source");
50 PA_MODULE_VERSION(PACKAGE_VERSION
);
52 "sink_name=<name for the sink> "
53 "source_name=<name for the source> "
54 "device=<device number> "
55 "record=<enable source?> "
56 "playback=<enable sink?> "
57 "format=<sample format> "
59 "channels=<number of channels> "
60 "channel_map=<channel map> "
61 "fragments=<number of fragments> "
62 "fragment_size=<fragment size>");
64 #define DEFAULT_SINK_NAME "wave_output"
65 #define DEFAULT_SOURCE_NAME "wave_input"
67 #define WAVEOUT_MAX_VOLUME 0xFFFF
73 pa_usec_t poll_timeout
;
76 pa_thread_mq thread_mq
;
79 uint32_t fragments
, fragment_size
;
81 uint32_t free_ofrags
, free_ifrags
;
86 int cur_ohdr
, cur_ihdr
;
87 WAVEHDR
*ohdrs
, *ihdrs
;
93 CRITICAL_SECTION crit
;
96 static const char* const valid_modargs
[] = {
111 static void do_write(struct userdata
*u
) {
113 pa_memchunk memchunk
;
121 if (!PA_SINK_IS_LINKED(u
->sink
->state
))
124 EnterCriticalSection(&u
->crit
);
125 free_frags
= u
->free_ofrags
;
126 LeaveCriticalSection(&u
->crit
);
128 if (!u
->sink_underflow
&& (free_frags
== u
->fragments
))
129 pa_log_debug("WaveOut underflow!");
132 hdr
= &u
->ohdrs
[u
->cur_ohdr
];
133 if (hdr
->dwFlags
& WHDR_PREPARED
)
134 waveOutUnprepareHeader(u
->hwo
, hdr
, sizeof(WAVEHDR
));
136 hdr
->dwBufferLength
= 0;
137 while (hdr
->dwBufferLength
< u
->fragment_size
) {
140 len
= u
->fragment_size
- hdr
->dwBufferLength
;
142 pa_sink_render(u
->sink
, len
, &memchunk
);
144 pa_assert(memchunk
.memblock
);
145 pa_assert(memchunk
.length
);
147 if (memchunk
.length
< len
)
148 len
= memchunk
.length
;
150 p
= pa_memblock_acquire(memchunk
.memblock
);
151 memcpy(hdr
->lpData
+ hdr
->dwBufferLength
, (char*) p
+ memchunk
.index
, len
);
152 pa_memblock_release(memchunk
.memblock
);
154 hdr
->dwBufferLength
+= len
;
156 pa_memblock_unref(memchunk
.memblock
);
157 memchunk
.memblock
= NULL
;
160 /* Insufficient data in sink buffer? */
161 if (hdr
->dwBufferLength
== 0) {
162 u
->sink_underflow
= 1;
166 u
->sink_underflow
= 0;
168 res
= waveOutPrepareHeader(u
->hwo
, hdr
, sizeof(WAVEHDR
));
169 if (res
!= MMSYSERR_NOERROR
)
170 pa_log_error("Unable to prepare waveOut block: %d", res
);
172 res
= waveOutWrite(u
->hwo
, hdr
, sizeof(WAVEHDR
));
173 if (res
!= MMSYSERR_NOERROR
)
174 pa_log_error("Unable to write waveOut block: %d", res
);
176 u
->written_bytes
+= hdr
->dwBufferLength
;
178 EnterCriticalSection(&u
->crit
);
180 LeaveCriticalSection(&u
->crit
);
184 u
->cur_ohdr
%= u
->fragments
;
188 static void do_read(struct userdata
*u
) {
190 pa_memchunk memchunk
;
198 if (!PA_SOURCE_IS_LINKED(u
->source
->state
))
201 EnterCriticalSection(&u
->crit
);
202 free_frags
= u
->free_ifrags
;
204 LeaveCriticalSection(&u
->crit
);
206 if (free_frags
== u
->fragments
)
207 pa_log_debug("WaveIn overflow!");
210 hdr
= &u
->ihdrs
[u
->cur_ihdr
];
211 if (hdr
->dwFlags
& WHDR_PREPARED
)
212 waveInUnprepareHeader(u
->hwi
, hdr
, sizeof(WAVEHDR
));
214 if (hdr
->dwBytesRecorded
) {
215 memchunk
.memblock
= pa_memblock_new(u
->core
->mempool
, hdr
->dwBytesRecorded
);
216 pa_assert(memchunk
.memblock
);
218 p
= pa_memblock_acquire(memchunk
.memblock
);
219 memcpy((char*) p
, hdr
->lpData
, hdr
->dwBytesRecorded
);
220 pa_memblock_release(memchunk
.memblock
);
222 memchunk
.length
= hdr
->dwBytesRecorded
;
225 pa_source_post(u
->source
, &memchunk
);
226 pa_memblock_unref(memchunk
.memblock
);
229 res
= waveInPrepareHeader(u
->hwi
, hdr
, sizeof(WAVEHDR
));
230 if (res
!= MMSYSERR_NOERROR
)
231 pa_log_error("Unable to prepare waveIn block: %d", res
);
233 res
= waveInAddBuffer(u
->hwi
, hdr
, sizeof(WAVEHDR
));
234 if (res
!= MMSYSERR_NOERROR
)
235 pa_log_error("Unable to add waveIn block: %d", res
);
239 u
->cur_ihdr
%= u
->fragments
;
243 static void thread_func(void *userdata
) {
244 struct userdata
*u
= userdata
;
247 pa_assert(u
->sink
|| u
->source
);
249 pa_log_debug("Thread starting up");
251 if (u
->core
->realtime_scheduling
)
252 pa_make_realtime(u
->core
->realtime_priority
);
254 pa_thread_mq_install(&u
->thread_mq
);
259 if (PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
) ||
260 PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
)) {
262 if (u
->sink
->thread_info
.rewind_requested
)
263 pa_sink_process_rewind(u
->sink
, 0);
265 if (PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
))
267 if (PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
))
270 pa_rtpoll_set_timer_relative(u
->rtpoll
, u
->poll_timeout
);
272 pa_rtpoll_set_timer_disabled(u
->rtpoll
);
274 /* Hmm, nothing to do. Let's sleep */
275 if ((ret
= pa_rtpoll_run(u
->rtpoll
, TRUE
)) < 0)
283 /* If this was no regular exit from the loop we have to continue
284 * processing messages until we received PA_MESSAGE_SHUTDOWN */
285 pa_asyncmsgq_post(u
->thread_mq
.outq
, PA_MSGOBJECT(u
->core
), PA_CORE_MESSAGE_UNLOAD_MODULE
, u
->module
, 0, NULL
, NULL
);
286 pa_asyncmsgq_wait_for(u
->thread_mq
.inq
, PA_MESSAGE_SHUTDOWN
);
289 pa_log_debug("Thread shutting down");
292 static void CALLBACK
chunk_done_cb(HWAVEOUT hwo
, UINT msg
, DWORD_PTR inst
, DWORD param1
, DWORD param2
) {
293 struct userdata
*u
= (struct userdata
*)inst
;
298 EnterCriticalSection(&u
->crit
);
300 pa_assert(u
->free_ofrags
<= u
->fragments
);
301 LeaveCriticalSection(&u
->crit
);
304 static void CALLBACK
chunk_ready_cb(HWAVEIN hwi
, UINT msg
, DWORD_PTR inst
, DWORD param1
, DWORD param2
) {
305 struct userdata
*u
= (struct userdata
*)inst
;
310 EnterCriticalSection(&u
->crit
);
312 pa_assert(u
->free_ifrags
<= u
->fragments
);
313 LeaveCriticalSection(&u
->crit
);
316 static pa_usec_t
sink_get_latency(struct userdata
*u
) {
322 memset(&mmt
, 0, sizeof(mmt
));
323 mmt
.wType
= TIME_BYTES
;
324 if (waveOutGetPosition(u
->hwo
, &mmt
, sizeof(mmt
)) == MMSYSERR_NOERROR
)
325 return pa_bytes_to_usec(u
->written_bytes
- mmt
.u
.cb
, &u
->sink
->sample_spec
);
327 EnterCriticalSection(&u
->crit
);
328 free_frags
= u
->free_ofrags
;
329 LeaveCriticalSection(&u
->crit
);
331 return pa_bytes_to_usec((u
->fragments
- free_frags
) * u
->fragment_size
, &u
->sink
->sample_spec
);
335 static pa_usec_t
source_get_latency(struct userdata
*u
) {
339 pa_assert(u
->source
);
341 EnterCriticalSection(&u
->crit
);
342 free_frags
= u
->free_ifrags
;
343 LeaveCriticalSection(&u
->crit
);
345 r
+= pa_bytes_to_usec((free_frags
+ 1) * u
->fragment_size
, &u
->source
->sample_spec
);
350 static int process_msg(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
353 if (pa_sink_isinstance(o
)) {
354 u
= PA_SINK(o
)->userdata
;
358 case PA_SINK_MESSAGE_GET_LATENCY
: {
361 r
= sink_get_latency(u
);
362 *((pa_usec_t
*) data
) = r
;
368 return pa_sink_process_msg(o
, code
, data
, offset
, chunk
);
371 if (pa_source_isinstance(o
)) {
372 u
= PA_SOURCE(o
)->userdata
;
376 case PA_SOURCE_MESSAGE_GET_LATENCY
: {
379 r
= source_get_latency(u
);
380 *((pa_usec_t
*) data
) = r
;
386 return pa_source_process_msg(o
, code
, data
, offset
, chunk
);
392 static void sink_get_volume_cb(pa_sink
*s
) {
393 struct userdata
*u
= s
->userdata
;
395 pa_volume_t left
, right
;
397 if (waveOutGetVolume(u
->hwo
, &vol
) != MMSYSERR_NOERROR
)
400 left
= PA_CLAMP_VOLUME((vol
& 0xFFFF) * PA_VOLUME_NORM
/ WAVEOUT_MAX_VOLUME
);
401 right
= PA_CLAMP_VOLUME(((vol
>> 16) & 0xFFFF) * PA_VOLUME_NORM
/ WAVEOUT_MAX_VOLUME
);
403 /* Windows supports > 2 channels, except for volume control */
404 if (s
->real_volume
.channels
> 2)
405 pa_cvolume_set(&s
->real_volume
, s
->real_volume
.channels
, (left
+ right
)/2);
407 s
->real_volume
.values
[0] = left
;
408 if (s
->real_volume
.channels
> 1)
409 s
->real_volume
.values
[1] = right
;
412 static void sink_set_volume_cb(pa_sink
*s
) {
413 struct userdata
*u
= s
->userdata
;
416 vol
= s
->real_volume
.values
[0] * WAVEOUT_MAX_VOLUME
/ PA_VOLUME_NORM
;
417 if (s
->real_volume
.channels
> 1)
418 vol
|= (s
->real_volume
.values
[1] * WAVEOUT_MAX_VOLUME
/ PA_VOLUME_NORM
) << 16;
420 if (waveOutSetVolume(u
->hwo
, vol
) != MMSYSERR_NOERROR
)
424 static int ss_to_waveformat(pa_sample_spec
*ss
, LPWAVEFORMATEX wf
) {
425 wf
->wFormatTag
= WAVE_FORMAT_PCM
;
427 if (ss
->channels
> 2) {
428 pa_log_error("More than two channels not supported.");
432 wf
->nChannels
= ss
->channels
;
441 pa_log_error("Unsupported sample rate.");
445 wf
->nSamplesPerSec
= ss
->rate
;
447 if (ss
->format
== PA_SAMPLE_U8
)
448 wf
->wBitsPerSample
= 8;
449 else if (ss
->format
== PA_SAMPLE_S16NE
)
450 wf
->wBitsPerSample
= 16;
452 pa_log_error("Unsupported sample format.");
456 wf
->nBlockAlign
= wf
->nChannels
* wf
->wBitsPerSample
/8;
457 wf
->nAvgBytesPerSec
= wf
->nSamplesPerSec
* wf
->nBlockAlign
;
464 int pa__get_n_used(pa_module
*m
) {
467 pa_assert(m
->userdata
);
468 u
= (struct userdata
*)m
->userdata
;
470 return (u
->sink
? pa_sink_used_by(u
->sink
) : 0) +
471 (u
->source
? pa_source_used_by(u
->source
) : 0);
474 int pa__init(pa_module
*m
) {
475 struct userdata
*u
= NULL
;
476 HWAVEOUT hwo
= INVALID_HANDLE_VALUE
;
477 HWAVEIN hwi
= INVALID_HANDLE_VALUE
;
479 int nfrags
, frag_size
;
480 pa_bool_t record
= TRUE
, playback
= TRUE
;
484 pa_modargs
*ma
= NULL
;
490 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
491 pa_log("failed to parse module arguments.");
495 if (pa_modargs_get_value_boolean(ma
, "record", &record
) < 0 || pa_modargs_get_value_boolean(ma
, "playback", &playback
) < 0) {
496 pa_log("record= and playback= expect boolean argument.");
500 if (!playback
&& !record
) {
501 pa_log("neither playback nor record enabled for device.");
505 device
= WAVE_MAPPER
;
506 if (pa_modargs_get_value_u32(ma
, "device", &device
) < 0) {
507 pa_log("failed to parse device argument");
513 if (pa_modargs_get_value_s32(ma
, "fragments", &nfrags
) < 0 || pa_modargs_get_value_s32(ma
, "fragment_size", &frag_size
) < 0) {
514 pa_log("failed to parse fragments arguments");
518 ss
= m
->core
->default_sample_spec
;
519 if (pa_modargs_get_sample_spec_and_channel_map(ma
, &ss
, &map
, PA_CHANNEL_MAP_WAVEEX
) < 0) {
520 pa_log("failed to parse sample specification");
524 if (ss_to_waveformat(&ss
, &wf
) < 0)
527 u
= pa_xmalloc(sizeof(struct userdata
));
530 if (waveInOpen(&hwi
, device
, &wf
, (DWORD_PTR
)chunk_ready_cb
, (DWORD_PTR
)u
, CALLBACK_FUNCTION
) != MMSYSERR_NOERROR
) {
531 pa_log("failed to open waveIn");
534 if (waveInStart(hwi
) != MMSYSERR_NOERROR
) {
535 pa_log("failed to start waveIn");
538 pa_log_debug("Opened waveIn subsystem.");
542 if (waveOutOpen(&hwo
, device
, &wf
, (DWORD_PTR
)chunk_done_cb
, (DWORD_PTR
)u
, CALLBACK_FUNCTION
) != MMSYSERR_NOERROR
) {
543 pa_log("failed to open waveOut");
546 pa_log_debug("Opened waveOut subsystem.");
549 InitializeCriticalSection(&u
->crit
);
551 if (hwi
!= INVALID_HANDLE_VALUE
) {
552 pa_source_new_data data
;
553 pa_source_new_data_init(&data
);
554 data
.driver
= __FILE__
;
556 pa_source_new_data_set_sample_spec(&data
, &ss
);
557 pa_source_new_data_set_channel_map(&data
, &map
);
558 pa_source_new_data_set_name(&data
, pa_modargs_get_value(ma
, "source_name", DEFAULT_SOURCE_NAME
));
559 u
->source
= pa_source_new(m
->core
, &data
, PA_SOURCE_HARDWARE
|PA_SOURCE_LATENCY
);
560 pa_source_new_data_done(&data
);
562 pa_assert(u
->source
);
563 u
->source
->userdata
= u
;
564 pa_source_set_description(u
->source
, "Windows waveIn PCM");
565 u
->source
->parent
.process_msg
= process_msg
;
569 if (hwo
!= INVALID_HANDLE_VALUE
) {
570 pa_sink_new_data data
;
571 pa_sink_new_data_init(&data
);
572 data
.driver
= __FILE__
;
574 pa_sink_new_data_set_sample_spec(&data
, &ss
);
575 pa_sink_new_data_set_channel_map(&data
, &map
);
576 pa_sink_new_data_set_name(&data
, pa_modargs_get_value(ma
, "sink_name", DEFAULT_SINK_NAME
));
577 u
->sink
= pa_sink_new(m
->core
, &data
, PA_SINK_HARDWARE
|PA_SINK_LATENCY
);
578 pa_sink_new_data_done(&data
);
581 u
->sink
->get_volume
= sink_get_volume_cb
;
582 u
->sink
->set_volume
= sink_set_volume_cb
;
583 u
->sink
->userdata
= u
;
584 pa_sink_set_description(u
->sink
, "Windows waveOut PCM");
585 u
->sink
->parent
.process_msg
= process_msg
;
589 pa_assert(u
->source
|| u
->sink
);
596 u
->fragments
= nfrags
;
597 u
->free_ifrags
= u
->fragments
;
598 u
->free_ofrags
= u
->fragments
;
599 u
->fragment_size
= frag_size
- (frag_size
% pa_frame_size(&ss
));
601 u
->written_bytes
= 0;
602 u
->sink_underflow
= 1;
604 u
->poll_timeout
= pa_bytes_to_usec(u
->fragments
* u
->fragment_size
/ 10, &ss
);
608 u
->ihdrs
= pa_xmalloc0(sizeof(WAVEHDR
) * u
->fragments
);
610 u
->ohdrs
= pa_xmalloc0(sizeof(WAVEHDR
) * u
->fragments
);
612 for (i
= 0;i
< u
->fragments
;i
++) {
613 u
->ihdrs
[i
].dwBufferLength
= u
->fragment_size
;
614 u
->ohdrs
[i
].dwBufferLength
= u
->fragment_size
;
615 u
->ihdrs
[i
].lpData
= pa_xmalloc(u
->fragment_size
);
617 u
->ohdrs
[i
].lpData
= pa_xmalloc(u
->fragment_size
);
624 /* Read mixer settings */
626 sink_get_volume_cb(u
->sink
);
628 u
->rtpoll
= pa_rtpoll_new();
629 pa_thread_mq_init(&u
->thread_mq
, m
->core
->mainloop
, u
->rtpoll
);
630 if (!(u
->thread
= pa_thread_new("waveout-source", thread_func
, u
))) {
631 pa_log("Failed to create thread.");
636 pa_sink_set_asyncmsgq(u
->sink
, u
->thread_mq
.inq
);
637 pa_sink_set_rtpoll(u
->sink
, u
->rtpoll
);
638 pa_sink_put(u
->sink
);
641 pa_source_set_asyncmsgq(u
->source
, u
->thread_mq
.inq
);
642 pa_source_set_rtpoll(u
->source
, u
->rtpoll
);
643 pa_source_put(u
->source
);
657 void pa__done(pa_module
*m
) {
664 if (!(u
= m
->userdata
))
668 pa_sink_unlink(u
->sink
);
670 pa_source_unlink(u
->source
);
672 pa_asyncmsgq_send(u
->thread_mq
.inq
, NULL
, PA_MESSAGE_SHUTDOWN
, NULL
, 0, NULL
);
674 pa_thread_free(u
->thread
);
675 pa_thread_mq_done(&u
->thread_mq
);
678 pa_sink_unref(u
->sink
);
680 pa_source_unref(u
->source
);
683 pa_rtpoll_free(u
->rtpoll
);
685 if (u
->hwi
!= INVALID_HANDLE_VALUE
) {
690 if (u
->hwo
!= INVALID_HANDLE_VALUE
) {
691 waveOutReset(u
->hwo
);
692 waveOutClose(u
->hwo
);
695 for (i
= 0;i
< u
->fragments
;i
++) {
696 pa_xfree(u
->ihdrs
[i
].lpData
);
697 pa_xfree(u
->ohdrs
[i
].lpData
);
703 DeleteCriticalSection(&u
->crit
);