📄 esdlib.c
字号:
#include "config.h"
#include "esd.h"
#include <stdio.h>
#include <stdlib.h>
//#include <unistd.h>
//#include <dirent.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <time.h>
#include <string.h>
//#include <netdb.h>
#include <sys/types.h>
//#include <socket.h>
//#include <netinet/in.h>
//#include <arpa/inet.h>
#include <winsock2.h>
/*******************************************************************/
/* prototypes */
int esd_set_socket_buffers( int sock, int src_format,
int src_rate, int base_rate );
/*******************************************************************/
/* alternate implementations */
#ifndef HAVE_INET_ATON
int inet_aton(const char *cp, struct in_addr *inp)
{
union {
unsigned int n;
char parts[4];
} u;
int a=0,b=0,c=0,d=0, i;
i = sscanf(cp, "%d.%d.%d.%d%*s", &a, &b, &c, &d);
if(i != 4)
return 0;
u.parts[0] = a;
u.parts[1] = b;
u.parts[2] = c;
u.parts[3] = d;
inp->s_addr = u.n;
return 1;
}
#endif
/*******************************************************************/
/* set socket buffer lengths to optimal length for audio data transfer */
int esd_set_socket_buffers( int sock, int src_format,
int src_rate, int base_rate )
{
int buf_size = ESD_BUF_SIZE;
if ( src_rate > 0 ) buf_size = ( buf_size * base_rate ) / src_rate;
if ( ( src_format & ESD_MASK_BITS ) == ESD_BITS16 )
buf_size *= 2;
if ( ! ( ( src_format & ESD_MASK_CHAN ) == ESD_MONO ) )
buf_size *= 2;
setsockopt( sock, SOL_SOCKET, SO_SNDBUF, &buf_size, sizeof( buf_size ) );
setsockopt( sock, SOL_SOCKET, SO_RCVBUF, &buf_size, sizeof( buf_size ) );
return buf_size;
}
/*******************************************************************/
/* send the authorization cookie, create one if needed */
int esd_send_auth( int sock )
{
int auth_fd = -1, i = 0;
int endian = ESD_ENDIAN_KEY;
char *auth_filename = 0, auth_key[ESD_KEY_LEN];
char *home = NULL;
char tumbler = '\0';
int namelen, retval;
/* assemble the authorization filename */
home = getenv( "HOME" );
if ( !home ) {
fprintf( stderr, "HOME environment variable not set?\n" );
return -1;
}
namelen = strlen(home) + sizeof("/.esd_auth");
if ((auth_filename = malloc(namelen + 1)) == 0) {
fprintf( stderr, "Memory exhausted\n" );
return -1;
}
strcpy( auth_filename, home );
strcat( auth_filename, "/.esd_auth" );
retval = 0;
/* open the authorization file */
if ( -1 == (auth_fd = open( auth_filename, O_RDONLY ) ) ) {
/* it doesn't exist? create one */
auth_fd = open( auth_filename, O_RDWR | O_CREAT | O_EXCL,
/* S_IRUSR | S_IWUSR */ 0 );
if ( -1 == auth_fd ) {
/* coun't even create it? bail */
perror( auth_filename );
goto exit_fn;
}
/* spew random garbage for a key */
srand( time(NULL) );
for ( i = 0 ; i < ESD_KEY_LEN ; i++ ) {
tumbler = rand() % 256;
write( auth_fd, &tumbler, 1 );
}
/* rewind the file to the beginning, and proceed */
lseek( auth_fd, 0, SEEK_SET );
}
/* read the key from the authorization file */
if ( ESD_KEY_LEN != read( auth_fd, auth_key, ESD_KEY_LEN ) )
goto exit_fd;
/* send the key to the server */
if ( ESD_KEY_LEN != write( sock, auth_key, ESD_KEY_LEN ) )
/* send key failed */
goto exit_fd;
/* send the key to the server */
if ( sizeof(endian) != write( sock, &endian, sizeof(endian) ) )
/* send key failed */
goto exit_fd;
/* we've run the gauntlet, everything's ok, proceed as usual */
/* fsync( sock ); */
retval = 1;
exit_fd:
close( auth_fd );
exit_fn:
free( auth_filename );
return retval;
}
/*******************************************************************/
/* lock/unlock will disable/enable foreign clients from connecting */
int esd_lock( int esd ) {
int proto = ESD_PROTO_LOCK;
int ok = 0;
/* diagnostic info */
/*
if ( getenv( "ESDBG" ) )
printf( "esound locking\n" );
*/
write( esd, &proto, sizeof(proto) );
esd_send_auth( esd );
if ( read( esd, &ok, sizeof(ok) ) != sizeof(ok) )
return -1;
return ok;
}
int esd_unlock( int esd ){
int proto = ESD_PROTO_UNLOCK;
int ok = 0;
/* diagnostic info */
/*
if ( getenv( "ESDBG" ) )
printf( "esound unlocking\n" );
*/
write( esd, &proto, sizeof(proto) );
esd_send_auth( esd );
if ( read( esd, &ok, sizeof(ok) ) != sizeof(ok) )
return -1;
return ok;
}
/*******************************************************************/
/* standby/resume will free/reclaim audio device so others may use it */
int esd_standby( int esd )
{
int proto = ESD_PROTO_STANDBY;
int ok = 0;
/* diagnostic info */
/*
if ( getenv( "ESDBG" ) )
printf( "esound standing by\n" );
*/
write( esd, &proto, sizeof(proto) );
esd_send_auth( esd );
if ( read( esd, &ok, sizeof(ok) ) != sizeof(ok) )
return -1;
return ok;
}
int esd_resume( int esd )
{
int proto = ESD_PROTO_RESUME;
int ok = 0;
/* diagnostic info */
/*
if ( getenv( "ESDBG" ) )
printf( "esound resuming\n" );
*/
write( esd, &proto, sizeof(proto) );
esd_send_auth( esd );
if ( read( esd, &ok, sizeof(ok) ) != sizeof(ok) )
return -1;
return ok;
}
/*******************************************************************/
/* initialize the socket to send data to the sound daemon */
int esd_open_sound( const char *host )
{
const char *espeaker = NULL;
struct hostent *he;
/*********************/
/* socket test setup */
struct sockaddr_in socket_addr;
int socket_out;
int curstate = 1;
/* TODO: find out why I don't have INET_ADDRSTRLEN in
my copy of /usr/include/netinet/in.h (instead of 64)
*/
char default_host[] = "0.0.0.0";
char connect_host[64];
int port = ESD_DEFAULT_PORT;
unsigned int host_div = 0;
/* diagnostic info */
/*
if ( getenv( "ESDBG" ) )
printf( "esound opening: %s\n", ( host ? host : "(nil)" ) );
*/
/* see if we have a remote speaker to play to */
espeaker = host ? host : getenv( "ESPEAKER" );
if ( espeaker != NULL ) {
/* split the espeaker host into host:port */
host_div = strcspn( espeaker, ":" );
/* get host */
if ( host_div ) {
strncpy( connect_host, espeaker, host_div );
connect_host[ host_div ] = '\0';
} else {
strcpy( connect_host, default_host );
}
/* Resolving the host name */
if ( ( he = gethostbyname( connect_host ) ) == NULL ) {
fprintf( stderr, "Can\'t resolve host name \"%s\"!\n",
connect_host);
return(-1);
}
memcpy( (struct in_addr *) &socket_addr.sin_addr, he->h_addr,
sizeof( struct in_addr ) );
/* get port */
if ( host_div != strlen( espeaker ) )
port = atoi( espeaker + host_div + 1 );
if ( !port )
port = ESD_DEFAULT_PORT;
/* printf( "(remote) host is %s : %d\n", connect_host, port ); */
} else if( !inet_aton( default_host, &socket_addr.sin_addr ) ) {
fprintf( stderr, "couldn't convert %s to inet address\n",
default_host );
return -1;
}
/* create the socket, and set for non-blocking */
socket_out = socket( AF_INET, SOCK_STREAM, 0 );
if ( socket_out < 0 )
{
fprintf(stderr,"Unable to create socket\n");
return( -1 );
}
/* this was borrowed blindly from the Tcl socket stuff */
if ( fcntl( socket_out, /* F_SETFD */ 0 , /* FD_CLOEXEC*/ 0 ) < 0 )
{
fprintf(stderr,"Unable to set socket to non-blocking\n");
return( -1 );
}
if ( setsockopt( socket_out, SOL_SOCKET, SO_REUSEADDR,
&curstate, sizeof(curstate) ) < 0 )
{
fprintf(stderr,"Unable to set for a fresh socket\n");
return( -1 );
}
/* set the connect information */
socket_addr.sin_family = AF_INET;
socket_addr.sin_port = htons( port );
if ( connect( socket_out,
(struct sockaddr *) &socket_addr,
sizeof(struct sockaddr_in) ) < 0 )
{
/* fprintf(stderr,"Unable to connect to EsounD server at port %d\n",
port ); */
/* fprintf(stderr,"This generally means that the program could not talk to the esound server\n"); */
return -1;
}
/* send authorization */
if ( !esd_send_auth( socket_out ) ) {
/* couldn't send authorization key, bail */
close( socket_out );
/* diagnostic info */
/*
if ( getenv( "ESDBG" ) )
printf( "esound opening: authorization failed\n" );
*/
return -1;
}
/* diagnostic info */
/*
if ( getenv( "ESDBG" ) )
printf( "esound opening: assigned to %d\n", socket_out );
*/
return socket_out;
}
/*******************************************************************/
/* open a socket for playing as a stream */
int esd_play_stream( esd_format_t format, int rate,
const char *host, const char *name )
{
int sock;
int proto = ESD_PROTO_STREAM_PLAY;
char name_buf[ ESD_NAME_MAX ];
/* connect to the EsounD server */
sock = esd_open_sound( host );
if ( sock < 0 )
return sock;
/* prepare the name buffer */
if ( name )
strncpy( name_buf, name, ESD_NAME_MAX );
else
name_buf[ 0 ] = '\0';
/* send the audio format information */
if ( write( sock, &proto, sizeof(proto) ) != sizeof(proto) )
return -1;
if ( write( sock, &format, sizeof(format) ) != sizeof(format) )
return -1;
if( write( sock, &rate, sizeof(rate) ) != sizeof(rate) )
return -1;
if( write( sock, name_buf, ESD_NAME_MAX ) != ESD_NAME_MAX )
return -1;
/* Reduce buffers on sockets to the minimum needed */
esd_set_socket_buffers( sock, format, rate, 44100 );
/* flush the socket */
/* fsync( sock ); */
/* diagnostic info */
/*
if ( getenv( "ESDBG" ) )
printf( "esound playing stream\n" );
*/
return sock;
}
/*******************************************************************/
/* open a socket for playing as a stream, fallback to /dev/dsp */
int esd_play_stream_fallback( esd_format_t format, int rate,
const char *host, const char *name )
{
int socket_out;
/* try to open a connection to the server */
socket_out = esd_play_stream( format, rate, host, name );
if ( socket_out >= 0 )
return socket_out;
/* if ESPEAKER is set, this is an error, bail out */
if ( getenv( "ESPEAKER" ) )
return -1;
/* go for /dev/dsp */
// esd_audio_format = format;
// esd_audio_rate = rate;
// socket_out = esd_audio_open();
/* diagnostic info */
/*
// if ( getenv( "ESDBG" ) )
// printf( "esound playing stream fallback\n" );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -