]>
code.delx.au - pulseaudio/blob - src/modules/module-solaris.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
34 #include <sys/ioctl.h>
36 #include <sys/types.h>
41 #include <sys/audio.h>
43 #include <polyp/mainloop-signal.h>
45 #include <polypcore/iochannel.h>
46 #include <polypcore/sink.h>
47 #include <polypcore/source.h>
48 #include <polypcore/module.h>
49 #include <polypcore/sample-util.h>
50 #include <polypcore/util.h>
51 #include <polypcore/modargs.h>
52 #include <polypcore/xmalloc.h>
53 #include <polypcore/log.h>
55 #include "module-solaris-symdef.h"
57 PA_MODULE_AUTHOR ( "Pierre Ossman" )
58 PA_MODULE_DESCRIPTION ( "Solaris Sink/Source" )
59 PA_MODULE_VERSION ( PACKAGE_VERSION
)
60 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> buffer_size=<record buffer size>" )
69 pa_memchunk memchunk
, silence
;
73 unsigned int written_bytes
, read_bytes
;
79 static const char * const valid_modargs
[] = {
92 #define DEFAULT_SINK_NAME "solaris_output"
93 #define DEFAULT_SOURCE_NAME "solaris_input"
94 #define DEFAULT_DEVICE "/dev/audio"
96 #define CHUNK_SIZE 2048
98 static void update_usage ( struct userdata
* u
) {
99 pa_module_set_used ( u
-> module
,
100 ( u
-> sink
? pa_idxset_size ( u
-> sink
-> inputs
) : 0 ) +
101 ( u
-> sink
? pa_idxset_size ( u
-> sink
-> monitor_source
-> outputs
) : 0 ) +
102 ( u
-> source
? pa_idxset_size ( u
-> source
-> outputs
) : 0 ));
105 static void do_write ( struct userdata
* u
) {
108 pa_memchunk
* memchunk
;
114 if (! u
-> sink
|| ! pa_iochannel_is_writable ( u
-> io
))
119 err
= ioctl ( u
-> fd
, AUDIO_GETINFO
, & info
);
123 * Since we cannot modify the size of the output buffer we fake it
124 * by not filling it more than u->buffer_size.
126 len
= u
-> buffer_size
;
127 len
-= u
-> written_bytes
- ( info
. play
. samples
* u
-> sample_size
);
130 * Do not fill more than half the buffer in one chunk since we only
131 * get notifications upon completion of entire chunks.
133 if ( len
> ( u
-> buffer_size
/ 2 ))
134 len
= u
-> buffer_size
/ 2 ;
136 if ( len
< u
-> sample_size
)
139 memchunk
= & u
-> memchunk
;
141 if (! memchunk
-> length
)
142 if ( pa_sink_render ( u
-> sink
, len
, memchunk
) < 0 )
143 memchunk
= & u
-> silence
;
145 assert ( memchunk
-> memblock
);
146 assert ( memchunk
-> memblock
-> data
);
147 assert ( memchunk
-> length
);
149 if ( memchunk
-> length
< len
)
150 len
= memchunk
-> length
;
152 if (( r
= pa_iochannel_write ( u
-> io
, ( uint8_t *) memchunk
-> memblock
-> data
+ memchunk
-> index
, len
)) < 0 ) {
153 pa_log ( __FILE__
": write() failed: %s \n " , strerror ( errno
));
157 if ( memchunk
== & u
-> silence
)
158 assert ( r
% u
-> sample_size
== 0 );
160 u
-> memchunk
. index
+= r
;
161 u
-> memchunk
. length
-= r
;
163 if ( u
-> memchunk
. length
<= 0 ) {
164 pa_memblock_unref ( u
-> memchunk
. memblock
);
165 u
-> memchunk
. memblock
= NULL
;
169 u
-> written_bytes
+= r
;
172 * Write 0 bytes which will generate a SIGPOLL when "played".
174 if ( write ( u
-> fd
, NULL
, 0 ) < 0 ) {
175 pa_log ( __FILE__
": write() failed: %s \n " , strerror ( errno
));
180 static void do_read ( struct userdata
* u
) {
181 pa_memchunk memchunk
;
186 if (! u
-> source
|| ! pa_iochannel_is_readable ( u
-> io
))
191 err
= ioctl ( u
-> fd
, I_NREAD
, & l
);
194 memchunk
. memblock
= pa_memblock_new ( l
, u
-> core
-> memblock_stat
);
195 assert ( memchunk
. memblock
);
196 if (( r
= pa_iochannel_read ( u
-> io
, memchunk
. memblock
-> data
, memchunk
. memblock
-> length
)) < 0 ) {
197 pa_memblock_unref ( memchunk
. memblock
);
199 pa_log ( __FILE__
": read() failed: %s \n " , strerror ( errno
));
203 assert ( r
<= ( ssize_t
) memchunk
. memblock
-> length
);
204 memchunk
. length
= memchunk
. memblock
-> length
= r
;
207 pa_source_post ( u
-> source
, & memchunk
);
208 pa_memblock_unref ( memchunk
. memblock
);
213 static void io_callback ( pa_iochannel
* io
, void * userdata
) {
214 struct userdata
* u
= userdata
;
220 void sig_callback ( pa_mainloop_api
* api
, pa_signal_event
* e
, int sig
, void * userdata
) {
221 struct userdata
* u
= userdata
;
226 static pa_usec_t
sink_get_latency_cb ( pa_sink
* s
) {
230 struct userdata
* u
= s
-> userdata
;
231 assert ( s
&& u
&& u
-> sink
);
233 err
= ioctl ( u
-> fd
, AUDIO_GETINFO
, & info
);
236 r
+= pa_bytes_to_usec ( u
-> written_bytes
, & s
-> sample_spec
);
237 r
-= pa_bytes_to_usec ( info
. play
. samples
* u
-> sample_size
, & s
-> sample_spec
);
239 if ( u
-> memchunk
. memblock
)
240 r
+= pa_bytes_to_usec ( u
-> memchunk
. length
, & s
-> sample_spec
);
245 static pa_usec_t
source_get_latency_cb ( pa_source
* s
) {
247 struct userdata
* u
= s
-> userdata
;
250 assert ( s
&& u
&& u
-> source
);
252 err
= ioctl ( u
-> fd
, AUDIO_GETINFO
, & info
);
255 r
+= pa_bytes_to_usec ( info
. record
. samples
* u
-> sample_size
, & s
-> sample_spec
);
256 r
-= pa_bytes_to_usec ( u
-> read_bytes
, & s
-> sample_spec
);
261 static int pa_solaris_auto_format ( int fd
, int mode
, pa_sample_spec
* ss
) {
264 AUDIO_INITINFO (& info
);
266 if ( mode
!= O_RDONLY
) {
267 info
. play
. sample_rate
= ss
-> rate
;
268 info
. play
. channels
= ss
-> channels
;
269 switch ( ss
-> format
) {
271 info
. play
. precision
= 8 ;
272 info
. play
. encoding
= AUDIO_ENCODING_LINEAR
;
275 info
. play
. precision
= 8 ;
276 info
. play
. encoding
= AUDIO_ENCODING_ALAW
;
279 info
. play
. precision
= 8 ;
280 info
. play
. encoding
= AUDIO_ENCODING_ULAW
;
282 case PA_SAMPLE_S16NE
:
283 info
. play
. precision
= 16 ;
284 info
. play
. encoding
= AUDIO_ENCODING_LINEAR
;
291 if ( mode
!= O_WRONLY
) {
292 info
. record
. sample_rate
= ss
-> rate
;
293 info
. record
. channels
= ss
-> channels
;
294 switch ( ss
-> format
) {
296 info
. record
. precision
= 8 ;
297 info
. record
. encoding
= AUDIO_ENCODING_LINEAR
;
300 info
. record
. precision
= 8 ;
301 info
. record
. encoding
= AUDIO_ENCODING_ALAW
;
304 info
. record
. precision
= 8 ;
305 info
. record
. encoding
= AUDIO_ENCODING_ULAW
;
307 case PA_SAMPLE_S16NE
:
308 info
. record
. precision
= 16 ;
309 info
. record
. encoding
= AUDIO_ENCODING_LINEAR
;
316 if ( ioctl ( fd
, AUDIO_SETINFO
, & info
) < 0 ) {
318 pa_log ( __FILE__
": AUDIO_SETINFO: Unsupported sample format. \n " );
320 pa_log ( __FILE__
": AUDIO_SETINFO: %s \n " , strerror ( errno
));
327 static int pa_solaris_set_buffer ( int fd
, int buffer_size
) {
330 AUDIO_INITINFO (& info
);
332 info
. record
. buffer_size
= buffer_size
;
334 if ( ioctl ( fd
, AUDIO_SETINFO
, & info
) < 0 ) {
336 pa_log ( __FILE__
": AUDIO_SETINFO: Unsupported buffer size. \n " );
338 pa_log ( __FILE__
": AUDIO_SETINFO: %s \n " , strerror ( errno
));
345 int pa__init ( pa_core
* c
, pa_module
* m
) {
346 struct userdata
* u
= NULL
;
351 int record
= 1 , playback
= 1 ;
353 pa_modargs
* ma
= NULL
;
356 if (!( ma
= pa_modargs_new ( m
-> argument
, valid_modargs
))) {
357 pa_log ( __FILE__
": failed to parse module arguments. \n " );
361 if ( pa_modargs_get_value_boolean ( ma
, "record" , & record
) < 0 || pa_modargs_get_value_boolean ( ma
, "playback" , & playback
) < 0 ) {
362 pa_log ( __FILE__
": record= and playback= expect numeric argument. \n " );
366 if (! playback
&& ! record
) {
367 pa_log ( __FILE__
": neither playback nor record enabled for device. \n " );
371 mode
= ( playback
&& record
) ? O_RDWR
: ( playback
? O_WRONLY
: ( record
? O_RDONLY
: 0 ));
374 if ( pa_modargs_get_value_s32 ( ma
, "buffer_size" , & buffer_size
) < 0 ) {
375 pa_log ( __FILE__
": failed to parse buffer size argument \n " );
379 ss
= c
-> default_sample_spec
;
380 if ( pa_modargs_get_sample_spec ( ma
, & ss
) < 0 ) {
381 pa_log ( __FILE__
": failed to parse sample specification \n " );
385 if (( fd
= open ( p
= pa_modargs_get_value ( ma
, "device" , DEFAULT_DEVICE
), mode
| O_NONBLOCK
)) < 0 )
388 pa_log_info ( __FILE__
": device opened in %s mode. \n " , mode
== O_WRONLY
? "O_WRONLY" : ( mode
== O_RDONLY
? "O_RDONLY" : "O_RDWR" ));
390 if ( pa_solaris_auto_format ( fd
, mode
, & ss
) < 0 )
393 if (( mode
!= O_WRONLY
) && ( buffer_size
>= 1 ))
394 if ( pa_solaris_set_buffer ( fd
, buffer_size
) < 0 )
397 u
= pa_xmalloc ( sizeof ( struct userdata
));
400 if ( mode
!= O_WRONLY
) {
401 u
-> source
= pa_source_new ( c
, __FILE__
, pa_modargs_get_value ( ma
, "source_name" , DEFAULT_SOURCE_NAME
), 0 , & ss
, NULL
);
403 u
-> source
-> userdata
= u
;
404 u
-> source
-> get_latency
= source_get_latency_cb
;
405 pa_source_set_owner ( u
-> source
, m
);
406 u
-> source
-> description
= pa_sprintf_malloc ( "Solaris PCM on '%s'" , p
);
410 if ( mode
!= O_RDONLY
) {
411 u
-> sink
= pa_sink_new ( c
, __FILE__
, pa_modargs_get_value ( ma
, "sink_name" , DEFAULT_SINK_NAME
), 0 , & ss
, NULL
);
413 u
-> sink
-> get_latency
= sink_get_latency_cb
;
414 u
-> sink
-> userdata
= u
;
415 pa_sink_set_owner ( u
-> sink
, m
);
416 u
-> sink
-> description
= pa_sprintf_malloc ( "Solaris PCM on '%s'" , p
);
420 assert ( u
-> source
|| u
-> sink
);
422 u
-> io
= pa_iochannel_new ( c
-> mainloop
, u
-> source
? fd
: - 1 , u
-> sink
? fd
: 0 );
424 pa_iochannel_set_callback ( u
-> io
, io_callback
, u
);
427 u
-> memchunk
. memblock
= NULL
;
428 u
-> memchunk
. length
= 0 ;
429 u
-> sample_size
= pa_frame_size (& ss
);
430 u
-> buffer_size
= buffer_size
;
432 u
-> silence
. memblock
= pa_memblock_new ( u
-> silence
. length
= CHUNK_SIZE
, u
-> core
-> memblock_stat
);
433 assert ( u
-> silence
. memblock
);
434 pa_silence_memblock ( u
-> silence
. memblock
, & ss
);
435 u
-> silence
. index
= 0 ;
437 u
-> written_bytes
= 0 ;
443 u
-> sig
= pa_signal_new ( SIGPOLL
, sig_callback
, u
);
445 ioctl ( u
-> fd
, I_SETSIG
, S_MSG
);
461 void pa__done ( pa_core
* c
, pa_module
* m
) {
465 if (!( u
= m
-> userdata
))
468 ioctl ( u
-> fd
, I_SETSIG
, 0 );
469 pa_signal_free ( u
-> sig
);
471 if ( u
-> memchunk
. memblock
)
472 pa_memblock_unref ( u
-> memchunk
. memblock
);
473 if ( u
-> silence
. memblock
)
474 pa_memblock_unref ( u
-> silence
. memblock
);
477 pa_sink_disconnect ( u
-> sink
);
478 pa_sink_unref ( u
-> sink
);
482 pa_source_disconnect ( u
-> source
);
483 pa_source_unref ( u
-> source
);
486 pa_iochannel_free ( u
-> io
);