您的位置:首页 > 运维架构 > Linux

Linux 音频 驱动 接口 简介 之 OSS 编程 方法 采样频率 量化 位数 实例 driver interface

2012-03-28 18:22 555 查看
音频器件与DSP间的接口

两个概念:

* 采样频率:每秒采多少次;

* 量化精度(位数):每采一次采出的电压值分为多少份,如:量化精度为8bit,则分为2的8次方等份。

PCM接口:

由时钟脉冲(BCLK)、帧同步(FS)、数据接收(DR)、数据发送(DX)组成,每个音频通道获得一条独立的数据队列;

IIS(Inter-IC Sound)接口:

1980s-LRCLK(Left/Right Clock) ,其高位为左声道,低位为右声道;

AC97接口:

是一种数据格式,用于音频编码的内部架构规格,具有控制功能;AC-Link接口:位时钟(BITCLK),同步校正(SYNC)、编码到处理器(SDATAIN)与CPU到编码器(SDATAOUT)。

OSS驱动的组成与用户空间编程

OSS驱动实现两个基本音频设备:

mixer(混音器)

分为 input mixer 和 output mixer

打开设备 /dev/mixer 后,

可使用 ioctl(mixerfd, SOUND_MIXER_READ(SOUND_MIXER_MIC), &value);

及 ioctl(mixerfd, SOUND_MIXER_WRITE(SOUND_MIXER_VOLUME), &value);

来读取和写入麦克及喇叭的输入、输出增益;

dsp(数字信号处理器)

首先打开 /dev/dsp (声卡若支持全双工模式,则可以 O_RDWR 模式打开)后,

使用 ioctl(dspfd, SOUND_PCM_WRITE_CHANNELS, &value); 设置通道数,

ioctl(dspfd, SOUND_PCM_WRITE_RATE, &value); 设置采样频率,

ioctl(dspfd, SOUND_PCM_WRITE_BITS, &value); 设置量化位数,

使用 read 和 write 对 dspfd 设备操作,可实现录音放音,

ioctl(dspfd, SOUND_PCM_SYNC, 0); 函数可实现录音前等待放音结束。

简单的录音放音程序实例:
/*

* ===================================================================

*

*       Filename: oss.c

*

*    Description:

*

*        Version: 1.0

*        Created: Monday, May 24, 2010 11:07:27 HKT HKT

*       Revision: none

*       Compiler: gcc

*

*         Author: Wang Cheng (Dancy), dancesimply@gmail.com

*        Company: Kunming Lang Ju Inc.

*

* ===================================================================

*/

#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 8000

#define SIZE 8

#define CHANNELS 1

unsigned char buf[RATE*SIZE*CHANNELS/(8)];

char voice_name[] = "test.wav";//record file name

volatile int file_voice_fd=-1;//record file fd;

volatile int fd; /* 声音设备的文件描述符 */

//关闭声卡设备

void file_close()

{

    if(fd >0)

       {

           close(fd);

           fd=-1;

       }

}

int file_open()

{

int arg; /* 用于ioctl调用的参数 */

int status;   /* 系统调用的返回值 */

status = 1;

int ret;

ret = 0;

    //判断声音设备是否打开

if (fd > 0) return fd;

/* 打开声音设备 */

fd = open("/dev/dsp", O_RDWR,0);

if (fd < 0) {

    perror("open of /dev/dsp failed");

    ret = -1;

    goto quit;

}

ret = fd;

/* 设置采样时的量化位数 */

arg = SIZE;

status = ioctl(fd, SOUND_PCM_WRITE_BITS, &arg);

if (status == -1)

{

    perror("SOUND_PCM_WRITE_BITS ioctl failed");

    ret = -2;

    goto fd_err;

}

if (arg != SIZE)

{

   perror("unable to set sample size");

   ret = -3;

   goto fd_err;

}

/* 设置采样时的声道数目 */

arg = CHANNELS;

status = ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &arg);

if (status == -1)

{

   perror("SOUND_PCM_WRITE_CHANNELS ioctl failed");

   ret = -4;

     file_close();

    goto fd_err;

}

if (arg != CHANNELS)

{

      perror("unable to set number of channels");

      ret = -5;

     goto fd_err;

}

/* 设置采样时的采样频率 */

arg = RATE;

status = ioctl(fd, SOUND_PCM_WRITE_RATE, &arg);

if (status == -1)

{

   perror("SOUND_PCM_WRITE_WRITE ioctl failed");

   ret = -6;

   }

fd_err:

if(ret < 0)

{

     file_close();

}

quit:

    printf("ret = %d\n",ret);

return ret;

}

int create_voice_file()

{

    file_voice_fd = open(voice_name , O_RDWR | O_CREAT | O_TRUNC,S_IRUSR|S_IWUSR|S_IXUSR);

    if(file_voice_fd < 0)

   {

        printf("create new file failure");

       return -1;

    }

    printf("voice_name = %s, file fd is %d\n",voice_name, file_voice_fd);

    return 0;

}

int open_voice_file()

{

    file_voice_fd = open(voice_name , O_RDWR | O_CREAT | O_APPEND,S_IRUSR|S_IWUSR|S_IXUSR);

    if(file_voice_fd < 0)

   {

        printf("create new file failure");

       return -1;

    }

    printf("voice_name = %s, file fd is %d\n",voice_name, file_voice_fd);

    return 0;

}

int close_record_file()

{

    if(file_voice_fd >0 )

    {

        close(file_voice_fd);

        file_voice_fd = -1;

        return 0;

    }

    else

    {

        return -1;

    }

}

int main(int agrc, char **argv)

{

file_open();

if ('c' == **(argv+1))

{

   printf("voice record!\n");

   create_voice_file();

   int i = 0;

   while (i<5)

   {

    read(fd, buf, sizeof(buf));

    write(file_voice_fd, buf, sizeof(buf));

    printf("No. %d\n", i++);

   }

   close_record_file();

   goto play;

}

else if ('p' == **(argv+1))

{

play:

   printf("voice play!\n");

   open_voice_file();

   char playbuf[RATE*SIZE*CHANNELS/8*5];

   read(file_voice_fd, playbuf, sizeof(playbuf));

   write(fd, playbuf, sizeof(playbuf));

   close_record_file();

}

else

{

   printf("please input args...\nc for record and p for play.\n");

}

file_close();

}

参考文献:宋宝华
《Linux设备驱动开发详解》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息