summaryrefslogtreecommitdiff
path: root/esd-server.h
blob: 0d815ddc67886a6d9089069262a296c4cd3477c9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
#ifndef ESD_SERVER_H
#define ESD_SERVER_H

/* get public information from the public header file */
#include "esd.h"

#include "config.h"

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>

/*******************************************************************/
/* sound daemon data structures */

/* the ESD_*'s are defined from the lsb for client format info, */
/* from the msb for server side info. it should all fit into an int */

/* endianness of data */
#define ESD_MASK_END	( 0xF000000 )
#define ESD_ENDSAME	( 0x0000000 )
#define ESD_ENDDIFF	( 0x1000000 )

/* a client may be in one of several states */
enum esd_client_state {
    ESD_STREAMING_DATA,		/* data from here on is streamed data */
    ESD_CACHING_SAMPLE,		/* midway through caching a sample */
    ESD_NEEDS_REQDATA,		/* more data needed to complere request */
    ESD_NEXT_REQUEST,		/* proceed to next request */
    ESD_CLIENT_STATE_MAX	/* place holder */
};
typedef int esd_client_state_t;

/* mix functions control how the player data is combined */
typedef int (*mix_func_t)( void *player, int length );
typedef int (*translate_func_t)( void *dest_buf, int dest_len, 
				 int dest_rate, esd_format_t dest_format, 
				 void *source_data, int src_len, 
				 int src_rate, esd_format_t src_format );
/* NOTE: in heavy flux! */

/* a client is what contacts the server, and makes requests of daemon */
typedef struct esd_client {
    struct esd_client *next; 	/* it's a list, eh? link 'em */

    esd_client_state_t state;	/* which of above states are we in? */
  
    esd_proto_t request;	/* current request for this client */
    int fd;			/* the clients protocol stream */
#if defined(ENABLE_IPV6)
    struct sockaddr_in6 source6;
#endif
    struct sockaddr_in source;	/* data maintained about source */

    int swap_byte_order;	/* for big/little endian compatibility */
    octet proto_data[ 1024 ];	/* hold the protocol request data */
    int proto_data_length;	/* how much request data we have */
} esd_client_t;

/* a player is what produces data for a sound */
typedef struct esd_player {
    struct esd_player *next;	/* point to next player in list */
    void *parent;		/* client or sample that spawned player */

    esd_format_t format;	/* magic int with the format info */
    int rate;			/* sample rate */
    int left_vol_scale;		/* volume scaling */
    int right_vol_scale;

    int source_id;		/* either a stream fd or sample id */
    octet *data_buffer;		/* buffer to hold sound data */
    int buffer_length;		/* total buffer length */
    int actual_length;		/* actual length of data in buffer */

    /* time_t last_read; */	/* timeout for streams, not used */
    int last_pos;		/* track read position for samples */
    char name[ ESD_NAME_MAX ];	/* name of stream for remote control */

    mix_func_t mix_func;	/* mixes data into the combined buffer */
    translate_func_t translate_func;	/* copies data between players */
} esd_player_t;

/* TODO?: typedef esd_player_t esd_recorder_t, and monitor? */

/* a sample is a pre-cached sound, played by sample_id */
typedef struct esd_sample {
    struct esd_sample *next;	/* point to next sample in list */
    struct esd_client *parent;	/* the client that spawned sample */

    esd_format_t format;	/* magic int with the format info */
    int rate;			/* sample rate */
    int left_vol_scale;		/* volume scaling */
    int right_vol_scale;

    int sample_id;		/* the sample's id number */
    octet *data_buffer;		/* buffer to hold sound data */
    int sample_length;		/* total buffer length */

    int cached_length;		/* amount of data cached so far */
    int ref_count;		/* track players for clean deletion */
    int erase_when_done;	/* track uncache requests */
    char name[ ESD_NAME_MAX ];	/* name of sample for remote control */
} esd_sample_t;

/*******************************************************************/
/* server function prototypes */

/* esd.c - global variables */
extern int esd_is_owned;
extern int esd_is_locked;
extern char esd_owner_key[ESD_KEY_LEN];

extern int esd_on_standby;
extern int esd_pending_driver_reconnect;
extern int esdbg_trace;
extern int esdbg_comms;
extern int esdbg_mixer;

extern int esd_buf_size_octets;
extern int esd_buf_size_samples;
extern int esd_sample_size;

extern int esd_autostandby_secs;
extern time_t esd_last_activity;
extern int esd_on_autostandby;

int esd_server_standby(void);
int esd_server_resume(void);

/* clients.c - manage the client connections */
extern esd_client_t *esd_clients_list;
void dump_clients(void);
void add_new_client( esd_client_t *new_client );
void erase_client( esd_client_t *client );

int get_new_clients( int listen );
int wait_for_clients_and_data( int listen );
void esd_comm_loop( int listen_socket, void *output_buffer, int esd_terminate );

/* filter.c - things with which to handle filters */
extern esd_player_t *esd_filter_list;
extern translate_func_t esd_first_filter_func;

void erase_filter( esd_player_t *filter );

/* proto.c - deal with client protocol requests */
extern int esd_forced_standby;

int poll_client_requests(void);

/* players.c - manage the players, recorder, and monitor */
extern esd_player_t *esd_players_list;
extern esd_player_t *esd_recorder_list;
extern esd_player_t *esd_monitor_list;

void dump_players(void);
void add_player( esd_player_t *player );
void erase_player( esd_player_t *player );
void free_player( esd_player_t *player );
void erase_monitor( esd_player_t *monitor );
void add_recorder( esd_player_t *recorder );
void erase_recorder( esd_player_t *recorder );

esd_player_t *new_stream_player( esd_client_t *client );
esd_player_t *new_sample_player( int id, int loop );

int write_player( esd_player_t *player, void *src_buffer, int src_length, 
		  int src_rate, int src_format );
int read_player( esd_player_t *player );
int recorder_write( void *buffer, int length );
void monitor_write( void *output_buffer, int length );

/* samples.c - manage the players, recorder, and monitor */
extern esd_sample_t *esd_samples_list;
extern int esd_playing_samples;
extern int esd_next_sample_id;

void dump_samples(void);
void add_sample( esd_sample_t *sample );
void erase_sample( int id, int force );
esd_sample_t *new_sample( esd_client_t *client );
esd_sample_t *find_caching_sample( esd_client_t *client );
int read_sample( esd_sample_t *sample );
int play_sample( int sample_id, int loop );
int stop_sample( int sample_id );

/* mix.c - deal with mixing signals, and format conversion */
mix_func_t get_mix_func( esd_player_t *player );
translate_func_t get_translate_func( esd_format_t src_fmt, int src_rate,
				     esd_format_t dst_fmt, int dst_rate );

int refresh_mix_funcs();
int mix_players( void *mixed, int length );

/*******************************************************************/
/* filter.c */
int filter_write( void *buffer, int size, esd_format_t format, int rate );

/*******************************************************************/
/* esdlib.c */
int esd_set_socket_buffers( int sock, int src_format, 
			    int src_rate, int base_rate );

/* audio.c */
int esound_getblksize(void);

/*******************************************************************/
/* evil evil macros */

/* switch endian order for cross platform playing */
#define swap_endian_16(x) ( ( (x) >> 8 ) | ( ((x)&0xFF) << 8 ) )
#define swap_endian_32(x) \
	( ( (x) >> 24 ) | ( ((x)&0xFF0000) >> 8 ) | \
	  ( ((x)&0xFF00) << 8 ) | ( ((x)&0xFF) << 24 ) )

/* the endian key is transferred in binary, if it's read into int, */
/* and matches ESD_ENDIAN_KEY (ENDN), then the endianness of the */
/* server and the client match; if it's SWAP_ENDIAN_KEY, swap data */
#define ESD_SWAP_ENDIAN_KEY swap_endian_32(ESD_ENDIAN_KEY)
#define maybe_swap_32(c,x) \
	( (c) ? (swap_endian_32( (x) )) : (x) )

#define ESD_DEFAULT_AUTOSTANDBY_SECS 5

/* evil macros for debugging protocol */

#ifdef ESDBG /* expand debug macros to yield diagnostic information */

#define ESDBG_TRACE(x) \
	do { \
	    if ( esdbg_trace ) { \
		printf( ":trace: [%12s,%5d] \t", __FILE__, __LINE__ ); \
    		x; \
	    } \
	} while( 0 );

#define ESDBG_COMMS(x) \
	do { \
	    if ( esdbg_comms ) { \
		printf( ":comms: [%12s,%5d] \t", __FILE__, __LINE__ ); \
    		x; \
	    } \
	} while( 0 );

#define ESDBG_MIXER(x) \
	do { \
	    if ( esdbg_mixer ) { \
		printf( "+mixer+ [%12s,%5d] \t", __FILE__, __LINE__ ); \
    		x; \
	    } \
	} while( 0 );

#define ESD_READ_INT(s,a,l,r,d) \
	do { \
	    unsigned int esd_ri; \
    	    r = read( s, a, l ); \
    	    if ( esdbg_comms ) { \
		printf( "---> rd [%12s,%5d] \t%-10s: %2d, %4d = %4d  (%d)     (", \
			__FILE__, __LINE__, d, s, l, r, *a ); \
    		for ( esd_ri = 0 ; esd_ri < sizeof(int) ; esd_ri++ ) \
    		    printf( "0x%02x ", *(((octet*)a)+esd_ri) ); \
		printf( ")\n" ); \
	    } \
        } while ( 0 );

#define ESD_READ_BIN(s,a,l,r,d) \
	do { \
	    unsigned int esd_rb; \
    	    r = read( s, a, l ); \
    	    if ( esdbg_comms ) { \
		printf( "---> rd [%12s,%5d] \t%-10s: %2d, %4d = %4d  (", \
			__FILE__, __LINE__, d, s, l, r ); \
    		for ( esd_rb = 0 ; esd_rb < 8 ; esd_rb++ ) \
    		    printf( "0x%02x ", *(((octet*)a)+esd_rb) ); \
		printf( "...)\n" ); \
	    } \
        } while ( 0 );

#define ESD_WRITE_INT(s,a,l,r,d) \
	do { \
	    unsigned int esd_wi; \
    	    r = write( s, a, l ); \
    	    if ( esdbg_comms ) { \
		printf( "<--- wr [%12s,%5d] \t%-10s: %2d, %4d = %4d  (%d)     (", \
			__FILE__, __LINE__, d, s, l, r, *a ); \
    		for ( esd_wi = 0 ; esd_wi < sizeof(int) ; esd_wi++ ) \
    		    printf( "0x%02x ", *(((octet*)a)+esd_wi) ); \
		printf( ")\n" ); \
	    } \
        } while ( 0 );

#define ESD_WRITE_BIN(s,a,l,r,d) \
	do { \
	    unsigned int esd_wb; \
    	    r = write( s, a, l ); \
    	    if ( esdbg_comms ) { \
		printf( "<--- wr [%12s,%5d] \t%-10s: %2d, %4d = %4d  (", \
			__FILE__, __LINE__, d, s, l, r ); \
    		for ( esd_wb = 0 ; esd_wb < 8 ; esd_wb++ ) \
    		    printf( "0x%02X ", *(((octet*)a)+esd_wb) ); \
		printf( "...)\n" ); \
	    } \
        } while ( 0 );

#else /* #ifdef ESDBG */ /* expand debug macros to simply do, and not say */

#define ESDBG_TRACE(x)
#define ESDBG_COMMS(x)
#define ESDBG_MIXER(x)

#define ESD_READ_INT(s,a,l,r,d)	 r = read( s, a, l );
#define ESD_READ_BIN(s,a,l,r,d)  r = read( s, a, l );
#define ESD_WRITE_INT(s,a,l,r,d) r = write( s, a, l );
#define ESD_WRITE_BIN(s,a,l,r,d) r = write( s, a, l );

#endif /* #ifdef ESDBG */

/* MkLinux on the PowerMac is weird because it is a big-endian processor,
   but it uses little-endian sound streams */
/* TODO: beef up mix.c, and add function pointers for the basic functions */
#ifdef DRIVER_MKLINUX
#define MAYBE_SWAP_FOR_MK(x) ( (((x)&0xFF00)>>8) | (((x)&0x00FF)<<8) )
#else
#define MAYBE_SWAP_FOR_MK(x) (x)
#endif  

#endif /* #ifndef ESD_SERVER_H */