📄 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 */
// these are really send calls...
if ( send( sock, (char *)auth_key, ESD_KEY_LEN, 0 ) == SOCKET_ERROR )
/* send key failed */
goto exit_fd;
/* send the key to the server */
if ( send( sock, (char *)&endian, sizeof(endian), 0 ) == SOCKET_ERROR )
/* send key failed */
goto exit_fd;
/* we've run the gauntlet, everything's ok, proceed as usual */
/* fsync( sock ); */
retval = 1;
goto exit_fn;
exit_fd:
closesocket( 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;
char regspeaker[1024];
DWORD dwRegSpeaker;
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 */
if (!host)
{
HKEY hKey;
DWORD dwType;
RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Enlightened\\WinESD", 0, KEY_READ, &hKey);
dwType = REG_SZ;
dwRegSpeaker = sizeof(regspeaker);
if (RegQueryValueEx(hKey, "ESPEAKER", 0, &dwType, regspeaker, &dwRegSpeaker) == ERROR_SUCCESS)
{
espeaker = regspeaker;
}
else
Beep(2000, 250);
}
else
espeaker = host;
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 );
// }
/* 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"); */
Beep(1500,500);
return -1;
}
if ( ioctlsocket( socket_out, FIONBIO, &curstate ) )
{
fprintf(stderr,"Unable to set for a fresh socket\n");
Beep(500,500);
return( -1 );
}
if ( setsockopt( socket_out, SOL_SOCKET, SO_REUSEADDR,
&curstate, sizeof(curstate) ) < 0 )
{
fprintf(stderr,"Unable to set for a fresh socket\n");
Beep(500,500);
return( -1 );
}
/* send authorization */
if ( !esd_send_auth( socket_out ) ) {
/* couldn't send authorization key, bail */
closesocket( 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 )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -