⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 esdlib.c

📁 Windows NT声卡驱动VXD
💻 C
📖 第 1 页 / 共 2 页
字号:
#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 + -