Linux下的基于udp传输的语音采集和播放
本人最近在研究实现在局域网内的两台Linux主机
·
本人最近在研究实现在局域网内的两台Linux主机实现语音通讯。虽然Linux下的音频编程框架有两种OSS和ALSA,但本人是新手,以前基本上都没怎么接触过音频, 觉得先从OSS入手好理解些,于是就基于OSS写了如下代码。下面是我写的测试程序,包括语音采集(udp-client.c)和语音播放(udp-server.c),经过验证基本能实现语音的采集和播放功能,但是还是有一定的问题,就是刚开始时,声音开听得很清楚,但时间长了以后就延时很大,而且有时候可能开没声音,我是用udp传的,这是不是与udp的传输方式有关,哪位对这方面比较了解的,希望能指点一下。代码如下:
/*********************************************************/
// udp-client.c
// gcc -o udp-client udp-client.c
// padsp ./udp-client IP
/*********************************************************/
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <linux/soundcard.h>
//录音频率
#define RATE 88200
//量化位数
#define SIZE 16
//声道数目
#define CHANNELS 2
//缓冲区大小
#define RSIZE 2048
//保存录取的音频数据
unsigned char buf[RSIZE];
int main(int argc,char *argv[])
{
int fd,sockfd;
int status;
int arg;
struct sockaddr_in s_addr;
if((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1)
{
perror("socket");
exit(errno);
}
else
printf("creat sockfd success!.\n\r");
s_addr.sin_family=AF_INET;
s_addr.sin_port=htons(7000);
if(argc!=2)
{
printf("用法:./udp-dsp-client IP地址。\n");
return 1;
}
else
s_addr.sin_addr.s_addr=inet_addr(argv[1]);
bzero ( & (s_addr.sin_zero),8);
/*************读方式打开音频设备********************************************************************************/
fd= open("/dev/dsp",O_RDONLY,0777);
if(fd < 0)
{
perror("Cannot open /dev/dsp device");
return 1;
}
//设置采样的量化位数
arg = SIZE;
status = ioctl(fd,SOUND_PCM_WRITE_BITS,&arg);
if(status == -1)
{
perror("Connet set SOUND_PCM_WRITE_BITS ");
return -1;
}
//设置采样时的声道数目
arg = CHANNELS;
status = ioctl(fd,SOUND_PCM_WRITE_CHANNELS,&arg);
if(status == -1)
{
perror("Connet set SOUND_PCM_WRITE_CHANNELS ");
return -1;
}
//设置采样时的频率
arg = RATE;
status = ioctl(fd,SOUND_PCM_WRITE_RATE,&arg);
if(status == -1)
{
perror("Connet set SOUND_PCM_WRITE_RATE ");
return -1;
}
int readNum,sendNum;
while(1)
{
//从声卡读语音数据
readNum = read(fd,buf,RSIZE);
if(readNum==-1)
{
perror("read wrong number of bytes\n");
}
//发送语音数据
sendNum=sendto(sockfd,buf,readNum,0,(struct sockaddr * )& s_addr,sizeof(struct sockaddr));
if(sendNum==-1)
<span style="white-space:pre"> </span>{
printf("sendto error\n");
break;
}
}
}
/*************************************************************************
// Mail: tangshaojie@sina.cn
// udp-server.c
// gcc -o udp-server udp-server.c
// padsp ./udp-server
************************************************************************/
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <linux/soundcard.h>
//录音频率
#define RATE 88200
//量化位数
#define SIZE 16
//声道数目
#define CHANNELS 2
//缓冲区大小
#define RSIZE 2048
//保存录取的音频数据
unsigned char buf[RSIZE];
int main(int argc,char *argv[])
{
//声卡描述符
int fd;
int arg;
int status;
//socket
struct sockaddr_in s_addr;
struct sockaddr_in c_addr;
int sock;
socklen_t addr_len;
int len;
if((sock=socket(AF_INET,SOCK_DGRAM,0))==-1) //使用UDP方式
{
perror("socket");
exit(errno);
}
else
printf("creat socket success.\n\r");
memset(&s_addr,0,sizeof(struct sockaddr_in));
s_addr.sin_family=AF_INET; //协议设为AF_INET
s_addr.sin_port=htons(7000); //接受端口为7000
s_addr.sin_addr.s_addr=INADDR_ANY; //本地任意IP
if((bind(sock,(struct sockaddr *) &s_addr,sizeof(s_addr)))==-1)
{
perror("bind");
exit(errno);
}
else
printf("bind address to socket.\n\r");
addr_len=sizeof(c_addr);
fd = open("/dev/dsp",O_WRONLY);
if(fd < 0)
{
perror("Connot open /dev/dsp device");
return 1;
}
//设置采样的量化位数
arg = SIZE;
status = ioctl(fd,SOUND_PCM_WRITE_BITS,&arg);
if(status == -1)
{
perror("Connet set SOUND_PCM_WRITE_BITS ");
return -1;
}
//设置采样时的声道数目
arg = CHANNELS;
status = ioctl(fd,SOUND_PCM_WRITE_CHANNELS,&arg);
if(status == -1)
{
perror("Connet set SOUND_PCM_WRITE_CHANNELS ");
return -1;
}
//设置采样时的频率
arg = RATE;
status = ioctl(fd,SOUND_PCM_WRITE_RATE,&arg);
if(status == -1)
{
perror("Connet set SOUND_PCM_WRITE_RATE ");
return -1;
}
//一直接受播放,直到按下ctrl+c为止
while(1)
{
len=recvfrom(sock,buf,sizeof(buf),0,(struct sockaddr *)&c_addr,&addr_len);
status = write(fd,buf,len);
if(status != len)
perror("wrote wrong number of bytes");
}
close(fd);
return 0;
}
更多推荐
已为社区贡献1条内容
所有评论(0)