[buug] a question about a audio transfers program

George Wong crazylion at vip.sina.com
Tue Jul 27 10:55:30 PDT 2004


I wrote a socket program which used to voice transfers. It could transmit voice in signal direction. There are two problems:
First, there is delay. And sometimes, the voice is intermittent. I think it is the false of network. How could I improve the performance of the program.
Secondly, I want to implement the voice transfers in bidirectional. There are two ways that I could reach. One, I add both write() and read() in a loop. But it causes read() error if I put read() behind write(). I think it is because that there is no waiting before read(), the voice transfers between server and client need time.Another is that start both server and client in one side, but I cannot open audio device twice. Is there a function that could check if the device is opened before the program want to open it? 

In addition, I use ipp in the program to implement audio filter which make audio into PCM. Are there other implementations without IPP?

------audio_device.c------

/* Linux audio output device interface */
#include	<fcntl.h>
#include	<unistd.h>
#include	<sys/ioctl.h>
#include	<linux/soundcard.h>
#include	<sched.h>
#include	<signal.h>

/* Console, file, and string I/O */
#include	<stdio.h>
#include	<string.h>
#include	<stdlib.h>

/* Standard IPP definitions */
#include	"ippdefs.h"
#include	"ippSP.h"

#define		MAX_BUF_SIZE	80			/* Audio buffer size */

#define		DS		6			/* Default audio sample rate = 48 kHz,
							   must downsample to 8 kHz */
#define		US		6			/* Default audio sample rate = 48kHz,
							   must upsample to 8 kHz */

/* User interface constants */
#define		UI_STACK_SIZE	2500			/* User interface stack size, in 32-bit words */
#define		MAX_STRING	256			/* The length of string that user inputs */


/****************
 Shared variable
 ***************/
int	flag=1;				/* the flag of whether to go on */

/***************************************************************************************
// Name:			OpenAudioDevice
//
// Description:		Initialize Linux audio output device.
//
// Input Arguments:	dev		- Pointer to the audio output device.
//			channels	- Number of audio channels.
//
// Returns:		Status		0	= success, device ready
//					-100	= unable to open device
//					-101	= unable to select 16-bit stereo PCM
//					-102	= unable to select 44100 Hz sample rate
//					-103	= unable to select specified # of channels
//
****************************************************************************************/
int OpenAudioDevice(int *dev, int channels, int SampleRate)
{
	long param;
	int status=0;

	/* Open audio device (UDA1341 on the Linux SA-1110 Microprocessor Evaluation Module) */
	if ((*dev=open("/dev/dsp",O_RDWR))==-1) status=-100;

	/* Request 16-bit, little-endian, PCM data format */
	param = AFMT_S16_LE;
	if ((ioctl(*dev,SNDCTL_DSP_SETFMT,&param))!=0) { close (*dev); status=-101; }

	/* Request sample rate */
	param=SampleRate;
	if ((ioctl (*dev,SNDCTL_DSP_SPEED,&param))!=0) { close (*dev); status=-102; }

	/* Request number of channels */
	param = channels;
	if ((ioctl(*dev,SNDCTL_DSP_CHANNELS,&param))!=0) { close (*dev); status=-103; }

	/* Trap unsuccessful attempts to open audio device */
	if (status<0) { fprintf(stderr,"\nUnable to open audio device.\n"); fflush(stderr); return(status); }
	else return 0;
}

/***************************************************************************************
// Name:			GetAudioInput
//
// Description:		Read pcm audio from the audio input device.
//			Assumes 48 kHz input stream
//
// Input Arguments:	dev	- Pointer to the audio input device.
//			sig	- Pointer to a buffer of interleaved pcm audio.
//			len	- PCM buffer length, in samples (not bytes)
//
// Returns:		None.
//
// Notes:		Stereophonic data is interleaved as follows:  R0L0R1L1 ... R575L575;
//			For channels=1, right channel data is replicated on to the left.
****************************************************************************************/
void GetAudioInput(int *dev, Ipp16s *sig, int len)
{
	int i,j;					/* Buffer indices */
	static Ipp16s pcm[2*MAX_BUF_SIZE];

	/* Fill pcm audio input buffer */
	read(*dev,pcm,2*len*sizeof(Ipp16s));

	/* Extract right channel from the L/R interleaved data since
	   resampler requires contiguous (non-interleaved) samples */
	for(i=j=0;j<(2*len);i++,j+=2)
		sig[i]=pcm[j];
		//sig[i]=(((int)pcm[j]+(int)pcm[j+1])>>1)&0xffff;
}

/***************************************************************************************
// Name:			GetAudioInput_8
//
// Description:		Read pcm audio from the audio input device.
//			Assumes 48 kHz input stream, generates 8 kHz output stream
//
// Input Arguments:	dev	- Pointer to the audio input device.
//			sig	- Pointer to a buffer of interleaved pcm audio.
//			len	- PCM buffer length, in samples (not bytes)
//
// Returns:		None.
//
// Notes:		Stereophonic data is interleaved as follows:  R0L0R1L1 ... R575L575;
//			For channels=1, right channel data is replicated on to the left.
****************************************************************************************/
void GetAudioInput_8(int *dev, Ipp16s *sig, int len)
{
	int i,j;					/* Buffer indices */
	static Ipp16s pcm[DS*2*MAX_BUF_SIZE];

	/* Downsample filter */
	int TAPS_DS=38;
	static Ipp16s fmem[76];
	static int fptr;
	static int init=0;
	static Ipp16s taps_ds[38]=
	{
	  -42, 268, 494, 792, 1030, 1086, 852, 294, -516, -1390, -2038, -2148, -1468, 108,
       2472, 5300, 8114, 10380, 11644, 11644, 10380, 8114, 5300, 2472, 108, -1468,
	  -2148, -2038, -1390, -516, 294, 852, 1086, 1030, 792, 494, 268, -42
	};

	if (!init)
	{
		init=1;
		ippsZero_16s(fmem,76);
		fptr=0;
	}

	/* Fill pcm audio input buffer */
	read(*dev,pcm,DS*2*len*sizeof(Ipp16s));

	/* Extract right channel from the L/R interleaved data since
	   resampler requires contiguous (non-interleaved) samples */
	for(i=0,j=1;i<(DS*len);i++,j+=2)
		pcm[i]=pcm[j];

	/* Resample 48 kHz -> 8 kHz */
	ippsFIR_Direct_16s_I(pcm,DS*len,taps_ds,TAPS_DS,fmem,&fptr);
	for(i=j=0;i<len;i++,j+=DS)
		sig[i]=pcm[j];
}

/***************************************************************************************
// Name:			PutAudioOutput
//
// Description:		Write pcm audio to the audio output device.
//			Assumes 48 kHz input stream
//
// Input Arguments:	dev	- Pointer to the audio input device.
//			sig	- Pointer to a buffer of interleaved pcm audio.
//			len	- PCM buffer length, in samples (not bytes)
//
// Returns:		None.
//
// Notes:		Stereophonic data is interleaved as follows:  R0L0R1L1 ... R575L575;
//			For channels=1, right channel data is replicated on to the left.
****************************************************************************************/
void PutAudioOutput(int *dev, Ipp16s *sig, int len)
{
	int i,j;					/* Buffer indices */
	static Ipp16s pcm[2*MAX_BUF_SIZE];

	for(i=j=0;i<2*len;i+=2,j++)			/* Devide the PCM audio into two channels */
		pcm[i]=pcm[i+1]=sig[j];

	write(*dev,pcm,sizeof(Ipp16s)*len*2);		/* Write to the device */
}

/***************************************************************************************
// Name:			PutAudioOutput_8
//
// Description:		Write pcm audio to the audio output device.
//			Assumes 48 kHz sample rate; upsamples from 8->48 kHz
//
// Input Arguments:	dev	- Pointer to the audio input device.
//			sig	- Pointer to a buffer of interleaved pcm audio.
//			len	- PCM buffer length, in samples (not bytes)
//
// Returns:		None.
//
// Notes:		Stereophonic data is interleaved as follows:  R0L0R1L1 ... R575L575;
//			For channels=1, right channel data is replicated on to the left.
****************************************************************************************/
void PutAudioOutput_8(int *fp, Ipp16s *pcm, int len)
{
	static Ipp16s obuf[US*2*MAX_BUF_SIZE];		/* audio output buffer */
	static Ipp16s ubuf[US*MAX_BUF_SIZE];
	int i,j;

	/* Filter parameters */
	int RS_TAPS=38;
	static Ipp16s DelayLineRS[80];
	static int DelayLineIndexRS;
	static int init=0;
	Ipp16s rstaps[38]=
	{ -105, 670, 1235, 1980, 2575, 2715, 2130, 735, -1290, -3475, -5095, -5370, -3670,
	   270, 6180, 13250, 20285, 25950, 29110, 29110, 25950, 20285, 13250, 6180, 270, -3670,
	  -5370, -5095, -3475, -1290, 735, 2130, 2715, 2575, 1980, 1235, 670, -105 };

	if (!init)
	{
		init=1;
		ippsZero_16s(DelayLineRS,80);
		DelayLineIndexRS=0;
	}

	/* Clear upsample buffer */
	ippsZero_16s(ubuf,US*len);

	/* Upsample from 12 to 48 kHz */
	for(i=j=0;i<US*len;i+=US,j++)
		ubuf[i]=pcm[j];

	/* Interpolate */
	ippsFIR_Direct_16s_I(ubuf,US*len,rstaps,RS_TAPS,DelayLineRS,&DelayLineIndexRS);

	/* Replicate signal on both left and right channels */
	for(i=j=0;i<US*2*len;i+=2,j++)
		obuf[i]=obuf[i+1]=ubuf[j];

	/* Pass audio output buffer to the audio output device */
	write(*fp,obuf,sizeof(Ipp16s)*len*2*US);
}

/*********************************************************************************************
// Name:			 User interface thread
//
// Description:		Keyboard character-based user interface
//				Thread terminates with the parent
//
// Returns:		None
**********************************************************************************************/
int UserInterface()
{
	char msg[MAX_STRING];			/* Keyboard message */
	int i;

	/* UI main loop */
	while(1)
	{
		/* Get user input from the keyboard */
		//gets(msg);
		scanf("%s",msg);

		/* Parse and act on user input */
		switch(msg[0])
		{
			/* h = help */
			case 'h':
			case 'H':
				printf("\n\nCommands:\n");
				printf("q  - QUIT\n");
				printf("\n\n");
				break;

			/* q = Quit */
			case 'q':
			case 'Q':
//				printf("the command is q\n");
				flag=0;
				break;

			default:
				break;
		}

		/* Clear keyboard message buffer */
		for(i=0;i<MAX_STRING;i++)
			msg[i]='\0';
	}
}

------audio_server.c------
/*
 *   audio_server.c
 *   
 *   audio server program
 *
 *   Usage:
 *            -h   For help
 *            
 *   Options:
 *            [server address] [port]
 */

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/wait.h>
#include <signal.h>
#include <ctype.h>

#ifndef SHUT_RDWR
#define SHUT_RDWR 3
#endif

#define MAX_CLIENTS 64
//#define BUF_SIZE 4096
#define BACKLOG 10                /* How many pending connections queue will hold */
#define CORRECT 0
#define WRONG -1

/* Standard IPP definitions */
#include	"ippdefs.h"
#include	"ippSP.h"

#define TRUE 1
#define FALSE 0


#define MAX_BUF_SIZE 80
#define CONTINUE "OK"

/*
 *   Extern functions prototype
 */

extern int OpenAudioDevice(int *dev,int channels,int SampleRate);
extern void GetAudioInput(int *dev, Ipp16s *sig,int len);
extern void GetAudioInput_8(int *dev, Ipp16s *sig,int len);
extern void PutAudioOutput(int *dev, Ipp16s *sig,int len);
extern void PutAudioOutput_8(int *fp, Ipp16s *pcm,int len);
extern int UserInterface();

/****************
 Shared variable
 ***************/
extern int	flag;				/* the flag of whether to go on */

/*
 *   Process terminated child processes
 */
static void sigchld_handler(int signo)
{
	pid_t PID;
	int status;

	do {
		PID=waitpid(-1,&status,WNOHANG);
	}while(PID!=-1);

	/* Reset signal process */
	signal(SIGCHLD,sigchld_handler);
}

/*
 *   Report errors and return to shell:
 */
static void bail(const char *on_what)
{
	if(errno!=0)
		fprintf(stderr, "%s: %s\n", strerror(errno), on_what); 
}


void help()
{
	printf("File server 0.1:\n");
	printf("Usage:  server [host address [port]]\n");
	printf("Examples:\n");
	printf("\t server\n");
	printf("\t server 127.0.0.1\n");
	printf("\t server 127.0.0.1 9090\n");
	printf("\t server -h\n");
	printf("\n\nFor bug report, please mail to crazylion at vip.sina.com\n");
}
 


/*  
 *  Check if the format of host and port is right
 */ 
int check(char *host,char *port)
{
	int index=0;                                      /* Arrary subscript */
	while(host[index]!='\0')                          /* Check validity of host address */
	{
		if(isdigit(host[index])||host[index]=='.')
			;
		else
		{
			printf("Please check host format, such as 127.0.0.1 \n or type -h for help.\n");
			return WRONG;
			break;
		}
		index++;
	}
	if(isdigit(*port))                                /* Check validity of port number */
		;
	else
	{
		printf("Please check port format, such as 9090 \n or type -h for help.\n");
		return WRONG;
	}
	return CORRECT;
}


int main(int argc,char **argv)
{
	int z;
	char *server_addr="127.0.0.1";
	char *server_port="9090";
	struct sockaddr_in adr_srvr;                  /* AF_INET */
	struct sockaddr_in adr_clnt;                  /* AF_INET */
	int len_inet;                                 /* Length */
	int sock=-1;                                  /* Socket */
	int client=-1;                                /* Client socket */
	pid_t PID;                                    /* Process PID */
	int so_reuseaddr = TRUE;

	/* 
	 *  Capture signal SIGCHLD:
	 */
	signal(SIGCHLD,sigchld_handler);

	/*
	 *  Using address provided by command line
	 *  or using default address 127.0.0.1
	 */
	if(argc>=2)
	{
	 	if(!strcmp(argv[1],"-h"))
		{
			help();
			return 1;
		}
		else
		{
			server_addr=argv[1];
			if(argc>=3)
				server_port=argv[2];
		}
	}
	if(check(server_addr,server_port)==CORRECT)
		;
	else
		return WRONG;
	
		
		
	/*
	 *  Create a TCP/IP socket to use
	 */
	sock=socket(PF_INET,SOCK_STREAM,0);
	if(sock==-1)
		bail("socket(2)");
	
	z=setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&so_reuseaddr,sizeof so_reuseaddr);
	if(z==-1)
		bail("setsockopt(2)");
		
	/*
	 *  Initialize address structure
	 */
	memset(&adr_srvr,0,sizeof adr_srvr);
	adr_srvr.sin_family=AF_INET;
	adr_srvr.sin_port=htons(atoi(server_port));
	adr_srvr.sin_addr.s_addr=inet_addr(server_addr);	
	
	/*
	 *  Bind the server address
	 */
	len_inet=sizeof adr_srvr;
	z=bind(sock,(struct sockaddr *)&adr_srvr,len_inet);
	if(z==-1)
		bail("bind(2)");

	/*
	 *  Make it a listening socket
	 */
	z=listen(sock,BACKLOG);
	if(z==-1)
		bail("listen(2)");		
	

	/*
	 *   Begin to loop
	 */
	while(1)
	{
		/*
		 *   Wait for connection
		 */
		len_inet=sizeof adr_clnt;
		client=accept(sock,(struct sockaddr *)&adr_clnt,&len_inet);
		if(client==-1)
			bail("accept(2)");

		/*
		 *   Fork a new server process 
		 *   to service this client
		 */
		if((PID=fork())==-1)
		{
			/* Fail to fork: Give up */
			close(client);
			continue;
		}else if(PID>0){
			/* Parent process */
			close(client);
			continue;
		}

		/*
		 *  Process client's requests:
		 */
		//FILE	*fout;					/* Output file pointer */
		Ipp16s	buf[MAX_BUF_SIZE];			/* Input PCM speech buffer */
		int	AudioDevice=2;				/* Pointer to the (Linux) audio output device */
		//int	StackUI[UI_STACK_SIZE];			/* User interface stack (child thread) */
		int	UsrInterPID;				/* User thread PID */
		char	conti[10];				/* Check if it could continue */

		/* Spawn user interface thread */
		//UsrInterPID = __clone(UserInterface, &(StackUI[UI_STACK_SIZE]), CLONE_VM|CLONE_FS);
		UsrInterPID=PID;
			

		if(OpenAudioDevice(&AudioDevice, 2, 48000) < 0)			/* Open the audio device */
		{
			bail("OpenAudioDevice()");
			exit(1);
		}

		while(flag)
		{
			memset(buf,0,sizeof buf);
			GetAudioInput_8(&AudioDevice, buf, MAX_BUF_SIZE);	/* Read from the audio device */
			
			
			z=write(client,buf,sizeof buf);			/* Write to client socket */
			if(z==-1)
				bail("write(2)");
			z=recv(client,conti,strlen(conti),0);			/* Receive verify message */
			if(z==-1)
				bail("recv(2)");
			conti[z]='\0';
			z=strcmp(conti,CONTINUE);
			if(z)
				continue;
			else
				printf("Miss a piece of message!\n");
			//PutAudioOutput_8(&AudioDevice, buf, MAX_BUF_SIZE);	/* Write to the audio device */
			//printf("%2d",flag);
		}

		close(AudioDevice);

		/* kill the UI thread */
		kill(UsrInterPID, SIGKILL);
		
		exit(0);							/* Child process exit */
	}
	shutdown(client,SHUT_RDWR);
	close(sock);

	return 0;
}


------audio_client.c------
/*
 *   audio_client.c
 *   
 *   audio client program
 *
 *   Usage:
 *            -h   For help
 *            
 *   Options:
 *            [server address] [port]
 */

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/wait.h>
#include <signal.h>

#ifndef SHUT_RDWR
#define SHUT_RDWR 3
#endif

#define CORRECT 0
#define WRONG -1


#define TRUE 1
#define FALSE 0


#define MAX_BUF_SIZE 80
#define CONTINUE OK


/* Standard IPP definitions */
#include	"ippdefs.h"
#include	"ippSP.h"


/*
 *   Extern functions prototype
 */

extern int OpenAudioDevice(int *dev,int channels,int SampleRate);
extern void GetAudioInput(int *dev, Ipp16s *sig,int len);
extern void GetAudioInput_8(int *dev, Ipp16s *sig,int len);
extern void PutAudioOutput(int *dev, Ipp16s *sig,int len);
extern void PutAudioOutput_8(int *fp, Ipp16s *pcm,int len);
extern int UserInterface();

/****************
 Shared variable
 ***************/
extern int	flag;				/* the flag of whether to go on */

/*
 *   Report errors and return to shell:
 */
static void bail(const char *on_what)
{
	if(errno!=0)
		fprintf(stderr," %s: %s\n", strerror(errno), on_what); 
}


void help()
{
	printf("File server 0.1:\n");
	printf("Usage:  server [host address [port]]\n");
	printf("Examples:\n");
	printf("\t client\n");
	printf("\t client 127.0.0.1\n");
	printf("\t client 127.0.0.1 9090\n");
	printf("\t client -h\n");
	printf("\n\nFor bug report, please mail to crazylion at vip.sina.com\n");
}
 


/*  
 *  Check if the format of host and port is right
 */ 
int check(char *host,char *port)
{
	int index=0;                                      /* Arrary subscript */
	while(host[index]!='\0')                          /* Check validity of host address */
	{
		if(isdigit(host[index])||host[index]=='.')
			;
		else
		{
			printf("Please check host format, such as 127.0.0.1 \n or type -h for help.\n");
			return WRONG;
			break;
		}
		index++;
	}
	if(isdigit(*port))                                /* Check validity of port number */
		;
	else
	{
		printf("Please check port format, such as 9090 \n or type -h for help.\n");
		return WRONG;
	}
	return CORRECT;
}


int main(int argc,char ** argv)
{
	int z;
	char *server_addr="127.0.0.1";
	char *server_port="9090";
	struct sockaddr_in adr_srvr;                  /* AF_INET */
	int len_inet;                                 /* Length */
	int sock=-1;                                  /* Socket */
	int	AudioDevice=2;				/* Pointer to the (Linux) audio output device */
	Ipp16s	buf[MAX_BUF_SIZE];		      /* Input PCM speech buffer */
	char	*conti="OK";			      /* Check if it could continue */
	int so_reuseaddr = TRUE;

	/*
	 *  Using address provided by command line
	 *  or using default address 127.0.0.1
	 */
	if(argc>=2)
	{
	 	if(!strcmp(argv[1],"-h"))
		{
			help();
			return 1;
		}
		else
		{
			server_addr=argv[1];
			if(argc>=3)
				server_port=argv[2];
		}
	}
	if(check(server_addr,server_port)==CORRECT)
		;
	else
		return WRONG;
	
		
		
	/*
	 *  Create a TCP/IP socket to use
	 */
	sock=socket(PF_INET,SOCK_STREAM,0);
	if(sock==-1)
		bail("socket(2)");
	
	z=setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&so_reuseaddr,sizeof so_reuseaddr);
	if(z==-1)
		bail("setsockopt(2)");
		
	/*
	 *  Initialize address structure
	 */
	memset(&adr_srvr,0,sizeof adr_srvr);
	adr_srvr.sin_family=AF_INET;
	adr_srvr.sin_port=htons(atoi(server_port));
	adr_srvr.sin_addr.s_addr=inet_addr(server_addr);	
	
	/*
	 *   Connect to server
	 */
	len_inet=sizeof adr_srvr;
	z=connect(sock,(struct sockaddr *)&adr_srvr,len_inet);
	if(z==-1)
		bail("connect(2)");
	if(OpenAudioDevice(&AudioDevice, 2, 48000) < 0)			/* Open the audio device */
	{
		bail("OpenAudioDevice()");
		exit(1);
	}

	while(flag)
	{
		memset(buf,0,sizeof buf);
		z=read(sock,&buf,sizeof buf);
		if(z==-1)
			bail("read(2)");
		PutAudioOutput_8(&AudioDevice, buf, MAX_BUF_SIZE);	/* Write to the audio device */
		z=send(sock,conti,strlen(conti),0);			/* Send verify message */
		if(z==-1)
			bail("send(2)");
	}
	close(AudioDevice);
	shutdown(sock,SHUT_RDWR);
	return 0;
}






More information about the buug mailing list