]>
code.delx.au - pulseaudio/blob - polyp/module-oss.c
969761f686b5af05b886a656e77b7f4bdfab2962
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 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 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
26 #include <sys/soundcard.h>
27 #include <sys/ioctl.h>
38 #include "iochannel.h"
43 #include "sample-util.h"
48 #include "module-oss-symdef.h"
50 PA_MODULE_AUTHOR ( "Lennart Poettering" )
51 PA_MODULE_DESCRIPTION ( "OSS Sink/Source" )
52 PA_MODULE_VERSION ( PACKAGE_VERSION
)
53 PA_MODULE_USAGE ( "sink_name=<name for the sink> source_name=<name for the source> device=<OSS device> record=<enable source?> playback=<enable sink?> format=<sample format> channels=<number of channels> rate=<sample rate> fragments=<number of fragments> fragment_size=<fragment size>" )
57 struct pa_source
* source
;
58 struct pa_iochannel
* io
;
61 struct pa_memchunk memchunk
, silence
;
63 uint32_t in_fragment_size
, out_fragment_size
, sample_size
;
64 int use_getospace
, use_getispace
;
67 struct pa_module
* module
;
70 static const char * const valid_modargs
[] = {
84 #define DEFAULT_SINK_NAME "oss_output"
85 #define DEFAULT_SOURCE_NAME "oss_input"
86 #define DEFAULT_DEVICE "/dev/dsp"
88 static void update_usage ( struct userdata
* u
) {
89 pa_module_set_used ( u
-> module
,
90 ( u
-> sink
? pa_idxset_ncontents ( u
-> sink
-> inputs
) : 0 ) +
91 ( u
-> sink
? pa_idxset_ncontents ( u
-> sink
-> monitor_source
-> outputs
) : 0 ) +
92 ( u
-> source
? pa_idxset_ncontents ( u
-> source
-> outputs
) : 0 ));
95 static void do_write ( struct userdata
* u
) {
96 struct pa_memchunk
* memchunk
;
103 if (! u
-> sink
|| ! pa_iochannel_is_writable ( u
-> io
))
108 l
= u
-> out_fragment_size
;
110 if ( u
-> use_getospace
) {
113 if ( ioctl ( u
-> fd
, SNDCTL_DSP_GETOSPACE
, & info
) < 0 )
114 u
-> use_getospace
= 0 ;
116 if ( info
. bytes
/ l
> 0 ) {
117 l
= ( info
. bytes
/ l
)* l
;
124 memchunk
= & u
-> memchunk
;
126 if (! memchunk
-> length
)
127 if ( pa_sink_render ( u
-> sink
, l
, memchunk
) < 0 )
128 memchunk
= & u
-> silence
;
130 assert ( memchunk
-> memblock
);
131 assert ( memchunk
-> memblock
-> data
);
132 assert ( memchunk
-> length
);
134 if (( r
= pa_iochannel_write ( u
-> io
, ( uint8_t *) memchunk
-> memblock
-> data
+ memchunk
-> index
, memchunk
-> length
)) < 0 ) {
135 pa_log ( __FILE__
": write() failed: %s \n " , strerror ( errno
));
139 if ( memchunk
== & u
-> silence
)
140 assert ( r
% u
-> sample_size
== 0 );
142 u
-> memchunk
. index
+= r
;
143 u
-> memchunk
. length
-= r
;
145 if ( u
-> memchunk
. length
<= 0 ) {
146 pa_memblock_unref ( u
-> memchunk
. memblock
);
147 u
-> memchunk
. memblock
= NULL
;
151 l
= l
> ( size_t ) r
? l
- r
: 0 ;
152 } while ( loop
&& l
> 0 );
155 static void do_read ( struct userdata
* u
) {
156 struct pa_memchunk memchunk
;
162 if (! u
-> source
|| ! pa_iochannel_is_readable ( u
-> io
))
167 l
= u
-> in_fragment_size
;
169 if ( u
-> use_getispace
) {
172 if ( ioctl ( u
-> fd
, SNDCTL_DSP_GETISPACE
, & info
) < 0 )
173 u
-> use_getispace
= 0 ;
175 if ( info
. bytes
/ l
> 0 ) {
176 l
= ( info
. bytes
/ l
)* l
;
183 memchunk
. memblock
= pa_memblock_new ( l
, u
-> core
-> memblock_stat
);
184 assert ( memchunk
. memblock
);
185 if (( r
= pa_iochannel_read ( u
-> io
, memchunk
. memblock
-> data
, memchunk
. memblock
-> length
)) < 0 ) {
186 pa_memblock_unref ( memchunk
. memblock
);
188 pa_log ( __FILE__
": read() failed: %s \n " , strerror ( errno
));
192 assert ( r
<= ( ssize_t
) memchunk
. memblock
-> length
);
193 memchunk
. length
= memchunk
. memblock
-> length
= r
;
196 pa_source_post ( u
-> source
, & memchunk
);
197 pa_memblock_unref ( memchunk
. memblock
);
199 l
= l
> ( size_t ) r
? l
- r
: 0 ;
200 } while ( loop
&& l
> 0 );
203 static void io_callback ( struct pa_iochannel
* io
, void * userdata
) {
204 struct userdata
* u
= userdata
;
210 static pa_usec_t
sink_get_latency_cb ( struct pa_sink
* s
) {
213 struct userdata
* u
= s
-> userdata
;
214 assert ( s
&& u
&& u
-> sink
);
216 if ( ioctl ( u
-> fd
, SNDCTL_DSP_GETODELAY
, & arg
) < 0 ) {
217 pa_log ( __FILE__
": device doesn't support SNDCTL_DSP_GETODELAY. \n " );
218 s
-> get_latency
= NULL
;
222 r
+= pa_bytes_to_usec ( arg
, & s
-> sample_spec
);
224 if ( u
-> memchunk
. memblock
)
225 r
+= pa_bytes_to_usec ( u
-> memchunk
. length
, & s
-> sample_spec
);
230 static pa_usec_t
source_get_latency_cb ( struct pa_source
* s
) {
231 struct userdata
* u
= s
-> userdata
;
233 assert ( s
&& u
&& u
-> sink
);
235 if (! u
-> use_getispace
)
238 if ( ioctl ( u
-> fd
, SNDCTL_DSP_GETISPACE
, & info
) < 0 ) {
239 u
-> use_getispace
= 0 ;
246 return pa_bytes_to_usec ( info
. bytes
, & s
-> sample_spec
);
249 int pa__init ( struct pa_core
* c
, struct pa_module
* m
) {
250 struct audio_buf_info info
;
251 struct userdata
* u
= NULL
;
254 int nfrags
, frag_size
, in_frag_size
, out_frag_size
;
256 int record
= 1 , playback
= 1 ;
257 struct pa_sample_spec ss
;
258 struct pa_modargs
* ma
= NULL
;
261 if (!( ma
= pa_modargs_new ( m
-> argument
, valid_modargs
))) {
262 pa_log ( __FILE__
": failed to parse module arguments. \n " );
266 if ( pa_modargs_get_value_boolean ( ma
, "record" , & record
) < 0 || pa_modargs_get_value_boolean ( ma
, "playback" , & playback
) < 0 ) {
267 pa_log ( __FILE__
": record= and playback= expect numeric argument. \n " );
271 if (! playback
&& ! record
) {
272 pa_log ( __FILE__
": neither playback nor record enabled for device. \n " );
276 mode
= ( playback
&& record
) ? O_RDWR
: ( playback
? O_WRONLY
: ( record
? O_RDONLY
: 0 ));
280 if ( pa_modargs_get_value_s32 ( ma
, "fragments" , & nfrags
) < 0 || pa_modargs_get_value_s32 ( ma
, "fragment_size" , & frag_size
) < 0 ) {
281 pa_log ( __FILE__
": failed to parse fragments arguments \n " );
285 ss
= c
-> default_sample_spec
;
286 if ( pa_modargs_get_sample_spec ( ma
, & ss
) < 0 ) {
287 pa_log ( __FILE__
": failed to parse sample specification \n " );
291 if (( fd
= pa_oss_open ( p
= pa_modargs_get_value ( ma
, "device" , DEFAULT_DEVICE
), & mode
, NULL
)) < 0 )
294 pa_log ( __FILE__
": device opened in %s mode. \n " , mode
== O_WRONLY
? "O_WRONLY" : ( mode
== O_RDONLY
? "O_RDONLY" : "O_RDWR" ));
297 if ( nfrags
>= 2 && frag_size
>= 1 )
298 if ( pa_oss_set_fragments ( fd
, nfrags
, frag_size
) < 0 )
301 if ( pa_oss_auto_format ( fd
, & ss
) < 0 )
304 if ( ioctl ( fd
, SNDCTL_DSP_GETBLKSIZE
, & frag_size
) < 0 ) {
305 pa_log ( __FILE__
": SNDCTL_DSP_GETBLKSIZE: %s \n " , strerror ( errno
));
309 in_frag_size
= out_frag_size
= frag_size
;
311 u
= pa_xmalloc ( sizeof ( struct userdata
));
313 u
-> use_getospace
= u
-> use_getispace
= 0 ;
315 if ( ioctl ( fd
, SNDCTL_DSP_GETISPACE
, & info
) >= 0 ) {
316 pa_log ( __FILE__
": input -- %u fragments of size %u. \n " , info
. fragstotal
, info
. fragsize
);
317 in_frag_size
= info
. fragsize
;
318 u
-> use_getispace
= 1 ;
321 if ( ioctl ( fd
, SNDCTL_DSP_GETOSPACE
, & info
) >= 0 ) {
322 pa_log ( __FILE__
": output -- %u fragments of size %u. \n " , info
. fragstotal
, info
. fragsize
);
323 out_frag_size
= info
. fragsize
;
324 u
-> use_getospace
= 1 ;
327 if ( mode
!= O_WRONLY
) {
328 u
-> source
= pa_source_new ( c
, pa_modargs_get_value ( ma
, "source_name" , DEFAULT_SOURCE_NAME
), 0 , & ss
);
330 u
-> source
-> userdata
= u
;
331 u
-> source
-> get_latency
= source_get_latency_cb
;
332 pa_source_set_owner ( u
-> source
, m
);
333 u
-> source
-> description
= pa_sprintf_malloc ( "Open Sound System PCM on '%s'" , p
);
337 if ( mode
!= O_RDONLY
) {
338 u
-> sink
= pa_sink_new ( c
, pa_modargs_get_value ( ma
, "sink_name" , DEFAULT_SINK_NAME
), 0 , & ss
);
340 u
-> sink
-> get_latency
= sink_get_latency_cb
;
341 u
-> sink
-> userdata
= u
;
342 pa_sink_set_owner ( u
-> sink
, m
);
343 u
-> sink
-> description
= pa_sprintf_malloc ( "Open Sound System PCM on '%s'" , p
);
347 assert ( u
-> source
|| u
-> sink
);
349 u
-> io
= pa_iochannel_new ( c
-> mainloop
, u
-> source
? fd
: - 1 , u
-> sink
? fd
: 0 );
351 pa_iochannel_set_callback ( u
-> io
, io_callback
, u
);
354 u
-> memchunk
. memblock
= NULL
;
355 u
-> memchunk
. length
= 0 ;
356 u
-> sample_size
= pa_frame_size (& ss
);
358 u
-> out_fragment_size
= out_frag_size
;
359 u
-> in_fragment_size
= in_frag_size
;
360 u
-> silence
. memblock
= pa_memblock_new ( u
-> silence
. length
= u
-> out_fragment_size
, u
-> core
-> memblock_stat
);
361 assert ( u
-> silence
. memblock
);
362 pa_silence_memblock ( u
-> silence
. memblock
, & ss
);
363 u
-> silence
. index
= 0 ;
382 void pa__done ( struct pa_core
* c
, struct pa_module
* m
) {
386 if (!( u
= m
-> userdata
))
389 if ( u
-> memchunk
. memblock
)
390 pa_memblock_unref ( u
-> memchunk
. memblock
);
391 if ( u
-> silence
. memblock
)
392 pa_memblock_unref ( u
-> silence
. memblock
);
395 pa_sink_disconnect ( u
-> sink
);
396 pa_sink_unref ( u
-> sink
);
400 pa_source_disconnect ( u
-> source
);
401 pa_source_unref ( u
-> source
);
404 pa_iochannel_free ( u
-> io
);