]>
code.delx.au - pulseaudio/blob - src/modules/module-waveout.c
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 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
->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
->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
);