]>
code.delx.au - pulseaudio/blob - polyp/module-esound-sink.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
36 #include "iochannel.h"
43 #include "module-esound-sink-symdef.h"
44 #include "socket-client.h"
48 PA_MODULE_AUTHOR ( "Lennart Poettering" )
49 PA_MODULE_DESCRIPTION ( "Esound " )
50 PA_MODULE_VERSION ( PACKAGE_VERSION
)
51 PA_MODULE_USAGE ( "sink_name=<name for the sink> server=<address> cookie=<filename> format=<sample format> channels=<number of channels> rate=<sample rate>" )
53 #define DEFAULT_SINK_NAME "esound_output"
55 #define PA_TYPEID_ESOUND_SINK PA_TYPEID_MAKE( 'E' , 'S' , 'D' , 'S' )
61 struct pa_iochannel
* io
;
62 struct pa_socket_client
* client
;
64 struct pa_defer_event
* defer_event
;
66 struct pa_memchunk memchunk
;
67 struct pa_module
* module
;
70 size_t write_length
, write_index
;
73 size_t read_length
, read_index
;
75 enum { STATE_AUTH
, STATE_LATENCY
, STATE_RUNNING
, STATE_DEAD
} state
;
83 static const char * const valid_modargs
[] = {
93 static void cancel ( struct userdata
* u
) {
96 u
-> state
= STATE_DEAD
;
99 pa_iochannel_free ( u
-> io
);
103 if ( u
-> defer_event
) {
104 u
-> core
-> mainloop
-> defer_free ( u
-> defer_event
);
105 u
-> defer_event
= NULL
;
109 pa_sink_disconnect ( u
-> sink
);
110 pa_sink_unref ( u
-> sink
);
115 pa_module_unload_request ( u
-> module
);
120 static int do_write ( struct userdata
* u
) {
124 if (! pa_iochannel_is_writable ( u
-> io
))
128 assert ( u
-> write_index
< u
-> write_length
);
130 if (( r
= pa_iochannel_write ( u
-> io
, ( uint8_t *) u
-> write_data
+ u
-> write_index
, u
-> write_length
- u
-> write_index
)) <= 0 ) {
131 pa_log ( __FILE__
": write() failed: %s \n " , strerror ( errno
));
136 assert ( u
-> write_index
<= u
-> write_length
);
138 if ( u
-> write_index
== u
-> write_length
) {
140 u
-> write_data
= NULL
;
141 u
-> write_index
= u
-> write_length
= 0 ;
143 } else if ( u
-> state
== STATE_RUNNING
) {
144 pa_module_set_used ( u
-> module
, pa_idxset_ncontents ( u
-> sink
-> inputs
) + pa_idxset_ncontents ( u
-> sink
-> monitor_source
-> outputs
));
146 if (! u
-> memchunk
. length
)
147 if ( pa_sink_render ( u
-> sink
, PIPE_BUF
, & u
-> memchunk
) < 0 )
150 assert ( u
-> memchunk
. memblock
&& u
-> memchunk
. length
);
152 if (( r
= pa_iochannel_write ( u
-> io
, ( uint8_t *) u
-> memchunk
. memblock
-> data
+ u
-> memchunk
. index
, u
-> memchunk
. length
)) < 0 ) {
153 pa_log ( __FILE__
": write() failed: %s \n " , strerror ( errno
));
157 u
-> memchunk
. index
+= r
;
158 u
-> memchunk
. length
-= r
;
160 if ( u
-> memchunk
. length
<= 0 ) {
161 pa_memblock_unref ( u
-> memchunk
. memblock
);
162 u
-> memchunk
. memblock
= NULL
;
169 static int handle_response ( struct userdata
* u
) {
174 assert ( u
-> read_length
== sizeof ( int32_t ));
176 /* Process auth data */
177 if (!*( int32_t *) u
-> read_data
) {
178 pa_log ( __FILE__
": Authentication failed: %s \n " , strerror ( errno
));
182 /* Request latency data */
183 assert (! u
-> write_data
);
184 *( int32_t *) ( u
-> write_data
= pa_xmalloc ( u
-> write_length
= sizeof ( int32_t ))) = ESD_PROTO_LATENCY
;
187 u
-> state
= STATE_LATENCY
;
189 /* Space for next response */
190 assert ( u
-> read_length
>= sizeof ( int32_t ));
192 u
-> read_length
= sizeof ( int32_t );
196 case STATE_LATENCY
: {
198 assert ( u
-> read_length
== sizeof ( int32_t ));
200 /* Process latency info */
201 u
-> latency
= ( pa_usec_t
) (( double ) (*( int32_t *) u
-> read_data
) * 1000000 / 44100 );
202 if ( u
-> latency
> 10000000 ) {
203 pa_log ( __FILE__
": WARNING! Invalid latency information received from server \n " );
208 assert (! u
-> write_data
);
209 p
= u
-> write_data
= pa_xmalloc0 ( u
-> write_length
= sizeof ( int32_t )* 3 + ESD_NAME_MAX
);
210 *( p
++) = ESD_PROTO_STREAM_PLAY
;
213 pa_strlcpy (( char *) p
, "Polypaudio Tunnel" , ESD_NAME_MAX
);
216 u
-> state
= STATE_RUNNING
;
218 /* Don't read any further */
219 pa_xfree ( u
-> read_data
);
221 u
-> read_index
= u
-> read_length
= 0 ;
233 static int do_read ( struct userdata
* u
) {
236 if (! pa_iochannel_is_readable ( u
-> io
))
239 if ( u
-> state
== STATE_AUTH
|| u
-> state
== STATE_LATENCY
) {
245 assert ( u
-> read_index
< u
-> read_length
);
247 if (( r
= pa_iochannel_read ( u
-> io
, ( uint8_t *) u
-> read_data
+ u
-> read_index
, u
-> read_length
- u
-> read_index
)) <= 0 ) {
248 pa_log ( __FILE__
": read() failed: %s \n " , r
< 0 ? strerror ( errno
) : "EOF" );
254 assert ( u
-> read_index
<= u
-> read_length
);
256 if ( u
-> read_index
== u
-> read_length
)
257 return handle_response ( u
);
263 static void do_work ( struct userdata
* u
) {
266 u
-> core
-> mainloop
-> defer_enable ( u
-> defer_event
, 0 );
268 if ( do_read ( u
) < 0 || do_write ( u
) < 0 )
272 static void notify_cb ( struct pa_sink
* s
) {
273 struct userdata
* u
= s
-> userdata
;
276 if ( pa_iochannel_is_writable ( u
-> io
))
277 u
-> core
-> mainloop
-> defer_enable ( u
-> defer_event
, 1 );
280 static pa_usec_t
get_latency_cb ( struct pa_sink
* s
) {
281 struct userdata
* u
= s
-> userdata
;
286 ( u
-> memchunk
. memblock
? pa_bytes_to_usec ( u
-> memchunk
. length
, & s
-> sample_spec
) : 0 );
289 static void defer_callback ( struct pa_mainloop_api
* m
, struct pa_defer_event
* e
, void * userdata
) {
290 struct userdata
* u
= userdata
;
295 static void io_callback ( struct pa_iochannel
* io
, void * userdata
) {
296 struct userdata
* u
= userdata
;
301 static void on_connection ( struct pa_socket_client
* c
, struct pa_iochannel
* io
, void * userdata
) {
302 struct userdata
* u
= userdata
;
304 pa_socket_client_unref ( u
-> client
);
308 pa_log ( __FILE__
": connection failed: %s \n " , strerror ( errno
));
314 pa_iochannel_set_callback ( u
-> io
, io_callback
, u
);
317 int pa__init ( struct pa_core
* c
, struct pa_module
* m
) {
318 struct userdata
* u
= NULL
;
320 struct pa_sample_spec ss
;
321 struct pa_modargs
* ma
= NULL
;
324 if (!( ma
= pa_modargs_new ( m
-> argument
, valid_modargs
))) {
325 pa_log ( __FILE__
": failed to parse module arguments \n " );
329 ss
= c
-> default_sample_spec
;
330 if ( pa_modargs_get_sample_spec ( ma
, & ss
) < 0 ) {
331 pa_log ( __FILE__
": invalid sample format specification \n " );
335 if (( ss
. format
!= PA_SAMPLE_U8
&& ss
. format
!= PA_SAMPLE_S16NE
) ||
337 pa_log ( __FILE__
": esound sample type support is limited to mono/stereo and U8 or S16NE sample data \n " );
341 u
= pa_xmalloc0 ( sizeof ( struct userdata
));
346 ( ss
. format
== PA_SAMPLE_U8
? ESD_BITS8
: ESD_BITS16
) |
347 ( ss
. channels
== 2 ? ESD_STEREO
: ESD_MONO
);
352 u
-> read_data
= u
-> write_data
= NULL
;
353 u
-> read_index
= u
-> write_index
= u
-> read_length
= u
-> write_length
= 0 ;
354 u
-> state
= STATE_AUTH
;
357 if (!( u
-> sink
= pa_sink_new ( c
, PA_TYPEID_ESOUND_SINK
, pa_modargs_get_value ( ma
, "sink_name" , DEFAULT_SINK_NAME
), 0 , & ss
))) {
358 pa_log ( __FILE__
": failed to create sink. \n " );
362 if (!( u
-> client
= pa_socket_client_new_string ( u
-> core
-> mainloop
, p
= pa_modargs_get_value ( ma
, "server" , ESD_UNIX_SOCKET_NAME
), ESD_DEFAULT_PORT
))) {
363 pa_log ( __FILE__
": failed to connect to server. \n " );
366 pa_socket_client_set_callback ( u
-> client
, on_connection
, u
);
368 /* Prepare the initial request */
369 u
-> write_data
= pa_xmalloc ( u
-> write_length
= ESD_KEY_LEN
+ sizeof ( int32_t ));
370 if ( pa_authkey_load_auto ( pa_modargs_get_value ( ma
, "cookie" , ".esd_auth" ), u
-> write_data
, ESD_KEY_LEN
) < 0 ) {
371 pa_log ( __FILE__
": failed to load cookie \n " );
374 *( int32_t *) (( uint8_t *) u
-> write_data
+ ESD_KEY_LEN
) = ESD_ENDIAN_KEY
;
376 /* Reserve space for the response */
377 u
-> read_data
= pa_xmalloc ( u
-> read_length
= sizeof ( int32_t ));
379 u
-> sink
-> notify
= notify_cb
;
380 u
-> sink
-> get_latency
= get_latency_cb
;
381 u
-> sink
-> userdata
= u
;
382 pa_sink_set_owner ( u
-> sink
, m
);
383 u
-> sink
-> description
= pa_sprintf_malloc ( "Esound sink '%s'" , p
);
385 u
-> memchunk
. memblock
= NULL
;
386 u
-> memchunk
. length
= 0 ;
388 u
-> defer_event
= c
-> mainloop
-> defer_new ( c
-> mainloop
, defer_callback
, u
);
389 c
-> mainloop
-> defer_enable ( u
-> defer_event
, 0 );
405 void pa__done ( struct pa_core
* c
, struct pa_module
* m
) {
409 if (!( u
= m
-> userdata
))
415 if ( u
-> memchunk
. memblock
)
416 pa_memblock_unref ( u
-> memchunk
. memblock
);
419 pa_socket_client_unref ( u
-> client
);
421 pa_xfree ( u
-> read_data
);
422 pa_xfree ( u
-> write_data
);