Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1317529
  • 博文数量: 860
  • 博客积分: 425
  • 博客等级: 下士
  • 技术积分: 1464
  • 用 户 组: 普通用户
  • 注册时间: 2011-08-20 19:57
个人简介

对技术执着

文章分类

全部博文(860)

文章存档

2019年(16)

2018年(12)

2015年(732)

2013年(85)

2012年(15)

我的朋友

分类: LINUX

2015-03-14 17:13:51

采用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()

  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

#include

#include

#include

#include

#include

#include  /*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");

}

阅读(455) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~