]>
code.delx.au - pulseaudio/blob - src/modules/module-waveout.c
ce9ea84d800bb64699b27b1a952cc499951c7595
4 This file is part of polypaudio.
6 polypaudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
11 polypaudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with polypaudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
30 #include <polyp/mainloop-api.h>
32 #include <polyp/xmalloc.h>
34 #include <polypcore/sink.h>
35 #include <polypcore/source.h>
36 #include <polypcore/module.h>
37 #include <polypcore/modargs.h>
38 #include <polypcore/sample-util.h>
39 #include <polypcore/core-util.h>
40 #include <polypcore/log.h>
42 #include "module-waveout-symdef.h"
44 PA_MODULE_AUTHOR("Pierre Ossman")
45 PA_MODULE_DESCRIPTION("Windows waveOut Sink/Source")
46 PA_MODULE_VERSION(PACKAGE_VERSION
)
48 "sink_name=<name for the sink> "
49 "source_name=<name for the source>"
50 "record=<enable source?> "
51 "playback=<enable sink?> "
52 "format=<sample format> "
53 "channels=<number of channels> "
55 "fragments=<number of fragments> "
56 "fragment_size=<fragment size> "
57 "channel_map=<channel map>")
59 #define DEFAULT_SINK_NAME "wave_output"
60 #define DEFAULT_SOURCE_NAME "wave_input"
62 #define WAVEOUT_MAX_VOLUME 0xFFFF
69 pa_defer_event
*defer
;
70 pa_usec_t poll_timeout
;
72 uint32_t fragments
, fragment_size
;
74 uint32_t free_ofrags
, free_ifrags
;
78 int cur_ohdr
, cur_ihdr
;
80 WAVEHDR
*ohdrs
, *ihdrs
;
87 CRITICAL_SECTION crit
;
90 static const char* const valid_modargs
[] = {
104 static void update_usage(struct userdata
*u
) {
105 pa_module_set_used(u
->module
,
106 (u
->sink
? pa_idxset_size(u
->sink
->inputs
) : 0) +
107 (u
->sink
? pa_idxset_size(u
->sink
->monitor_source
->outputs
) : 0) +
108 (u
->source
? pa_idxset_size(u
->source
->outputs
) : 0));
111 static void do_write(struct userdata
*u
)
113 uint32_t free_frags
, remain
;
114 pa_memchunk memchunk
, *cur_chunk
;
121 EnterCriticalSection(&u
->crit
);
123 free_frags
= u
->free_ofrags
;
126 LeaveCriticalSection(&u
->crit
);
128 if (free_frags
== u
->fragments
)
129 pa_log_debug(__FILE__
": WaveOut underflow!");
132 hdr
= &u
->ohdrs
[u
->cur_ohdr
];
133 if (hdr
->dwFlags
& WHDR_PREPARED
)
134 waveOutUnprepareHeader(u
->hwo
, hdr
, sizeof(WAVEHDR
));
138 cur_chunk
= &memchunk
;
140 if (pa_sink_render(u
->sink
, remain
, cur_chunk
) < 0) {
142 * Don't fill with silence unless we're getting close to
145 if (free_frags
> u
->fragments
/2)
146 cur_chunk
= &u
->silence
;
148 EnterCriticalSection(&u
->crit
);
150 u
->free_ofrags
+= free_frags
;
152 LeaveCriticalSection(&u
->crit
);
159 assert(cur_chunk
->memblock
);
160 assert(cur_chunk
->memblock
->data
);
161 assert(cur_chunk
->length
);
163 memcpy(hdr
->lpData
+ u
->fragment_size
- remain
,
164 (char*)cur_chunk
->memblock
->data
+ cur_chunk
->index
,
165 (cur_chunk
->length
< remain
)?cur_chunk
->length
:remain
);
167 remain
-= (cur_chunk
->length
< remain
)?cur_chunk
->length
:remain
;
169 if (cur_chunk
!= &u
->silence
) {
170 pa_memblock_unref(cur_chunk
->memblock
);
171 cur_chunk
->memblock
= NULL
;
175 res
= waveOutPrepareHeader(u
->hwo
, hdr
, sizeof(WAVEHDR
));
176 if (res
!= MMSYSERR_NOERROR
) {
177 pa_log_error(__FILE__
": ERROR: Unable to prepare waveOut block: %d",
180 res
= waveOutWrite(u
->hwo
, hdr
, sizeof(WAVEHDR
));
181 if (res
!= MMSYSERR_NOERROR
) {
182 pa_log_error(__FILE__
": ERROR: Unable to write waveOut block: %d",
186 u
->written_bytes
+= u
->fragment_size
;
190 u
->cur_ohdr
%= u
->fragments
;
191 u
->oremain
= u
->fragment_size
;
195 static void do_read(struct userdata
*u
)
198 pa_memchunk memchunk
;
205 EnterCriticalSection(&u
->crit
);
207 free_frags
= u
->free_ifrags
;
210 LeaveCriticalSection(&u
->crit
);
212 if (free_frags
== u
->fragments
)
213 pa_log_debug(__FILE__
": WaveIn overflow!");
216 hdr
= &u
->ihdrs
[u
->cur_ihdr
];
217 if (hdr
->dwFlags
& WHDR_PREPARED
)
218 waveInUnprepareHeader(u
->hwi
, hdr
, sizeof(WAVEHDR
));
220 if (hdr
->dwBytesRecorded
) {
221 memchunk
.memblock
= pa_memblock_new(hdr
->dwBytesRecorded
, u
->core
->memblock_stat
);
222 assert(memchunk
.memblock
);
224 memcpy((char*)memchunk
.memblock
->data
, hdr
->lpData
, hdr
->dwBytesRecorded
);
226 memchunk
.length
= memchunk
.memblock
->length
= hdr
->dwBytesRecorded
;
229 pa_source_post(u
->source
, &memchunk
);
230 pa_memblock_unref(memchunk
.memblock
);
233 res
= waveInPrepareHeader(u
->hwi
, hdr
, sizeof(WAVEHDR
));
234 if (res
!= MMSYSERR_NOERROR
) {
235 pa_log_error(__FILE__
": ERROR: Unable to prepare waveIn block: %d",
238 res
= waveInAddBuffer(u
->hwi
, hdr
, sizeof(WAVEHDR
));
239 if (res
!= MMSYSERR_NOERROR
) {
240 pa_log_error(__FILE__
": ERROR: Unable to add waveIn block: %d",
246 u
->cur_ihdr
%= u
->fragments
;
250 static void poll_cb(pa_mainloop_api
*a
, pa_time_event
*e
, const struct timeval
*tv
, void *userdata
) {
251 struct userdata
*u
= userdata
;
261 pa_gettimeofday(&ntv
);
262 pa_timeval_add(&ntv
, u
->poll_timeout
);
264 a
->time_restart(e
, &ntv
);
267 static void defer_cb(pa_mainloop_api
*a
, pa_defer_event
*e
, void *userdata
) {
268 struct userdata
*u
= userdata
;
272 a
->defer_enable(e
, 0);
278 static void CALLBACK
chunk_done_cb(HWAVEOUT hwo
, UINT msg
, DWORD_PTR inst
, DWORD param1
, DWORD param2
) {
279 struct userdata
*u
= (struct userdata
*)inst
;
284 EnterCriticalSection(&u
->crit
);
287 assert(u
->free_ofrags
<= u
->fragments
);
289 LeaveCriticalSection(&u
->crit
);
292 static void CALLBACK
chunk_ready_cb(HWAVEIN hwi
, UINT msg
, DWORD_PTR inst
, DWORD param1
, DWORD param2
) {
293 struct userdata
*u
= (struct userdata
*)inst
;
298 EnterCriticalSection(&u
->crit
);
301 assert(u
->free_ifrags
<= u
->fragments
);
303 LeaveCriticalSection(&u
->crit
);
306 static pa_usec_t
sink_get_latency_cb(pa_sink
*s
) {
307 struct userdata
*u
= s
->userdata
;
310 assert(s
&& u
&& u
->sink
);
312 memset(&mmt
, 0, sizeof(mmt
));
313 mmt
.wType
= TIME_BYTES
;
314 if (waveOutGetPosition(u
->hwo
, &mmt
, sizeof(mmt
)) == MMSYSERR_NOERROR
)
315 return pa_bytes_to_usec(u
->written_bytes
- mmt
.u
.cb
, &s
->sample_spec
);
317 EnterCriticalSection(&u
->crit
);
319 free_frags
= u
->free_ofrags
;
321 LeaveCriticalSection(&u
->crit
);
323 return pa_bytes_to_usec((u
->fragments
- free_frags
) * u
->fragment_size
,
328 static pa_usec_t
source_get_latency_cb(pa_source
*s
) {
330 struct userdata
*u
= s
->userdata
;
332 assert(s
&& u
&& u
->sink
);
334 EnterCriticalSection(&u
->crit
);
336 free_frags
= u
->free_ifrags
;
338 LeaveCriticalSection(&u
->crit
);
340 r
+= pa_bytes_to_usec((free_frags
+ 1) * u
->fragment_size
, &s
->sample_spec
);
345 static void notify_sink_cb(pa_sink
*s
) {
346 struct userdata
*u
= s
->userdata
;
349 u
->core
->mainloop
->defer_enable(u
->defer
, 1);
352 static void notify_source_cb(pa_source
*s
) {
353 struct userdata
*u
= s
->userdata
;
356 u
->core
->mainloop
->defer_enable(u
->defer
, 1);
359 static int sink_get_hw_volume_cb(pa_sink
*s
) {
360 struct userdata
*u
= s
->userdata
;
362 pa_volume_t left
, right
;
364 if (waveOutGetVolume(u
->hwo
, &vol
) != MMSYSERR_NOERROR
)
367 left
= (vol
& 0xFFFF) * PA_VOLUME_NORM
/ WAVEOUT_MAX_VOLUME
;
368 right
= ((vol
>> 16) & 0xFFFF) * PA_VOLUME_NORM
/ WAVEOUT_MAX_VOLUME
;
370 /* Windows supports > 2 channels, except for volume control */
371 if (s
->hw_volume
.channels
> 2)
372 pa_cvolume_set(&s
->hw_volume
, s
->hw_volume
.channels
, (left
+ right
)/2);
374 s
->hw_volume
.values
[0] = left
;
375 if (s
->hw_volume
.channels
> 1)
376 s
->hw_volume
.values
[1] = right
;
381 static int sink_set_hw_volume_cb(pa_sink
*s
) {
382 struct userdata
*u
= s
->userdata
;
385 vol
= s
->hw_volume
.values
[0] * WAVEOUT_MAX_VOLUME
/ PA_VOLUME_NORM
;
386 if (s
->hw_volume
.channels
> 1)
387 vol
|= (s
->hw_volume
.values
[0] * WAVEOUT_MAX_VOLUME
/ PA_VOLUME_NORM
) << 16;
389 if (waveOutSetVolume(u
->hwo
, vol
) != MMSYSERR_NOERROR
)
395 static int ss_to_waveformat(pa_sample_spec
*ss
, LPWAVEFORMATEX wf
) {
396 wf
->wFormatTag
= WAVE_FORMAT_PCM
;
398 if (ss
->channels
> 2) {
399 pa_log_error(__FILE__
": ERROR: More than two channels not supported.");
403 wf
->nChannels
= ss
->channels
;
412 pa_log_error(__FILE__
": ERROR: Unsupported sample rate.");
416 wf
->nSamplesPerSec
= ss
->rate
;
418 if (ss
->format
== PA_SAMPLE_U8
)
419 wf
->wBitsPerSample
= 8;
420 else if (ss
->format
== PA_SAMPLE_S16NE
)
421 wf
->wBitsPerSample
= 16;
423 pa_log_error(__FILE__
": ERROR: Unsupported sample format.");
427 wf
->nBlockAlign
= wf
->nChannels
* wf
->wBitsPerSample
/8;
428 wf
->nAvgBytesPerSec
= wf
->nSamplesPerSec
* wf
->nBlockAlign
;
435 int pa__init(pa_core
*c
, pa_module
*m
) {
436 struct userdata
*u
= NULL
;
437 HWAVEOUT hwo
= INVALID_HANDLE_VALUE
;
438 HWAVEIN hwi
= INVALID_HANDLE_VALUE
;
440 int nfrags
, frag_size
;
441 int record
= 1, playback
= 1;
444 pa_modargs
*ma
= NULL
;
450 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
451 pa_log(__FILE__
": failed to parse module arguments.");
455 if (pa_modargs_get_value_boolean(ma
, "record", &record
) < 0 || pa_modargs_get_value_boolean(ma
, "playback", &playback
) < 0) {
456 pa_log(__FILE__
": record= and playback= expect boolean argument.");
460 if (!playback
&& !record
) {
461 pa_log(__FILE__
": neither playback nor record enabled for device.");
467 if (pa_modargs_get_value_s32(ma
, "fragments", &nfrags
) < 0 || pa_modargs_get_value_s32(ma
, "fragment_size", &frag_size
) < 0) {
468 pa_log(__FILE__
": failed to parse fragments arguments");
472 ss
= c
->default_sample_spec
;
473 if (pa_modargs_get_sample_spec_and_channel_map(ma
, &ss
, &map
, PA_CHANNEL_MAP_WAVEEX
) < 0) {
474 pa_log(__FILE__
": failed to parse sample specification");
478 if (ss_to_waveformat(&ss
, &wf
) < 0)
481 u
= pa_xmalloc(sizeof(struct userdata
));
484 if (waveInOpen(&hwi
, WAVE_MAPPER
, &wf
, (DWORD_PTR
)chunk_ready_cb
, (DWORD_PTR
)u
, CALLBACK_FUNCTION
) != MMSYSERR_NOERROR
)
486 if (waveInStart(hwi
) != MMSYSERR_NOERROR
)
488 pa_log_debug(__FILE__
": Opened waveIn subsystem.");
492 if (waveOutOpen(&hwo
, WAVE_MAPPER
, &wf
, (DWORD_PTR
)chunk_done_cb
, (DWORD_PTR
)u
, CALLBACK_FUNCTION
) != MMSYSERR_NOERROR
)
494 pa_log_debug(__FILE__
": Opened waveOut subsystem.");
497 InitializeCriticalSection(&u
->crit
);
499 if (hwi
!= INVALID_HANDLE_VALUE
) {
500 u
->source
= pa_source_new(c
, __FILE__
, pa_modargs_get_value(ma
, "source_name", DEFAULT_SOURCE_NAME
), 0, &ss
, &map
);
502 u
->source
->userdata
= u
;
503 u
->source
->notify
= notify_source_cb
;
504 u
->source
->get_latency
= source_get_latency_cb
;
505 pa_source_set_owner(u
->source
, m
);
506 u
->source
->description
= pa_sprintf_malloc("Windows waveIn PCM");
510 if (hwo
!= INVALID_HANDLE_VALUE
) {
511 u
->sink
= pa_sink_new(c
, __FILE__
, pa_modargs_get_value(ma
, "sink_name", DEFAULT_SINK_NAME
), 0, &ss
, &map
);
513 u
->sink
->notify
= notify_sink_cb
;
514 u
->sink
->get_latency
= sink_get_latency_cb
;
515 u
->sink
->get_hw_volume
= sink_get_hw_volume_cb
;
516 u
->sink
->set_hw_volume
= sink_set_hw_volume_cb
;
517 u
->sink
->userdata
= u
;
518 pa_sink_set_owner(u
->sink
, m
);
519 u
->sink
->description
= pa_sprintf_malloc("Windows waveOut PCM");
523 assert(u
->source
|| u
->sink
);
529 u
->fragments
= nfrags
;
530 u
->free_ifrags
= u
->fragments
;
531 u
->free_ofrags
= u
->fragments
;
532 u
->fragment_size
= frag_size
- (frag_size
% pa_frame_size(&ss
));
534 u
->written_bytes
= 0;
536 u
->oremain
= u
->fragment_size
;
538 u
->poll_timeout
= pa_bytes_to_usec(u
->fragments
* u
->fragment_size
/ 10, &ss
);
540 pa_gettimeofday(&tv
);
541 pa_timeval_add(&tv
, u
->poll_timeout
);
543 u
->event
= c
->mainloop
->time_new(c
->mainloop
, &tv
, poll_cb
, u
);
546 u
->defer
= c
->mainloop
->defer_new(c
->mainloop
, defer_cb
, u
);
548 c
->mainloop
->defer_enable(u
->defer
, 0);
552 u
->ihdrs
= pa_xmalloc0(sizeof(WAVEHDR
) * u
->fragments
);
554 u
->ohdrs
= pa_xmalloc0(sizeof(WAVEHDR
) * u
->fragments
);
556 for (i
= 0;i
< u
->fragments
;i
++) {
557 u
->ihdrs
[i
].dwBufferLength
= u
->fragment_size
;
558 u
->ohdrs
[i
].dwBufferLength
= u
->fragment_size
;
559 u
->ihdrs
[i
].lpData
= pa_xmalloc(u
->fragment_size
);
561 u
->ohdrs
[i
].lpData
= pa_xmalloc(u
->fragment_size
);
565 u
->silence
.length
= u
->fragment_size
;
566 u
->silence
.memblock
= pa_memblock_new(u
->silence
.length
, u
->core
->memblock_stat
);
567 assert(u
->silence
.memblock
);
568 pa_silence_memblock(u
->silence
.memblock
, &ss
);
569 u
->silence
.index
= 0;
576 /* Read mixer settings */
578 sink_get_hw_volume_cb(u
->sink
);
583 if (hwi
!= INVALID_HANDLE_VALUE
)
586 if (hwo
!= INVALID_HANDLE_VALUE
)
598 void pa__done(pa_core
*c
, pa_module
*m
) {
604 if (!(u
= m
->userdata
))
608 c
->mainloop
->time_free(u
->event
);
611 c
->mainloop
->defer_free(u
->defer
);
614 pa_sink_disconnect(u
->sink
);
615 pa_sink_unref(u
->sink
);
619 pa_source_disconnect(u
->source
);
620 pa_source_unref(u
->source
);
623 if (u
->hwi
!= INVALID_HANDLE_VALUE
) {
628 if (u
->hwo
!= INVALID_HANDLE_VALUE
) {
629 waveOutReset(u
->hwo
);
630 waveOutClose(u
->hwo
);
633 for (i
= 0;i
< u
->fragments
;i
++) {
634 pa_xfree(u
->ihdrs
[i
].lpData
);
635 pa_xfree(u
->ohdrs
[i
].lpData
);
641 DeleteCriticalSection(&u
->crit
);