linux dsp 播放音频文件

时间:2020-12-05 03:57:03
#include <unistd.h>
#include
<fcntl.h>
#include
<sys/types.h>
#include
<sys/ioctl.h>
#include
<stdlib.h>
#include
<stdio.h>
#include
<linux/soundcard.h>
/* 下面的三个参数是跟具体文件相关
* cmd: file 音频文件
* [file pass.wav] =>> pass.wav: RIFF (little-endian) data, WAVE audio, Microsoft PCM, 16 bit, mono 44100 Hz
*  1. 16位
*  2. mono为当声道=1, Stereo为立体声=2
*  3. 44100HZ为频率这个大家都知道,及一秒钟采集或者播放音频的bit数量。
*/
#define RATE 44100
#define SIZE 16
#define CHANNELS 1 // 1表示单声道,2为立体/* 缓冲区 */
unsigned
char buff[RATE * SIZE * CHANNELS / 8]; //buff里面正好放一秒钟的音频

int main()
{
int fd;
int wavfd; /* wav文件的描述符 */
int arg; /* ioctl参数 */
int ret; /* 返回值 */
/* 打开dsp音频设备 */
fd
= open("/dev/dsp", O_WRONLY);
if (fd < 0) {
printf(
"open of /dev/dsp failed");
exit(
1);
}
wavfd
= open("pass.wav",O_RDONLY);
if (wavfd < 0) {
printf(
"open of wav failed");
close(fd);
exit(
1);
}

/* 设置bit */
arg
= SIZE;
ret
= ioctl(fd, SOUND_PCM_WRITE_BITS, &arg);
if (ret == -1)
perror(
"SOUND_PCM_WRITE_BITS ioctl failed");
if (arg != SIZE)
perror(
"unable to set sample size");

/* 设置channels */
arg
= CHANNELS;
ret
= ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &arg);
if (ret == -1)
perror(
"SOUND_PCM_WRITE_CHANNELS ioctl failed");
if (arg != CHANNELS)
perror(
"unable to set number of channels");

/* 设置rate */
arg
= RATE;
ret
= ioctl(fd, SOUND_PCM_WRITE_RATE, &arg);
if (ret == -1)
perror(
"SOUND_PCM_WRITE_WRITE ioctl failed");

/* 从wav文件中读buff大小的内容,然后写入/dev/dsp中,直到文件结束 */
  /* Q:这里我试验时播放了两次,不知道啥情况,如果大家也遇到了请指教。*/
while ((ret = read(wavfd, buff, sizeof(buff))) > 0) {
//printf("read size = %d\n", ret);
write(fd, buff, sizeof(buff));
/* 下面的代码用于在更改播放文件的参数时,播放掉缓冲区内的内容 */
ret
= ioctl(fd, SOUND_PCM_SYNC, 0);
if (ret == -1)
perror(
"SOUND_PCM_SYNC ioctl failed");
}

close(fd);
close(wavfd);
}


下面是封装的接口可以直接拿过来使用:

void play_audio(int rate, int bits, int channels, char *filename)
{
int fd;
int wavfd; /* wav文件的描述符 */
int arg; /* ioctl arg */
int ret; /* return value */

unsigned
char buff[rate * bits * channels / 8]; //buff里面正好放一秒钟的音频
/* open device */
fd
= open("/dev/dsp", O_WRONLY);
if (fd < 0) {
printf(
"open of /dev/dsp failed");
exit(
1);
}
wavfd
= open(filename, O_RDONLY);
if (wavfd < 0) {
printf(
"open of wav failed");
close(fd);
exit(
1);
}

/* set bits */
arg
= bits;
ret
= ioctl(fd, SOUND_PCM_WRITE_BITS, &arg);
if (ret == -1)
perror(
"SOUND_PCM_WRITE_BITS ioctl failed");
if (arg != SIZE)
perror(
"unable to set sample size");

/* set channels */
arg
= channels;
ret
= ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &arg);
if (ret == -1)
perror(
"SOUND_PCM_WRITE_CHANNELS ioctl failed");
if (arg != CHANNELS)
perror(
"unable to set number of channels");

/* set rate */
arg
= rate;
ret
= ioctl(fd, SOUND_PCM_WRITE_RATE, &arg);
if (ret == -1)
perror(
"SOUND_PCM_WRITE_WRITE ioctl failed");

/* 从wav文件中读buff大小的内容,然后写入/dev/dsp中,直到文件结束 */
while ((ret = read(wavfd, buff, sizeof(buff))) > 0) {
printf(
"read size = %d\n", ret);
write(fd, buff,
sizeof(buff));
/* 下面的代码用于在更改播放文件的参数时,播放掉缓冲区内的内容 */
ret
= ioctl(fd, SOUND_PCM_SYNC, 0);
if (ret == -1)
perror(
"SOUND_PCM_SYNC ioctl failed");
}

close(fd);
close(wavfd);
}