ALSA和OSS编程示例

下面的程序是ALSA编程的例子,用gcc编译之前需要sudo apt-get install libasound2-dev安装共享库,再在编译时在后面添上-lasound即可,record的功能是录音并把数据输出到屏幕上,当然也可以将输出重定向到别的文件里,play的功能是从stdin中读取数据并转换成声音输出,当然也可以将输入重定向到record的输出文件,播放刚刚录下的声音

record.c:

#define ALSA_PCM_NEW_HW_PARAMS_API

#include <alsa/asoundlib.h>

int main() {
long loops;
int rc;
int size;
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
unsigned int val;
int dir;
snd_pcm_uframes_t frames;
char *buffer;

/* Open PCM device for recording (capture). */
rc = snd_pcm_open(&handle, "default",
                    SND_PCM_STREAM_CAPTURE, 0);
if (rc < 0) {
    fprintf(stderr,
            "unable to open pcm device: %s/n",
            snd_strerror(rc));
    exit(1);
}

/* Allocate a hardware parameters object. */
snd_pcm_hw_params_alloca(¶ms);

/* Fill it in with default values. */
snd_pcm_hw_params_any(handle, params);

/* Set the desired hardware parameters. */

/* Interleaved mode */
snd_pcm_hw_params_set_access(handle, params,
                      SND_PCM_ACCESS_RW_INTERLEAVED);

/* Signed 16-bit little-endian format */
snd_pcm_hw_params_set_format(handle, params,
                              SND_PCM_FORMAT_S16_LE);

/* Two channels (stereo) */
snd_pcm_hw_params_set_channels(handle, params, 2);

/* 44100 bits/second sampling rate (CD quality) */
val = 44100;
snd_pcm_hw_params_set_rate_near(handle, params,
                                  &val, &dir);

/* Set period size to 32 frames. */
frames = 32;
snd_pcm_hw_params_set_period_size_near(handle,
                              params, &frames, &dir);

/* Write the parameters to the driver */
rc = snd_pcm_hw_params(handle, params);
if (rc < 0) {
    fprintf(stderr,
            "unable to set hw parameters: %s/n",
            snd_strerror(rc));
    exit(1);
}

/* Use a buffer large enough to hold one period */
snd_pcm_hw_params_get_period_size(params,
                                      &frames, &dir);
size = frames * 4; /* 2 bytes/sample, 2 channels */
buffer = (char *) malloc(size);

/* We want to loop for 5 seconds */
snd_pcm_hw_params_get_period_time(params,
                                         &val, &dir);
loops = 5000000 / val;

while (loops > 0) {
    loops--;
    rc = snd_pcm_readi(handle, buffer, frames);
    if (rc == -EPIPE) {
      /* EPIPE means overrun */
      fprintf(stderr, "overrun occurred/n");
      snd_pcm_prepare(handle);
    } else if (rc < 0) {
      fprintf(stderr,
              "error from read: %s/n",
              snd_strerror(rc));
    } else if (rc != (int)frames) {
      fprintf(stderr, "short read, read %d frames/n", rc);
    }
    rc = write(1, buffer, size);
    if (rc != size)
      fprintf(stderr,
              "short write: wrote %d bytes/n", rc);
}

snd_pcm_drain(handle);
snd_pcm_close(handle);
free(buffer);

return 0;
}

play.c:

#define ALSA_PCM_NEW_HW_PARAMS_API

#include <alsa/asoundlib.h>

int main() {
  long loops;
  int rc;
  int size;
  snd_pcm_t *handle;
  snd_pcm_hw_params_t *params;
  unsigned int val;
  int dir;
  snd_pcm_uframes_t frames;
  char *buffer;

  /* Open PCM device for playback. */
  rc = snd_pcm_open(&handle, "default",
                    SND_PCM_STREAM_PLAYBACK, 0);
  if (rc < 0) {
    fprintf(stderr,
            "unable to open pcm device: %s/n",
            snd_strerror(rc));
    exit(1);
  }

  /* Allocate a hardware parameters object. */
  snd_pcm_hw_params_alloca(¶ms);

  /* Fill it in with default values. */
  snd_pcm_hw_params_any(handle, params);

  /* Set the desired hardware parameters. */

  /* Interleaved mode */
  snd_pcm_hw_params_set_access(handle, params,
                      SND_PCM_ACCESS_RW_INTERLEAVED);

  /* Signed 16-bit little-endian format */
  snd_pcm_hw_params_set_format(handle, params,
                              SND_PCM_FORMAT_S16_LE);

  /* Two channels (stereo) */
  snd_pcm_hw_params_set_channels(handle, params, 2);

  /* 44100 bits/second sampling rate (CD quality) */
  val = 44100;
  snd_pcm_hw_params_set_rate_near(handle, params,
                                  &val, &dir);

  /* Set period size to 32 frames. */
  frames = 32;
  snd_pcm_hw_params_set_period_size_near(handle,
                              params, &frames, &dir);

  /* Write the parameters to the driver */
  rc = snd_pcm_hw_params(handle, params);
  if (rc < 0) {
    fprintf(stderr,
            "unable to set hw parameters: %s/n",
            snd_strerror(rc));
    exit(1);
  }

  /* Use a buffer large enough to hold one period */
  snd_pcm_hw_params_get_period_size(params, &frames,
                                    &dir);
  size = frames * 4; /* 2 bytes/sample, 2 channels */
  buffer = (char *) malloc(size);

  /* We want to loop for 5 seconds */
  snd_pcm_hw_params_get_period_time(params,
                                    &val, &dir);
  /* 5 seconds in microseconds divided by
   * period time */
  loops = 5000000 / val;

  while (loops > 0) {
    loops--;
    rc = read(0, buffer, size);
    if (rc == 0) {
      fprintf(stderr, "end of file on input/n");
      break;
    } else if (rc != size) {
      fprintf(stderr,
              "short read: read %d bytes/n", rc);
    }
    rc = snd_pcm_writei(handle, buffer, frames);
    if (rc == -EPIPE) {
      /* EPIPE means underrun */
      /*fprintf(stderr, "underrun occurred/n");*/
      snd_pcm_prepare(handle);
    } else if (rc < 0) {
      fprintf(stderr,
              "error from writei: %s/n",
              snd_strerror(rc));
    }  else if (rc != (int)frames) {
      fprintf(stderr,
              "short write, write %d frames/n", rc);
    }
  }

  snd_pcm_drain(handle);
  snd_pcm_close(handle);
  free(buffer);

  return 0;
}

下面的程序是OSS和socket编程实例,功能是用udp协议实现两台主机的单工语音通信,在运行前两边的主机都需要先modprobe snd_pcm_oss来加载内核的oss模块,这两个程序我在树莓派上试过,效果还比较好

udp-dsp-server.c

#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_w 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)
{
 
printf("sendto error\n");
break;
 
}
 
}
 
}

udp-dsp-client.c

#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;
 
}


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的 Android ALSA 驱动示例: 1. 在 Android 应用程序中创建一个名为 "audio" 的设备节点,并将其绑定到 ALSA 驱动程序。 ``` int create_audio_device_node() { // 创建一个名为 "audio" 的设备节点 int fd = open("/dev/audio", O_RDWR); if (fd < 0) { ALOGE("Failed to open /dev/audio"); return -errno; } // 将设备节点绑定到 ALSA 驱动程序 int ret = ioctl(fd, SNDCTL_DSP_SETNAME, "audio"); if (ret < 0) { ALOGE("Failed to bind /dev/audio to ALSA driver"); close(fd); return -errno; } return fd; } ``` 2. 使用 ALSA API 配置音频设备。 ``` int configure_audio_device(int fd, int sample_rate, int channels, int format) { int ret; // 设置采样率 ret = ioctl(fd, SNDCTL_DSP_SPEED, &sample_rate); if (ret < 0) { ALOGE("Failed to set sample rate"); return -errno; } // 设置通道数 int channels_mask = (channels == 2) ? 0x0003 : 0x0001; ret = ioctl(fd, SNDCTL_DSP_CHANNELS, &channels_mask); if (ret < 0) { ALOGE("Failed to set channel count"); return -errno; } // 设置音频格式 int format_mask = (format == AUDIO_FORMAT_PCM_16_BIT) ? AFMT_S16_LE : AFMT_U8; ret = ioctl(fd, SNDCTL_DSP_SETFMT, &format_mask); if (ret < 0) { ALOGE("Failed to set audio format"); return -errno; } return 0; } ``` 3. 使用 ALSA API 读取或写入音频数据。 ``` int read_audio_data(int fd, void *buffer, int size) { int ret = read(fd, buffer, size); if (ret < 0) { ALOGE("Failed to read audio data"); return -errno; } return ret; } int write_audio_data(int fd, void *buffer, int size) { int ret = write(fd, buffer, size); if (ret < 0) { ALOGE("Failed to write audio data"); return -errno; } return ret; } ``` 这些函数可以在 Android 应用程序中使用以访问 ALSA 驱动程序并处理音频数据。请注意,这只是一个简单的示例,实际的 ALSA 驱动程序可能需要更复杂的配置和控制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值