虽说现在较新的kernel都支持ALSA了,但是我认为OSS编程是比较容易上手的,因为比较符合Linux的编程的框架。再说ALSA配置的时候也可以选择OSS支持,这样OSS应用程序无需更改就可以使用ALSA驱动。
关于录音和放音的ADC/DAC的控制设备节点为/dev/dsp, 音量调整的设备节点为/dev/mixer。
从/dev/dsp读取的过程是录音,向/dev/dsp写入的过程为播放。
有许多CODEC,不支持以O_RDWR的方式打开。所以对于读和写,要分别打开,以两个文件描述符进行操作。
针对录音的流程,大致代码如下:
#include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/ioctl.h> #include <sys/stat.h> #include <stdlib.h> #include <stdio.h> #include <linux/soundcard.h> #define RATE 48000 #define CHANNELS 2 #define BITS 16 #define TOTAL (BITS * RATE * CHANNELS / 8 * 15) //15 seconds #define BYTES_4K 4096 #define RECORD_FILE "/mnt/disk/record.pcm" int main() { int pcm_fd; int dsp_fd_rd; char buf[4 * 1024] = {0}; int ret = 0; int total = 0; int rate = RATE; int channels = CHANNELS; int bits = BITS; dsp_fd_rd = open("/dev/dsp", O_RDONLY); if (dsp_fd_rd < 0) { perror("Failed to open!\n"); return -1; } pcm_fd = open(RECORD_FILE, O_WRONLY | O_CREAT, 0666); if (pcm_fd < 0) { perror("Failed to open/create pcm file"); return -1; } ioctl(dsp_fd_rd, SNDCTL_DSP_SPEED, &rate); ioctl(dsp_fd_rd, SNDCTL_DSP_STEREO, &channels); ioctl(dsp_fd_rd, SNDCTL_DSP_SETFMT, &bits); while (1) { ret = read(dsp_fd_rd, buf, BYTES_4K); if (ret < 0) { perror("Failed to read!"); return -1; } if (write(pcm_fd, buf, ret) < 0) { perror("Failed to write!"); return -1; } total += ret; if (total >= TOTAL) break; } close(dsp_fd_rd); close(pcm_fd); return 0; }
采样频率:这里为48Khz
通道数:2通道,也就是stereo
量化位数:16bit
还有一点要注意的是,针对我们的平台,每次read的大小必须为4K,也就是PAGE_SIZE的大小,因为DMA处理是以页为单位的。
以上代码实现简单的录音15秒并存放在文件中。
下面的代码设置了播放音量
int set_mixer_vol(unsigned int val) { int mixer_fd = open("/dev/mixer", O_RDWR); if (mixer_fd < 0) { perror("Failed to open /dev/mixer!"); return -1; } else { if ((val & 0xff) > 100) { val = 100; } ioctl(mixer_fd, SOUND_MIXER_WRITE_VOLUME, &val); close(mixer_fd); } return 0; }
播放的代码与录音类似,在此就不贴出了。