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
|
#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 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 );
/*******************************************************************/
/* 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 */
|