Linux下的OSS音频接口编程

采用OSS进行音频编程时应当遵循的一般性框架:

(1)打开音频设备;

(2)设置采样格式(即量化位数);

(3)设置声道数(单声道或者立体声);

(4)设置采样率(即采样速度);

(5)从设备读入数据或者向设备写入数据;

(6)关闭音频设备;

上述过程中,第(6)可选,因为在进程正常或非正常退出时都会关闭它所打开的文件描述字,这样也就把音频设备的资源释放了。但是,除此之外的五个步骤是不能缺少的,并且顺序也不能颠倒(OSS编程指南对此的说明是:在指定声道数之前设置采样率不能在所有的音频硬件上工作——如果在将声卡设置为高采样率模式之后更改了声道数,应用程序将出现不正确的行为。同时,必须在使用read()或者write()调用读写数据之前设置采样率)。

这是作者编写的一个读写/dev/dsp设备的小程序,可以用它来录制一段声音,也可以用来将录制到文件中的声音播放出来。除此之外,还可以通过命令行参数指定设备参数,如:采样率、量化位数、声道数、要录制的声音长度,等等。详细的命令行参数解释如下:

SndKit [-h] [-d device] [-c channel] [-b bits] [-f hz] [-l len] <-r|-p file>

其中:

¨ -h:打印帮助信息;

¨ -d:指定要读写的音频设备(默认为/dev/dsp);

¨ -c:指定使用的声道数(默认为MONO,单声道);

¨ -b:指定量化位数(默认为8位无符号整数);

¨ -f:指定采样频率(默认为8KHz);

¨ -l:指定录制的声音文件的长度(默认为1024,单位为KB);

¨ -r file:录制声音,file存放录制的声音数据;

¨ -p file:播放file文件中存储的声音数据。

注意:-h,-r,-p这三个选项不能同时出现在命令行上。比如,可以通过下面的命令录制一段声音:

[root@cyc source]# ./SndKit -c 2 -b 16 -f 48 -r cyc.wav

采用的是双声道立体声、16位量化位数、48KHz采样频率、录制的声音保存在cyc.wav文件中,要录制的声音长度采用默认值1024KB。录制好之后,可以通过下面的命令播放出来:

[root@cyc source]# ./SndKit -c 2 -b 16 -f 48 -p cyc.wav

sound data play complete!

需要注意的是,录制时采用的是什么样的参数,播放时就应该采用同样的参数,否则将会出错。

下面直接给出源代码:

/* Name: SndKit.c Copyright: GPLv2 Author: rockins(ybc2084@163.com) Date: 15-10-06 18:22 Description: implent raw sound record/play

run: ./SndKit [-h] [-d device] [-c channel] [-b bits] [-f hz] [-l len] <-r|-p file> e.g.: ./SndKit -h show help information ./SndKit -r record.wav record audio from microphone(/dev/dsp) ./SndKit -d /dev/dsp -p record.wav playback record.wav via /dev/dsp ./SndKit -b 8 -f 22 -r reacord.wav record audio in 8 bit & 22k hz ./SndKit -d /dev/dsp -c 2 -r record.wav record audio in /dev/dsp and stereo ./SndKit -r -l 40 record.wav record 40k audio data*/

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <fcntl.h>#include <errno.h>#include <sys/ioctl.h>#include <linux/soundcard.h> /*for OSS style sound programing */

#define TRUE 1#define FALSE 0

#define FMT8BITS AFMT_U8 /*unsigned 8 bits(for almost PC) */#define FMT16BITS AFMT_S16_LE /*signed 16 bits,little endian */

#define FMT8K 8000 /*default sampling rate */#define FMT11K 11025 /*11,22,44,48 are three pop rate */#define FMT22K 22050#define FMT44K 44100#define FMT48K 48000

#define MONO 1#define STEREO 2

#define ACT_RECORD 0#define ACT_PLAY 1

#define DFT_SND_DEV “/dev/dsp”#define DFT_SND_FMT FMT8BITS#define DFT_SND_SPD FMT8K#define DFT_SND_CHN MONO

#define DFT_LEN 1024 /*default record length:40k */#define BUFF_SIZE 512 /*buffer size:512 Bytes */

/************** function prototype ********************/

void Usage(void);int OpenDevice(const char *, unsigned int);int OpenFile(const char *, unsigned int);int CloseDevice(unsigned int);int CloseFile(unsigned int);

/************** function implementation **************/

int main(int argc, char *argv[]){ unsigned int snd_fmt = DFT_SND_FMT; /*sound format,bits */ unsigned int snd_chn = DFT_SND_CHN; /*sound channel number */ unsigned int snd_spd = DFT_SND_SPD; /*sound speed,frequency */ unsigned char *s_file = NULL; /*file hold sound data */ unsigned char *snd_device = DFT_SND_DEV; /*sound device */ unsigned int recd_or_play = ACT_PLAY; /*flag(default play) */ unsigned char buff[BUFF_SIZE]; /*sound buffer */ unsigned long len = DFT_LEN * 1024; /*record or play length(k) */ int snd_fd; /*sound device descriptor */ int s_fd; /*sound data file descrit */ ssize_t n; /*bytes already in or out */ ssize_t nRD; /*bytes readin */ ssize_t nWR; /*bytes write out */ unsigned int opt_chr; /*hold cli option */ unsigned int opt_err = FALSE; /*indicate whether parse option error */

/*parse cli option via getopt routine */ optind = 0; /*set optindex to 0 */ while ((opt_chr = getopt(argc, argv, “hd:c:b:f:l:r:p:”)) != -1) {switch (opt_chr) {case ‘h’: Usage(); return (0); /*return, 0 denote success */ break;case ‘d’: snd_device = optarg; /*sound device name */ break;case ‘c’: if (atoi(optarg) == 1) /*select channel number */ snd_chn = MONO; else if (atoi(optarg) == 2) snd_chn = STEREO; else { opt_err = 1; /*error occur */ fprintf(stderr, “wrong channel setting,” “should be 1 or 2(default 1,MONO)/n”); } break;case ‘b’: if (atoi(optarg) == 8) /*select data bit */ snd_fmt = FMT8BITS; else if (atoi(optarg) == 16) snd_fmt = FMT16BITS; else { opt_err = 1; /*error occur */ fprintf(stderr, “wrong bits setting,” “should be 8 or 16(default 8)/n”); } break;case ‘f’: if (atoi(optarg) == 8) snd_spd = FMT8K; /*sampling rate:8kbps */ else if (atoi(optarg) == 11) snd_spd = FMT11K; /*smapling rate:11.025k */ else if (atoi(optarg) == 22) snd_spd = FMT22K; /*sampling rate:22.050k */ else if (atoi(optarg) == 44) snd_spd = FMT44K; /*sampling rate:44.100k */ else if (atoi(optarg) == 48) snd_spd = FMT48K; /*sampling rate:48k */ else { opt_err = 1; /*error occur */ fprintf(stderr, “wrong sampling rate,” “should be 8,11,22,or 44(default 8kbps)/n”); } break;case ‘l’: len = atoi(optarg) * 1024; /*record length(k) */ break;case ‘r’: recd_or_play = ACT_RECORD; s_file = optarg; /*file to record sound */ break;case ‘p’: recd_or_play = ACT_PLAY; s_file = optarg; /*file to play sound */ break;case ‘?’: opt_err = 1; fprintf(stderr, “unknown option:%c/n”, optopt); break;default: opt_err = 1; fprintf(stderr, “getopt error:%d/n”, opterr); break;} }

/*check if cli option parsed right*/ if (opt_err || argc < 2) {fprintf(stderr, “parse command option failed!!!/n” “run ./SndKit -h for help/n”);return (-1); }

/*open device */ if ((snd_fd = OpenDevice(snd_device, recd_or_play)) < 0) {fprintf(stderr, “cannot open device %s:%s/n”, snd_device, strerror(errno));return (-1); }

/*open sound data file */ if ((s_fd = OpenFile(s_file, recd_or_play)) < 0) {fprintf(stderr, “cannot open sound file %s:%s/n”, s_file, strerror(errno));return (-1); }

/*set sound format */ if (SetFormat(snd_fd, snd_fmt, snd_chn, snd_spd) < 0) {fprintf(stderr, “cannot set %s in bit %d, channel %d, speed %d/n”, snd_device, snd_fmt, snd_chn, snd_spd);return (-1); }

/*do real action:record or playback */ if (recd_or_play == ACT_RECORD) { /*record sound into data file*/n = 0;while (n < len) { nRD = 0; /*amount read from sound device */ if ((nRD = read(snd_fd, buff, BUFF_SIZE)) < 0) { perror(“read sound device failed”); return (-1); }

if (n + nRD <= len) /*the len is not full */ nWR = nRD; /*write amount to sound data file */ else nWR = len – n; /*len will be overflow */

unsigned long old_nWR = nWR; /*s hold nWR’s old value */ unsigned long t = 0L; /*temp counter */ while (nWR > 0) { if ((t = write(s_fd, buff, nWR)) < 0) { perror(“write sound data file failed”); return (-1); } nWR -= t; } n += old_nWR;} } else if (recd_or_play == ACT_PLAY) { /*write sound data to device*/while (TRUE) { nRD = 0L; /*read amount from sound device */ if ((nRD = read(s_fd, buff, BUFF_SIZE)) < 0) { perror(“read sound data file failed”); return (-1); } else if (nRD == 0) { /*nRD == 0 means all sound stream output */ printf(“sound data play complete!/n”); exit(0); }

nWR = nRD; while (nWR > 0) { /*write into device*/ if ((n = write(snd_fd, buff, nWR)) < 0) { perror(“write sound device file failed”); return (-1); } nWR -= n; }} }

/*close sound device and sound data file*/ CloseDevice(snd_fd); CloseFile(s_fd);

return (0);}

/** OpenDevice():open sound device* params:* dev_name — device name,such as /dev/dsp* flag — flag(ACT_RECORD or ACT_PLAY)* returns:* file descriptor of sound device if sucess* -1 if failed*/int OpenDevice(const char *dev_name, unsigned int flag){ int dev_fd;

/*open sound device */ if (flag == ACT_RECORD) {if ((dev_fd = open(dev_name, O_RDONLY)) < 0) { return (-1);} } else if (flag == ACT_PLAY) {if ((dev_fd = open(dev_name, O_WRONLY)) < 0) { return (-1);} }

return (dev_fd);}

/** CloseDevice():close the sound device* params:* dev_fd — the sound device’s file descriptor* returns:* 0 if success* -1 if error occured*/int CloseDevice(unsigned int dev_fd){ return (close(dev_fd));}

/** OpenFile():open sound data file* params:* file_name — file name,e.g,record.wav* flag — flag(ACT_RECORD or ACT_PLAY)* returns:* file descriptor of sound data file if sucess* -1 if failed*/int OpenFile(const char *file_name, unsigned int flag){ int file_fd;

/*open sound data file */ if (flag == ACT_RECORD) {if ((file_fd = open(file_name, O_WRONLY)) < 0) { return (-1);} } else if (flag == ACT_PLAY) {if ((file_fd = open(file_name, O_RDONLY)) < 0) { return (-1);} }

return (file_fd);}

/** CloseFile():close the sound data file* params:* file_fd — the sound data file’s descriptor* returns:* 0 if success* -1 if error occured*/int CloseFile(unsigned int file_fd){ return (close(file_fd));}

/** SetFormat():Set Record and Playback format* params;* fd — device file descriptor* chn — channel(MONO or STEREO)* bits — FMT8BITS(8bits), FMT16BITS(16bits)* hz — FMT8K(8000HZ), FMT16K(16000HZ), FMT22K(22000HZ),* FMT44K(44000HZ),FMT48K(48000HZ)* returns:* return 0 if success, else return -1* notes:* parameter setting order should be like as:* 1.sample format(number of bits)* 2.number of channels(mono or stereo)* 3.sampling rate(speed)*/int SetFormat(unsigned int fd, unsigned int bits, unsigned int chn, unsigned int hz){ int ioctl_val;

/* set bit format */ ioctl_val = bits; if (ioctl(fd, SNDCTL_DSP_SETFMT, &ioctl_val) == -1) {fprintf(stderr, “Set fmt to bit %d failed:%s/n”, bits, strerror(errno));return (-1); } if (ioctl_val != bits) {fprintf(stderr, “do not support bit %d, supported %d/n”, bits, ioctl_val);return (-1); }

/*set channel */ ioctl_val = chn; if ((ioctl(fd, SNDCTL_DSP_CHANNELS, &ioctl_val)) == -1) {fprintf(stderr, “Set Audio Channels %d failed:%s/n”, chn, strerror(errno));return (-1); } if (ioctl_val != chn) {fprintf(stderr, “do not support channel %d,supported %d/n”, chn, ioctl_val);return (-1); }

/*set speed */ ioctl_val = hz; if (ioctl(fd, SNDCTL_DSP_SPEED, &ioctl_val) == -1) {fprintf(stderr, “Set speed to %d failed:%s/n”, hz, strerror(errno));return (-1); } if (ioctl_val != hz) {fprintf(stderr, “do not support speed %d,supported is %d/n”, hz, ioctl_val);return (-1); }

return (0);}

/** Usage():print help information* params:(none)* returns:(none)*/void Usage(void){ printf(“run: ./SndKit [-h] [-d device] [-c channel] [-b bits] [-f hz] [-l len] <-r|-p file>/n” “Description: implent raw sound record/play/n” “option:/n” “/t -h: print help informations/n” “/t -d device: assign sound device to record or playback(default /dev/dsp)/n” “/t -c channel: indicate in MONO or STEREO channel(default MONO)/n” “/t -b bits: assign sampling bits depth(default 8bits unsigned)/n” “/t -f hz: indicate sampling rate,i.e,frequence(default 8kbps)/n” “/t -l len: indicate recording sound’s length(default 1024k)/n” “/t -r|-p file: indicate record in or playback(no default,must give out explicitly)/n” “e.g.:/n” “/t ./SndKit -h show help information/n” “/t ./SndKit -r record.wav record audio from microphone(/dev/dsp)/n” “/t ./SndKit -d /dev/dsp -p record.wav playback record.wav via /dev/dsp/n” “/t ./SndKit -b 8 -f 22 -r reacord.wav record audio in 8 bit & 22k hz/n” “/t ./SndKit -d /dev/dsp -c 2 -r record.wav record audio in /dev/dsp and stereo/n” “/t ./SndKit -r -l 40 record.wav record 40k audio data in record.wav/n”);}

如此锐气,二十后生有之,六旬男子则更多见。

Linux下的OSS音频接口编程

相关文章:

你感兴趣的文章:

标签云: