]>
code.delx.au - pulseaudio/blob - src/modules/module-waveout.c
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 <polypcore/sink.h>
33 #include <polypcore/source.h>
34 #include <polypcore/module.h>
35 #include <polypcore/modargs.h>
36 #include <polypcore/sample-util.h>
37 #include <polypcore/util.h>
38 #include <polypcore/log.h>
39 #include <polypcore/xmalloc.h>
41 #include "module-waveout-symdef.h"
43 PA_MODULE_AUTHOR ( "Pierre Ossman" )
44 PA_MODULE_DESCRIPTION ( "Windows waveOut Sink/Source" )
45 PA_MODULE_VERSION ( PACKAGE_VERSION
)
46 PA_MODULE_USAGE ( "sink_name=<name for the sink> source_name=<name for the source> record=<enable source?> playback=<enable sink?> format=<sample format> channels=<number of channels> rate=<sample rate> fragments=<number of fragments> fragment_size=<fragment size>" )
48 #define DEFAULT_SINK_NAME "wave_output"
49 #define DEFAULT_SOURCE_NAME "wave_input"
51 #define WAVEOUT_MAX_VOLUME 0xFFFF
58 pa_defer_event
* defer
;
59 pa_usec_t poll_timeout
;
61 uint32_t fragments
, fragment_size
;
63 uint32_t free_ofrags
, free_ifrags
;
67 int cur_ohdr
, cur_ihdr
;
69 WAVEHDR
* ohdrs
, * ihdrs
;
76 CRITICAL_SECTION crit
;
79 static const char * const valid_modargs
[] = {
92 static void update_usage ( struct userdata
* u
) {
93 pa_module_set_used ( u
-> module
,
94 ( u
-> sink
? pa_idxset_size ( u
-> sink
-> inputs
) : 0 ) +
95 ( u
-> sink
? pa_idxset_size ( u
-> sink
-> monitor_source
-> outputs
) : 0 ) +
96 ( u
-> source
? pa_idxset_size ( u
-> source
-> outputs
) : 0 ));
99 static void do_write ( struct userdata
* u
)
101 uint32_t free_frags
, remain
;
102 pa_memchunk memchunk
, * cur_chunk
;
109 EnterCriticalSection (& u
-> crit
);
111 free_frags
= u
-> free_ofrags
;
114 LeaveCriticalSection (& u
-> crit
);
117 hdr
= & u
-> ohdrs
[ u
-> cur_ohdr
];
118 if ( hdr
-> dwFlags
& WHDR_PREPARED
)
119 waveOutUnprepareHeader ( u
-> hwo
, hdr
, sizeof ( WAVEHDR
));
123 cur_chunk
= & memchunk
;
125 if ( pa_sink_render ( u
-> sink
, remain
, cur_chunk
) < 0 ) {
127 * Don't fill with silence unless we're getting close to
130 if ( free_frags
> u
-> fragments
/ 2 )
131 cur_chunk
= & u
-> silence
;
133 EnterCriticalSection (& u
-> crit
);
135 u
-> free_ofrags
+= free_frags
;
137 LeaveCriticalSection (& u
-> crit
);
144 assert ( cur_chunk
-> memblock
);
145 assert ( cur_chunk
-> memblock
-> data
);
146 assert ( cur_chunk
-> length
);
148 memcpy ( hdr
-> lpData
+ u
-> fragment_size
- remain
,
149 ( char *) cur_chunk
-> memblock
-> data
+ cur_chunk
-> index
,
150 ( cur_chunk
-> length
< remain
)? cur_chunk
-> length
: remain
);
152 remain
-= ( cur_chunk
-> length
< remain
)? cur_chunk
-> length
: remain
;
154 if ( cur_chunk
!= & u
-> silence
) {
155 pa_memblock_unref ( cur_chunk
-> memblock
);
156 cur_chunk
-> memblock
= NULL
;
160 res
= waveOutPrepareHeader ( u
-> hwo
, hdr
, sizeof ( WAVEHDR
));
161 if ( res
!= MMSYSERR_NOERROR
) {
162 pa_log_error ( __FILE__
": ERROR: Unable to prepare waveOut block: %d \n " ,
165 res
= waveOutWrite ( u
-> hwo
, hdr
, sizeof ( WAVEHDR
));
166 if ( res
!= MMSYSERR_NOERROR
) {
167 pa_log_error ( __FILE__
": ERROR: Unable to write waveOut block: %d \n " ,
171 u
-> written_bytes
+= u
-> fragment_size
;
175 u
-> cur_ohdr
%= u
-> fragments
;
176 u
-> oremain
= u
-> fragment_size
;
180 static void do_read ( struct userdata
* u
)
183 pa_memchunk memchunk
;
190 EnterCriticalSection (& u
-> crit
);
192 free_frags
= u
-> free_ifrags
;
195 LeaveCriticalSection (& u
-> crit
);
198 hdr
= & u
-> ihdrs
[ u
-> cur_ihdr
];
199 if ( hdr
-> dwFlags
& WHDR_PREPARED
)
200 waveInUnprepareHeader ( u
-> hwi
, hdr
, sizeof ( WAVEHDR
));
202 if ( hdr
-> dwBytesRecorded
) {
203 memchunk
. memblock
= pa_memblock_new ( hdr
-> dwBytesRecorded
, u
-> core
-> memblock_stat
);
204 assert ( memchunk
. memblock
);
206 memcpy (( char *) memchunk
. memblock
-> data
, hdr
-> lpData
, hdr
-> dwBytesRecorded
);
208 memchunk
. length
= memchunk
. memblock
-> length
= hdr
-> dwBytesRecorded
;
211 pa_source_post ( u
-> source
, & memchunk
);
212 pa_memblock_unref ( memchunk
. memblock
);
215 res
= waveInPrepareHeader ( u
-> hwi
, hdr
, sizeof ( WAVEHDR
));
216 if ( res
!= MMSYSERR_NOERROR
) {
217 pa_log_error ( __FILE__
": ERROR: Unable to prepare waveIn block: %d \n " ,
220 res
= waveInAddBuffer ( u
-> hwi
, hdr
, sizeof ( WAVEHDR
));
221 if ( res
!= MMSYSERR_NOERROR
) {
222 pa_log_error ( __FILE__
": ERROR: Unable to add waveIn block: %d \n " ,
228 u
-> cur_ihdr
%= u
-> fragments
;
232 static void poll_cb ( pa_mainloop_api
* a
, pa_time_event
* e
, const struct timeval
* tv
, void * userdata
) {
233 struct userdata
* u
= userdata
;
243 pa_gettimeofday (& ntv
);
244 pa_timeval_add (& ntv
, u
-> poll_timeout
);
246 a
-> time_restart ( e
, & ntv
);
249 static void defer_cb ( pa_mainloop_api
* a
, pa_defer_event
* e
, void * userdata
) {
250 struct userdata
* u
= userdata
;
254 a
-> defer_enable ( e
, 0 );
260 static void CALLBACK
chunk_done_cb ( HWAVEOUT hwo
, UINT msg
, DWORD_PTR inst
, DWORD param1
, DWORD param2
) {
261 struct userdata
* u
= ( struct userdata
*) inst
;
266 EnterCriticalSection (& u
-> crit
);
269 assert ( u
-> free_ofrags
<= u
-> fragments
);
271 LeaveCriticalSection (& u
-> crit
);
274 static void CALLBACK
chunk_ready_cb ( HWAVEIN hwi
, UINT msg
, DWORD_PTR inst
, DWORD param1
, DWORD param2
) {
275 struct userdata
* u
= ( struct userdata
*) inst
;
280 EnterCriticalSection (& u
-> crit
);
283 assert ( u
-> free_ifrags
<= u
-> fragments
);
285 LeaveCriticalSection (& u
-> crit
);
288 static pa_usec_t
sink_get_latency_cb ( pa_sink
* s
) {
289 struct userdata
* u
= s
-> userdata
;
292 assert ( s
&& u
&& u
-> sink
);
294 memset (& mmt
, 0 , sizeof ( mmt
));
295 mmt
. wType
= TIME_BYTES
;
296 if ( waveOutGetPosition ( u
-> hwo
, & mmt
, sizeof ( mmt
)) == MMSYSERR_NOERROR
)
297 return pa_bytes_to_usec ( u
-> written_bytes
- mmt
. u
. cb
, & s
-> sample_spec
);
299 EnterCriticalSection (& u
-> crit
);
301 free_frags
= u
-> free_ofrags
;
303 LeaveCriticalSection (& u
-> crit
);
305 return pa_bytes_to_usec (( u
-> fragments
- free_frags
) * u
-> fragment_size
,
310 static pa_usec_t
source_get_latency_cb ( pa_source
* s
) {
312 struct userdata
* u
= s
-> userdata
;
314 assert ( s
&& u
&& u
-> sink
);
316 EnterCriticalSection (& u
-> crit
);
318 free_frags
= u
-> free_ifrags
;
320 LeaveCriticalSection (& u
-> crit
);
322 r
+= pa_bytes_to_usec (( free_frags
+ 1 ) * u
-> fragment_size
, & s
-> sample_spec
);
327 static void notify_sink_cb ( pa_sink
* s
) {
328 struct userdata
* u
= s
-> userdata
;
331 u
-> core
-> mainloop
-> defer_enable ( u
-> defer
, 1 );
334 static void notify_source_cb ( pa_source
* s
) {
335 struct userdata
* u
= s
-> userdata
;
338 u
-> core
-> mainloop
-> defer_enable ( u
-> defer
, 1 );
341 static int sink_get_hw_volume_cb ( pa_sink
* s
) {
342 struct userdata
* u
= s
-> userdata
;
344 pa_volume_t left
, right
;
346 if ( waveOutGetVolume ( u
-> hwo
, & vol
) != MMSYSERR_NOERROR
)
349 left
= ( vol
& 0xFFFF ) * PA_VOLUME_NORM
/ WAVEOUT_MAX_VOLUME
;
350 right
= (( vol
>> 16 ) & 0xFFFF ) * PA_VOLUME_NORM
/ WAVEOUT_MAX_VOLUME
;
352 /* Windows supports > 2 channels, except for volume control */
353 if ( s
-> hw_volume
. channels
> 2 )
354 pa_cvolume_set (& s
-> hw_volume
, s
-> hw_volume
. channels
, ( left
+ right
)/ 2 );
356 s
-> hw_volume
. values
[ 0 ] = left
;
357 if ( s
-> hw_volume
. channels
> 1 )
358 s
-> hw_volume
. values
[ 1 ] = right
;
363 static int sink_set_hw_volume_cb ( pa_sink
* s
) {
364 struct userdata
* u
= s
-> userdata
;
367 vol
= s
-> hw_volume
. values
[ 0 ] * WAVEOUT_MAX_VOLUME
/ PA_VOLUME_NORM
;
368 if ( s
-> hw_volume
. channels
> 1 )
369 vol
|= ( s
-> hw_volume
. values
[ 0 ] * WAVEOUT_MAX_VOLUME
/ PA_VOLUME_NORM
) << 16 ;
371 if ( waveOutSetVolume ( u
-> hwo
, vol
) != MMSYSERR_NOERROR
)
377 static int ss_to_waveformat ( pa_sample_spec
* ss
, LPWAVEFORMATEX wf
) {
378 wf
-> wFormatTag
= WAVE_FORMAT_PCM
;
380 if ( ss
-> channels
> 2 ) {
381 pa_log_error ( __FILE__
": ERROR: More than two channels not supported. \n " );
385 wf
-> nChannels
= ss
-> channels
;
394 pa_log_error ( __FILE__
": ERROR: Unsupported sample rate. \n " );
398 wf
-> nSamplesPerSec
= ss
-> rate
;
400 if ( ss
-> format
== PA_SAMPLE_U8
)
401 wf
-> wBitsPerSample
= 8 ;
402 else if ( ss
-> format
== PA_SAMPLE_S16NE
)
403 wf
-> wBitsPerSample
= 16 ;
405 pa_log_error ( __FILE__
": ERROR: Unsupported sample format. \n " );
409 wf
-> nBlockAlign
= wf
-> nChannels
* wf
-> wBitsPerSample
/ 8 ;
410 wf
-> nAvgBytesPerSec
= wf
-> nSamplesPerSec
* wf
-> nBlockAlign
;
417 int pa__init ( pa_core
* c
, pa_module
* m
) {
418 struct userdata
* u
= NULL
;
419 HWAVEOUT hwo
= INVALID_HANDLE_VALUE
;
420 HWAVEIN hwi
= INVALID_HANDLE_VALUE
;
422 int nfrags
, frag_size
;
423 int record
= 1 , playback
= 1 ;
425 pa_modargs
* ma
= NULL
;
431 if (!( ma
= pa_modargs_new ( m
-> argument
, valid_modargs
))) {
432 pa_log ( __FILE__
": failed to parse module arguments. \n " );
436 if ( pa_modargs_get_value_boolean ( ma
, "record" , & record
) < 0 || pa_modargs_get_value_boolean ( ma
, "playback" , & playback
) < 0 ) {
437 pa_log ( __FILE__
": record= and playback= expect boolean argument. \n " );
441 if (! playback
&& ! record
) {
442 pa_log ( __FILE__
": neither playback nor record enabled for device. \n " );
448 if ( pa_modargs_get_value_s32 ( ma
, "fragments" , & nfrags
) < 0 || pa_modargs_get_value_s32 ( ma
, "fragment_size" , & frag_size
) < 0 ) {
449 pa_log ( __FILE__
": failed to parse fragments arguments \n " );
453 ss
= c
-> default_sample_spec
;
454 if ( pa_modargs_get_sample_spec ( ma
, & ss
) < 0 ) {
455 pa_log ( __FILE__
": failed to parse sample specification \n " );
459 if ( ss_to_waveformat (& ss
, & wf
) < 0 )
462 u
= pa_xmalloc ( sizeof ( struct userdata
));
465 if ( waveInOpen (& hwi
, WAVE_MAPPER
, & wf
, ( DWORD_PTR
) chunk_ready_cb
, ( DWORD_PTR
) u
, CALLBACK_FUNCTION
) != MMSYSERR_NOERROR
)
467 if ( waveInStart ( hwi
) != MMSYSERR_NOERROR
)
469 pa_log_debug ( __FILE__
": Opened waveIn subsystem. \n " );
473 if ( waveOutOpen (& hwo
, WAVE_MAPPER
, & wf
, ( DWORD_PTR
) chunk_done_cb
, ( DWORD_PTR
) u
, CALLBACK_FUNCTION
) != MMSYSERR_NOERROR
)
475 pa_log_debug ( __FILE__
": Opened waveOut subsystem. \n " );
478 InitializeCriticalSection (& u
-> crit
);
480 if ( hwi
!= INVALID_HANDLE_VALUE
) {
481 u
-> source
= pa_source_new ( c
, __FILE__
, pa_modargs_get_value ( ma
, "source_name" , DEFAULT_SOURCE_NAME
), 0 , & ss
, NULL
);
483 u
-> source
-> userdata
= u
;
484 u
-> source
-> notify
= notify_source_cb
;
485 u
-> source
-> get_latency
= source_get_latency_cb
;
486 pa_source_set_owner ( u
-> source
, m
);
487 u
-> source
-> description
= pa_sprintf_malloc ( "Windows waveIn PCM" );
491 if ( hwo
!= INVALID_HANDLE_VALUE
) {
492 u
-> sink
= pa_sink_new ( c
, __FILE__
, pa_modargs_get_value ( ma
, "sink_name" , DEFAULT_SINK_NAME
), 0 , & ss
, NULL
);
494 u
-> sink
-> notify
= notify_sink_cb
;
495 u
-> sink
-> get_latency
= sink_get_latency_cb
;
496 u
-> sink
-> get_hw_volume
= sink_get_hw_volume_cb
;
497 u
-> sink
-> set_hw_volume
= sink_set_hw_volume_cb
;
498 u
-> sink
-> userdata
= u
;
499 pa_sink_set_owner ( u
-> sink
, m
);
500 u
-> sink
-> description
= pa_sprintf_malloc ( "Windows waveOut PCM" );
504 assert ( u
-> source
|| u
-> sink
);
510 u
-> fragments
= nfrags
;
511 u
-> free_ifrags
= u
-> fragments
;
512 u
-> free_ofrags
= u
-> fragments
;
513 u
-> fragment_size
= frag_size
- ( frag_size
% pa_frame_size (& ss
));
515 u
-> written_bytes
= 0 ;
517 u
-> oremain
= u
-> fragment_size
;
519 u
-> poll_timeout
= pa_bytes_to_usec ( u
-> fragments
* u
-> fragment_size
/ 3 , & ss
);
521 pa_gettimeofday (& tv
);
522 pa_timeval_add (& tv
, u
-> poll_timeout
);
524 u
-> event
= c
-> mainloop
-> time_new ( c
-> mainloop
, & tv
, poll_cb
, u
);
527 u
-> defer
= c
-> mainloop
-> defer_new ( c
-> mainloop
, defer_cb
, u
);
529 c
-> mainloop
-> defer_enable ( u
-> defer
, 0 );
533 u
-> ihdrs
= pa_xmalloc0 ( sizeof ( WAVEHDR
) * u
-> fragments
);
535 u
-> ohdrs
= pa_xmalloc0 ( sizeof ( WAVEHDR
) * u
-> fragments
);
537 for ( i
= 0 ; i
< u
-> fragments
; i
++) {
538 u
-> ihdrs
[ i
]. dwBufferLength
= u
-> fragment_size
;
539 u
-> ohdrs
[ i
]. dwBufferLength
= u
-> fragment_size
;
540 u
-> ihdrs
[ i
]. lpData
= pa_xmalloc ( u
-> fragment_size
);
542 u
-> ohdrs
[ i
]. lpData
= pa_xmalloc ( u
-> fragment_size
);
546 u
-> silence
. length
= u
-> fragment_size
;
547 u
-> silence
. memblock
= pa_memblock_new ( u
-> silence
. length
, u
-> core
-> memblock_stat
);
548 assert ( u
-> silence
. memblock
);
549 pa_silence_memblock ( u
-> silence
. memblock
, & ss
);
550 u
-> silence
. index
= 0 ;
560 if ( hwi
!= INVALID_HANDLE_VALUE
)
563 if ( hwo
!= INVALID_HANDLE_VALUE
)
575 void pa__done ( pa_core
* c
, pa_module
* m
) {
581 if (!( u
= m
-> userdata
))
585 c
-> mainloop
-> time_free ( u
-> event
);
588 c
-> mainloop
-> defer_free ( u
-> defer
);
591 pa_sink_disconnect ( u
-> sink
);
592 pa_sink_unref ( u
-> sink
);
596 pa_source_disconnect ( u
-> source
);
597 pa_source_unref ( u
-> source
);
600 if ( u
-> hwi
!= INVALID_HANDLE_VALUE
) {
605 if ( u
-> hwo
!= INVALID_HANDLE_VALUE
) {
606 waveOutReset ( u
-> hwo
);
607 waveOutClose ( u
-> hwo
);
610 for ( i
= 0 ; i
< u
-> fragments
; i
++) {
611 pa_xfree ( u
-> ihdrs
[ i
]. lpData
);
612 pa_xfree ( u
-> ohdrs
[ i
]. lpData
);
618 DeleteCriticalSection (& u
-> crit
);