]>
code.delx.au - pulseaudio/blob - polyp/module-solaris.c
f85e71dfb20b9a5a9362074f155ad2e351875855
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 "iochannel.h"
47 #include "sample-util.h"
52 #include "mainloop-signal.h"
53 #include "module-solaris-symdef.h"
55 PA_MODULE_AUTHOR ( "Pierre Ossman" )
56 PA_MODULE_DESCRIPTION ( "Solaris Sink/Source" )
57 PA_MODULE_VERSION ( PACKAGE_VERSION
)
58 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>" )
67 pa_memchunk memchunk
, silence
;
71 unsigned int written_bytes
, read_bytes
;
77 static const char * const valid_modargs
[] = {
90 #define DEFAULT_SINK_NAME "solaris_output"
91 #define DEFAULT_SOURCE_NAME "solaris_input"
92 #define DEFAULT_DEVICE "/dev/audio"
94 #define CHUNK_SIZE 2048
96 static void update_usage ( struct userdata
* u
) {
97 pa_module_set_used ( u
-> module
,
98 ( u
-> sink
? pa_idxset_size ( u
-> sink
-> inputs
) : 0 ) +
99 ( u
-> sink
? pa_idxset_size ( u
-> sink
-> monitor_source
-> outputs
) : 0 ) +
100 ( u
-> source
? pa_idxset_size ( u
-> source
-> outputs
) : 0 ));
103 static void do_write ( struct userdata
* u
) {
106 pa_memchunk
* memchunk
;
112 if (! u
-> sink
|| ! pa_iochannel_is_writable ( u
-> io
))
117 err
= ioctl ( u
-> fd
, AUDIO_GETINFO
, & info
);
121 * Since we cannot modify the size of the output buffer we fake it
122 * by not filling it more than u->buffer_size.
124 len
= u
-> buffer_size
;
125 len
-= u
-> written_bytes
- ( info
. play
. samples
* u
-> sample_size
);
128 * Do not fill more than half the buffer in one chunk since we only
129 * get notifications upon completion of entire chunks.
131 if ( len
> ( u
-> buffer_size
/ 2 ))
132 len
= u
-> buffer_size
/ 2 ;
134 if ( len
< u
-> sample_size
)
137 memchunk
= & u
-> memchunk
;
139 if (! memchunk
-> length
)
140 if ( pa_sink_render ( u
-> sink
, len
, memchunk
) < 0 )
141 memchunk
= & u
-> silence
;
143 assert ( memchunk
-> memblock
);
144 assert ( memchunk
-> memblock
-> data
);
145 assert ( memchunk
-> length
);
147 if ( memchunk
-> length
< len
)
148 len
= memchunk
-> length
;
150 if (( r
= pa_iochannel_write ( u
-> io
, ( uint8_t *) memchunk
-> memblock
-> data
+ memchunk
-> index
, len
)) < 0 ) {
151 pa_log ( __FILE__
": write() failed: %s \n " , strerror ( errno
));
155 if ( memchunk
== & u
-> silence
)
156 assert ( r
% u
-> sample_size
== 0 );
158 u
-> memchunk
. index
+= r
;
159 u
-> memchunk
. length
-= r
;
161 if ( u
-> memchunk
. length
<= 0 ) {
162 pa_memblock_unref ( u
-> memchunk
. memblock
);
163 u
-> memchunk
. memblock
= NULL
;
167 u
-> written_bytes
+= r
;
170 * Write 0 bytes which will generate a SIGPOLL when "played".
172 if ( write ( u
-> fd
, NULL
, 0 ) < 0 ) {
173 pa_log ( __FILE__
": write() failed: %s \n " , strerror ( errno
));
178 static void do_read ( struct userdata
* u
) {
179 pa_memchunk memchunk
;
184 if (! u
-> source
|| ! pa_iochannel_is_readable ( u
-> io
))
189 err
= ioctl ( u
-> fd
, I_NREAD
, & l
);
192 memchunk
. memblock
= pa_memblock_new ( l
, u
-> core
-> memblock_stat
);
193 assert ( memchunk
. memblock
);
194 if (( r
= pa_iochannel_read ( u
-> io
, memchunk
. memblock
-> data
, memchunk
. memblock
-> length
)) < 0 ) {
195 pa_memblock_unref ( memchunk
. memblock
);
197 pa_log ( __FILE__
": read() failed: %s \n " , strerror ( errno
));
201 assert ( r
<= ( ssize_t
) memchunk
. memblock
-> length
);
202 memchunk
. length
= memchunk
. memblock
-> length
= r
;
205 pa_source_post ( u
-> source
, & memchunk
);
206 pa_memblock_unref ( memchunk
. memblock
);
211 static void io_callback ( pa_iochannel
* io
, void * userdata
) {
212 struct userdata
* u
= userdata
;
218 void sig_callback ( pa_mainloop_api
* api
, pa_signal_event
* e
, int sig
, void * userdata
) {
219 struct userdata
* u
= userdata
;
224 static pa_usec_t
sink_get_latency_cb ( pa_sink
* s
) {
228 struct userdata
* u
= s
-> userdata
;
229 assert ( s
&& u
&& u
-> sink
);
231 err
= ioctl ( u
-> fd
, AUDIO_GETINFO
, & info
);
234 r
+= pa_bytes_to_usec ( u
-> written_bytes
, & s
-> sample_spec
);
235 r
-= pa_bytes_to_usec ( info
. play
. samples
* u
-> sample_size
, & s
-> sample_spec
);
237 if ( u
-> memchunk
. memblock
)
238 r
+= pa_bytes_to_usec ( u
-> memchunk
. length
, & s
-> sample_spec
);
243 static pa_usec_t
source_get_latency_cb ( pa_source
* s
) {
245 struct userdata
* u
= s
-> userdata
;
248 assert ( s
&& u
&& u
-> source
);
250 err
= ioctl ( u
-> fd
, AUDIO_GETINFO
, & info
);
253 r
+= pa_bytes_to_usec ( info
. record
. samples
* u
-> sample_size
, & s
-> sample_spec
);
254 r
-= pa_bytes_to_usec ( u
-> read_bytes
, & s
-> sample_spec
);
259 static int pa_solaris_auto_format ( int fd
, int mode
, pa_sample_spec
* ss
) {
262 AUDIO_INITINFO (& info
);
264 if ( mode
!= O_RDONLY
) {
265 info
. play
. sample_rate
= ss
-> rate
;
266 info
. play
. channels
= ss
-> channels
;
267 switch ( ss
-> format
) {
269 info
. play
. precision
= 8 ;
270 info
. play
. encoding
= AUDIO_ENCODING_LINEAR
;
273 info
. play
. precision
= 8 ;
274 info
. play
. encoding
= AUDIO_ENCODING_ALAW
;
277 info
. play
. precision
= 8 ;
278 info
. play
. encoding
= AUDIO_ENCODING_ULAW
;
280 case PA_SAMPLE_S16NE
:
281 info
. play
. precision
= 16 ;
282 info
. play
. encoding
= AUDIO_ENCODING_LINEAR
;
289 if ( mode
!= O_WRONLY
) {
290 info
. record
. sample_rate
= ss
-> rate
;
291 info
. record
. channels
= ss
-> channels
;
292 switch ( ss
-> format
) {
294 info
. record
. precision
= 8 ;
295 info
. record
. encoding
= AUDIO_ENCODING_LINEAR
;
298 info
. record
. precision
= 8 ;
299 info
. record
. encoding
= AUDIO_ENCODING_ALAW
;
302 info
. record
. precision
= 8 ;
303 info
. record
. encoding
= AUDIO_ENCODING_ULAW
;
305 case PA_SAMPLE_S16NE
:
306 info
. record
. precision
= 16 ;
307 info
. record
. encoding
= AUDIO_ENCODING_LINEAR
;
314 if ( ioctl ( fd
, AUDIO_SETINFO
, & info
) < 0 ) {
316 pa_log ( __FILE__
": AUDIO_SETINFO: Unsupported sample format. \n " );
318 pa_log ( __FILE__
": AUDIO_SETINFO: %s \n " , strerror ( errno
));
325 static int pa_solaris_set_buffer ( int fd
, int buffer_size
) {
328 AUDIO_INITINFO (& info
);
330 info
. record
. buffer_size
= buffer_size
;
332 if ( ioctl ( fd
, AUDIO_SETINFO
, & info
) < 0 ) {
334 pa_log ( __FILE__
": AUDIO_SETINFO: Unsupported buffer size. \n " );
336 pa_log ( __FILE__
": AUDIO_SETINFO: %s \n " , strerror ( errno
));
343 int pa__init ( pa_core
* c
, pa_module
* m
) {
344 struct userdata
* u
= NULL
;
349 int record
= 1 , playback
= 1 ;
351 pa_modargs
* ma
= NULL
;
354 if (!( ma
= pa_modargs_new ( m
-> argument
, valid_modargs
))) {
355 pa_log ( __FILE__
": failed to parse module arguments. \n " );
359 if ( pa_modargs_get_value_boolean ( ma
, "record" , & record
) < 0 || pa_modargs_get_value_boolean ( ma
, "playback" , & playback
) < 0 ) {
360 pa_log ( __FILE__
": record= and playback= expect numeric argument. \n " );
364 if (! playback
&& ! record
) {
365 pa_log ( __FILE__
": neither playback nor record enabled for device. \n " );
369 mode
= ( playback
&& record
) ? O_RDWR
: ( playback
? O_WRONLY
: ( record
? O_RDONLY
: 0 ));
372 if ( pa_modargs_get_value_s32 ( ma
, "buffer_size" , & buffer_size
) < 0 ) {
373 pa_log ( __FILE__
": failed to parse buffer size argument \n " );
377 ss
= c
-> default_sample_spec
;
378 if ( pa_modargs_get_sample_spec ( ma
, & ss
) < 0 ) {
379 pa_log ( __FILE__
": failed to parse sample specification \n " );
383 if (( fd
= open ( p
= pa_modargs_get_value ( ma
, "device" , DEFAULT_DEVICE
), mode
| O_NONBLOCK
)) < 0 )
386 pa_log_info ( __FILE__
": device opened in %s mode. \n " , mode
== O_WRONLY
? "O_WRONLY" : ( mode
== O_RDONLY
? "O_RDONLY" : "O_RDWR" ));
388 if ( pa_solaris_auto_format ( fd
, mode
, & ss
) < 0 )
391 if (( mode
!= O_WRONLY
) && ( buffer_size
>= 1 ))
392 if ( pa_solaris_set_buffer ( fd
, buffer_size
) < 0 )
395 u
= pa_xmalloc ( sizeof ( struct userdata
));
398 if ( mode
!= O_WRONLY
) {
399 u
-> source
= pa_source_new ( c
, __FILE__
, pa_modargs_get_value ( ma
, "source_name" , DEFAULT_SOURCE_NAME
), 0 , & ss
, NULL
);
401 u
-> source
-> userdata
= u
;
402 u
-> source
-> get_latency
= source_get_latency_cb
;
403 pa_source_set_owner ( u
-> source
, m
);
404 u
-> source
-> description
= pa_sprintf_malloc ( "Solaris PCM on '%s'" , p
);
408 if ( mode
!= O_RDONLY
) {
409 u
-> sink
= pa_sink_new ( c
, __FILE__
, pa_modargs_get_value ( ma
, "sink_name" , DEFAULT_SINK_NAME
), 0 , & ss
, NULL
);
411 u
-> sink
-> get_latency
= sink_get_latency_cb
;
412 u
-> sink
-> userdata
= u
;
413 pa_sink_set_owner ( u
-> sink
, m
);
414 u
-> sink
-> description
= pa_sprintf_malloc ( "Solaris PCM on '%s'" , p
);
418 assert ( u
-> source
|| u
-> sink
);
420 u
-> io
= pa_iochannel_new ( c
-> mainloop
, u
-> source
? fd
: - 1 , u
-> sink
? fd
: 0 );
422 pa_iochannel_set_callback ( u
-> io
, io_callback
, u
);
425 u
-> memchunk
. memblock
= NULL
;
426 u
-> memchunk
. length
= 0 ;
427 u
-> sample_size
= pa_frame_size (& ss
);
428 u
-> buffer_size
= buffer_size
;
430 u
-> silence
. memblock
= pa_memblock_new ( u
-> silence
. length
= CHUNK_SIZE
, u
-> core
-> memblock_stat
);
431 assert ( u
-> silence
. memblock
);
432 pa_silence_memblock ( u
-> silence
. memblock
, & ss
);
433 u
-> silence
. index
= 0 ;
435 u
-> written_bytes
= 0 ;
441 u
-> sig
= pa_signal_new ( SIGPOLL
, sig_callback
, u
);
443 ioctl ( u
-> fd
, I_SETSIG
, S_MSG
);
459 void pa__done ( pa_core
* c
, pa_module
* m
) {
463 if (!( u
= m
-> userdata
))
466 ioctl ( u
-> fd
, I_SETSIG
, 0 );
467 pa_signal_free ( u
-> sig
);
469 if ( u
-> memchunk
. memblock
)
470 pa_memblock_unref ( u
-> memchunk
. memblock
);
471 if ( u
-> silence
. memblock
)
472 pa_memblock_unref ( u
-> silence
. memblock
);
475 pa_sink_disconnect ( u
-> sink
);
476 pa_sink_unref ( u
-> sink
);
480 pa_source_disconnect ( u
-> source
);
481 pa_source_unref ( u
-> source
);
484 pa_iochannel_free ( u
-> io
);