]>
code.delx.au - pulseaudio/blob - polyp/module-waveout.c
1 /* $Id: module-waveout.c 333 2005-01-08 21:36:53Z lennart $ */
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
33 #include "mainloop-api.h"
35 #include "sample-util.h"
39 #include "module-waveout-symdef.h"
41 PA_MODULE_AUTHOR ( "Pierre Ossman" )
42 PA_MODULE_DESCRIPTION ( "Windows waveOut Sink/Source" )
43 PA_MODULE_VERSION ( PACKAGE_VERSION
)
44 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>" )
46 #define PA_TYPEID_WAVEOUT PA_TYPEID_MAKE( 'W' , 'A' , 'V' , 'E' )
48 #define DEFAULT_SINK_NAME "wave_output"
49 #define DEFAULT_SOURCE_NAME "wave_input"
53 struct pa_source
* source
;
55 struct pa_time_event
* event
;
56 struct pa_defer_event
* defer
;
57 pa_usec_t poll_timeout
;
59 uint32_t fragments
, fragment_size
;
61 uint32_t free_ofrags
, free_ifrags
;
65 int cur_ohdr
, cur_ihdr
;
67 WAVEHDR
* ohdrs
, * ihdrs
;
68 struct pa_memchunk silence
;
72 struct pa_module
* module
;
74 CRITICAL_SECTION crit
;
77 static const char * const valid_modargs
[] = {
90 static void update_usage ( struct userdata
* u
) {
91 pa_module_set_used ( u
-> module
,
92 ( u
-> sink
? pa_idxset_ncontents ( u
-> sink
-> inputs
) : 0 ) +
93 ( u
-> sink
? pa_idxset_ncontents ( u
-> sink
-> monitor_source
-> outputs
) : 0 ) +
94 ( u
-> source
? pa_idxset_ncontents ( u
-> source
-> outputs
) : 0 ));
97 static void do_write ( struct userdata
* u
)
99 uint32_t free_frags
, remain
;
100 struct pa_memchunk memchunk
, * cur_chunk
;
107 EnterCriticalSection (& u
-> crit
);
109 free_frags
= u
-> free_ofrags
;
112 LeaveCriticalSection (& u
-> crit
);
115 hdr
= & u
-> ohdrs
[ u
-> cur_ohdr
];
116 if ( hdr
-> dwFlags
& WHDR_PREPARED
)
117 waveOutUnprepareHeader ( u
-> hwo
, hdr
, sizeof ( WAVEHDR
));
121 cur_chunk
= & memchunk
;
123 if ( pa_sink_render ( u
-> sink
, remain
, cur_chunk
) < 0 ) {
125 * Don't fill with silence unless we're getting close to
128 if ( free_frags
> u
-> fragments
/ 2 )
129 cur_chunk
= & u
-> silence
;
131 EnterCriticalSection (& u
-> crit
);
133 u
-> free_ofrags
+= free_frags
;
135 LeaveCriticalSection (& u
-> crit
);
142 assert ( cur_chunk
-> memblock
);
143 assert ( cur_chunk
-> memblock
-> data
);
144 assert ( cur_chunk
-> length
);
146 memcpy ( hdr
-> lpData
+ u
-> fragment_size
- remain
,
147 ( char *) cur_chunk
-> memblock
-> data
+ cur_chunk
-> index
,
148 ( cur_chunk
-> length
< remain
)? cur_chunk
-> length
: remain
);
150 remain
-= ( cur_chunk
-> length
< remain
)? cur_chunk
-> length
: remain
;
152 if ( cur_chunk
!= & u
-> silence
) {
153 pa_memblock_unref ( cur_chunk
-> memblock
);
154 cur_chunk
-> memblock
= NULL
;
158 res
= waveOutPrepareHeader ( u
-> hwo
, hdr
, sizeof ( WAVEHDR
));
159 if ( res
!= MMSYSERR_NOERROR
) {
160 pa_log_error ( __FILE__
": ERROR: Unable to prepare waveOut block: %d \n " ,
163 res
= waveOutWrite ( u
-> hwo
, hdr
, sizeof ( WAVEHDR
));
164 if ( res
!= MMSYSERR_NOERROR
) {
165 pa_log_error ( __FILE__
": ERROR: Unable to write waveOut block: %d \n " ,
169 u
-> written_bytes
+= u
-> fragment_size
;
173 u
-> cur_ohdr
%= u
-> fragments
;
174 u
-> oremain
= u
-> fragment_size
;
178 static void do_read ( struct userdata
* u
)
181 struct pa_memchunk memchunk
;
188 EnterCriticalSection (& u
-> crit
);
190 free_frags
= u
-> free_ifrags
;
193 LeaveCriticalSection (& u
-> crit
);
196 hdr
= & u
-> ihdrs
[ u
-> cur_ihdr
];
197 if ( hdr
-> dwFlags
& WHDR_PREPARED
)
198 waveInUnprepareHeader ( u
-> hwi
, hdr
, sizeof ( WAVEHDR
));
200 if ( hdr
-> dwBytesRecorded
) {
201 memchunk
. memblock
= pa_memblock_new ( hdr
-> dwBytesRecorded
, u
-> core
-> memblock_stat
);
202 assert ( memchunk
. memblock
);
204 memcpy (( char *) memchunk
. memblock
-> data
, hdr
-> lpData
, hdr
-> dwBytesRecorded
);
206 memchunk
. length
= memchunk
. memblock
-> length
= hdr
-> dwBytesRecorded
;
209 pa_source_post ( u
-> source
, & memchunk
);
210 pa_memblock_unref ( memchunk
. memblock
);
213 res
= waveInPrepareHeader ( u
-> hwi
, hdr
, sizeof ( WAVEHDR
));
214 if ( res
!= MMSYSERR_NOERROR
) {
215 pa_log_error ( __FILE__
": ERROR: Unable to prepare waveIn block: %d \n " ,
218 res
= waveInAddBuffer ( u
-> hwi
, hdr
, sizeof ( WAVEHDR
));
219 if ( res
!= MMSYSERR_NOERROR
) {
220 pa_log_error ( __FILE__
": ERROR: Unable to add waveIn block: %d \n " ,
226 u
-> cur_ihdr
%= u
-> fragments
;
230 static void poll_cb ( struct pa_mainloop_api
* a
, struct pa_time_event
* e
, const struct timeval
* tv
, void * userdata
) {
231 struct userdata
* u
= userdata
;
241 pa_gettimeofday (& ntv
);
242 pa_timeval_add (& ntv
, u
-> poll_timeout
);
244 a
-> time_restart ( e
, & ntv
);
247 static void defer_cb ( struct pa_mainloop_api
* a
, struct pa_defer_event
* e
, void * userdata
) {
248 struct userdata
* u
= userdata
;
252 a
-> defer_enable ( e
, 0 );
258 static void CALLBACK
chunk_done_cb ( HWAVEOUT hwo
, UINT msg
, DWORD_PTR inst
, DWORD param1
, DWORD param2
) {
259 struct userdata
* u
= ( struct userdata
*) inst
;
264 EnterCriticalSection (& u
-> crit
);
267 assert ( u
-> free_ofrags
<= u
-> fragments
);
269 LeaveCriticalSection (& u
-> crit
);
272 static void CALLBACK
chunk_ready_cb ( HWAVEIN hwi
, UINT msg
, DWORD_PTR inst
, DWORD param1
, DWORD param2
) {
273 struct userdata
* u
= ( struct userdata
*) inst
;
278 EnterCriticalSection (& u
-> crit
);
281 assert ( u
-> free_ifrags
<= u
-> fragments
);
283 LeaveCriticalSection (& u
-> crit
);
286 static pa_usec_t
sink_get_latency_cb ( struct pa_sink
* s
) {
287 struct userdata
* u
= s
-> userdata
;
290 assert ( s
&& u
&& u
-> sink
);
292 memset (& mmt
, 0 , sizeof ( mmt
));
293 mmt
. wType
= TIME_BYTES
;
294 if ( waveOutGetPosition ( u
-> hwo
, & mmt
, sizeof ( mmt
)) == MMSYSERR_NOERROR
)
295 return pa_bytes_to_usec ( u
-> written_bytes
- mmt
. u
. cb
, & s
-> sample_spec
);
297 EnterCriticalSection (& u
-> crit
);
299 free_frags
= u
-> free_ofrags
;
301 LeaveCriticalSection (& u
-> crit
);
303 return pa_bytes_to_usec (( u
-> fragments
- free_frags
) * u
-> fragment_size
,
308 static pa_usec_t
source_get_latency_cb ( struct pa_source
* s
) {
310 struct userdata
* u
= s
-> userdata
;
312 assert ( s
&& u
&& u
-> sink
);
314 EnterCriticalSection (& u
-> crit
);
316 free_frags
= u
-> free_ifrags
;
318 LeaveCriticalSection (& u
-> crit
);
320 r
+= pa_bytes_to_usec (( free_frags
+ 1 ) * u
-> fragment_size
, & s
-> sample_spec
);
322 fprintf ( stderr
, "Latency: %d us \n " , ( int ) r
);
327 static void notify_sink_cb ( struct pa_sink
* s
) {
328 struct userdata
* u
= s
-> userdata
;
331 u
-> core
-> mainloop
-> defer_enable ( u
-> defer
, 1 );
334 static void notify_source_cb ( struct pa_source
* s
) {
335 struct userdata
* u
= s
-> userdata
;
338 u
-> core
-> mainloop
-> defer_enable ( u
-> defer
, 1 );
341 static int ss_to_waveformat ( struct pa_sample_spec
* ss
, LPWAVEFORMATEX wf
) {
342 wf
-> wFormatTag
= WAVE_FORMAT_PCM
;
344 if ( ss
-> channels
> 2 ) {
345 pa_log_error ( __FILE__
": ERROR: More than two channels not supported. \n " );
349 wf
-> nChannels
= ss
-> channels
;
358 pa_log_error ( __FILE__
": ERROR: Unsupported sample rate. \n " );
362 wf
-> nSamplesPerSec
= ss
-> rate
;
364 if ( ss
-> format
== PA_SAMPLE_U8
)
365 wf
-> wBitsPerSample
= 8 ;
366 else if ( ss
-> format
== PA_SAMPLE_S16NE
)
367 wf
-> wBitsPerSample
= 16 ;
369 pa_log_error ( __FILE__
": ERROR: Unsupported sample format. \n " );
373 wf
-> nBlockAlign
= wf
-> nChannels
* wf
-> wBitsPerSample
/ 8 ;
374 wf
-> nAvgBytesPerSec
= wf
-> nSamplesPerSec
* wf
-> nBlockAlign
;
381 int pa__init ( struct pa_core
* c
, struct pa_module
* m
) {
382 struct userdata
* u
= NULL
;
383 HWAVEOUT hwo
= INVALID_HANDLE_VALUE
;
384 HWAVEIN hwi
= INVALID_HANDLE_VALUE
;
386 int nfrags
, frag_size
;
387 int record
= 1 , playback
= 1 ;
388 struct pa_sample_spec ss
;
389 struct pa_modargs
* ma
= NULL
;
395 if (!( ma
= pa_modargs_new ( m
-> argument
, valid_modargs
))) {
396 pa_log ( __FILE__
": failed to parse module arguments. \n " );
400 if ( pa_modargs_get_value_boolean ( ma
, "record" , & record
) < 0 || pa_modargs_get_value_boolean ( ma
, "playback" , & playback
) < 0 ) {
401 pa_log ( __FILE__
": record= and playback= expect boolean argument. \n " );
405 if (! playback
&& ! record
) {
406 pa_log ( __FILE__
": neither playback nor record enabled for device. \n " );
412 if ( pa_modargs_get_value_s32 ( ma
, "fragments" , & nfrags
) < 0 || pa_modargs_get_value_s32 ( ma
, "fragment_size" , & frag_size
) < 0 ) {
413 pa_log ( __FILE__
": failed to parse fragments arguments \n " );
417 ss
= c
-> default_sample_spec
;
418 if ( pa_modargs_get_sample_spec ( ma
, & ss
) < 0 ) {
419 pa_log ( __FILE__
": failed to parse sample specification \n " );
423 if ( ss_to_waveformat (& ss
, & wf
) < 0 )
426 u
= pa_xmalloc ( sizeof ( struct userdata
));
429 if ( waveInOpen (& hwi
, WAVE_MAPPER
, & wf
, ( DWORD_PTR
) chunk_ready_cb
, ( DWORD_PTR
) u
, CALLBACK_FUNCTION
) != MMSYSERR_NOERROR
)
431 if ( waveInStart ( hwi
) != MMSYSERR_NOERROR
)
433 pa_log_debug ( __FILE__
": Opened waveIn subsystem. \n " );
437 if ( waveOutOpen (& hwo
, WAVE_MAPPER
, & wf
, ( DWORD_PTR
) chunk_done_cb
, ( DWORD_PTR
) u
, CALLBACK_FUNCTION
) != MMSYSERR_NOERROR
)
439 pa_log_debug ( __FILE__
": Opened waveOut subsystem. \n " );
442 InitializeCriticalSection (& u
-> crit
);
444 if ( hwi
!= INVALID_HANDLE_VALUE
) {
445 u
-> source
= pa_source_new ( c
, PA_TYPEID_WAVEOUT
, pa_modargs_get_value ( ma
, "source_name" , DEFAULT_SOURCE_NAME
), 0 , & ss
);
447 u
-> source
-> userdata
= u
;
448 u
-> source
-> notify
= notify_source_cb
;
449 u
-> source
-> get_latency
= source_get_latency_cb
;
450 pa_source_set_owner ( u
-> source
, m
);
451 u
-> source
-> description
= pa_sprintf_malloc ( "Windows waveIn PCM" );
455 if ( hwo
!= INVALID_HANDLE_VALUE
) {
456 u
-> sink
= pa_sink_new ( c
, PA_TYPEID_WAVEOUT
, pa_modargs_get_value ( ma
, "sink_name" , DEFAULT_SINK_NAME
), 0 , & ss
);
458 u
-> sink
-> notify
= notify_sink_cb
;
459 u
-> sink
-> get_latency
= sink_get_latency_cb
;
460 u
-> sink
-> userdata
= u
;
461 pa_sink_set_owner ( u
-> sink
, m
);
462 u
-> sink
-> description
= pa_sprintf_malloc ( "Windows waveOut PCM" );
466 assert ( u
-> source
|| u
-> sink
);
472 u
-> fragments
= nfrags
;
473 u
-> free_ifrags
= u
-> fragments
;
474 u
-> free_ofrags
= u
-> fragments
;
475 u
-> fragment_size
= frag_size
- ( frag_size
% pa_frame_size (& ss
));
477 u
-> written_bytes
= 0 ;
479 u
-> oremain
= u
-> fragment_size
;
481 u
-> poll_timeout
= pa_bytes_to_usec ( u
-> fragments
* u
-> fragment_size
/ 3 , & ss
);
483 pa_gettimeofday (& tv
);
484 pa_timeval_add (& tv
, u
-> poll_timeout
);
486 u
-> event
= c
-> mainloop
-> time_new ( c
-> mainloop
, & tv
, poll_cb
, u
);
489 u
-> defer
= c
-> mainloop
-> defer_new ( c
-> mainloop
, defer_cb
, u
);
491 c
-> mainloop
-> defer_enable ( u
-> defer
, 0 );
495 u
-> ihdrs
= pa_xmalloc0 ( sizeof ( WAVEHDR
) * u
-> fragments
);
497 u
-> ohdrs
= pa_xmalloc0 ( sizeof ( WAVEHDR
) * u
-> fragments
);
499 for ( i
= 0 ; i
< u
-> fragments
; i
++) {
500 u
-> ihdrs
[ i
]. dwBufferLength
= u
-> fragment_size
;
501 u
-> ohdrs
[ i
]. dwBufferLength
= u
-> fragment_size
;
502 u
-> ihdrs
[ i
]. lpData
= pa_xmalloc ( u
-> fragment_size
);
504 u
-> ohdrs
[ i
]. lpData
= pa_xmalloc ( u
-> fragment_size
);
508 u
-> silence
. length
= u
-> fragment_size
;
509 u
-> silence
. memblock
= pa_memblock_new ( u
-> silence
. length
, u
-> core
-> memblock_stat
);
510 assert ( u
-> silence
. memblock
);
511 pa_silence_memblock ( u
-> silence
. memblock
, & ss
);
512 u
-> silence
. index
= 0 ;
522 if ( hwi
!= INVALID_HANDLE_VALUE
)
525 if ( hwo
!= INVALID_HANDLE_VALUE
)
537 void pa__done ( struct pa_core
* c
, struct pa_module
* m
) {
543 if (!( u
= m
-> userdata
))
547 c
-> mainloop
-> time_free ( u
-> event
);
550 c
-> mainloop
-> defer_free ( u
-> defer
);
553 pa_sink_disconnect ( u
-> sink
);
554 pa_sink_unref ( u
-> sink
);
558 pa_source_disconnect ( u
-> source
);
559 pa_source_unref ( u
-> source
);
562 if ( u
-> hwi
!= INVALID_HANDLE_VALUE
) {
567 if ( u
-> hwo
!= INVALID_HANDLE_VALUE
) {
568 waveOutReset ( u
-> hwo
);
569 waveOutClose ( u
-> hwo
);
572 for ( i
= 0 ; i
< u
-> fragments
; i
++) {
573 pa_xfree ( u
-> ihdrs
[ i
]. lpData
);
574 pa_xfree ( u
-> ohdrs
[ i
]. lpData
);
580 DeleteCriticalSection (& u
-> crit
);