http://blog.csdn.net/sea918/article/details/7249216linux
一、音頻開發模型:編程
OSS(open sound system) linux/unix 平臺的上早期的統一音頻接口。linux kernl 2.6 版本之前其它提供兩種設備文件以供編程。 經常使用的操做函數爲open、close、read、write、ioctl.ubuntu
(/dev/dsp錄音設備文件/dev/audio播放設備文件)windows
ALSA(a)目前流行的編譯框架。linux 2.6 版本發後支持。bash
提供統一的編程接口:snd_pcm_open、snd_pcm_close、snd_pcm_hw_params框架
基設備文件爲:/dev/snd/pcmC0D0p /dev/snd/pcmC0D0c /dev/snd/pcmC0D1p /dev/snd/timer函數
能夠經過bash命令查看 alsa 驅動版本:oop
root@ubuntu:cat /proc/asound/version編碼
Advanced linux Sound Architecture Driver Version 1.0.23spa
2,Alsa-lib 編譯
a,下載並安裝 alsa-lib庫
root@ubuntu: tar -xvf alsa-lib-1.0.13.tar.bz2
root@ubuntu:./configure
root@ubuntu:make
root@ubuntu: make install
3,編程
a,添加頭文件
#include <alsa/asoundlib.h>
b,編程錄音代碼.
*/ /* Use the newer ALSA API */ #define ALSA_PCM_NEW_HW_PARAMS_API #include <stdio.h> #include <stdlib.h> #include <alsa/asoundlib.h> #define LENGTH 3 //錄音時間,秒 #define RATE 9600 //採樣頻率 #define SIZE 16 //量化位數 #define CHANNELS 1 //聲道數目 #define RSIZE 8 //buf的大小, /********如下是wave格式文件的文件頭格式說明******/ /*------------------------------------------------ | RIFF WAVE Chunk | | ID = 'RIFF' | | RiffType = 'WAVE' | ------------------------------------------------ | Format Chunk | | ID = 'fmt ' | ------------------------------------------------ | Fact Chunk(optional) | | ID = 'fact' | ------------------------------------------------ | Data Chunk | | ID = 'data' | ------------------------------------------------*/ /**********以上是wave文件格式頭格式說明***********/ /*wave 文件一共有四個Chunk組成,其中第三個Chunk能夠省略,每一個Chunk有標示(ID), 大小(size,就是本Chunk的內容部分長度),內容三部分組成*/ struct fhead { /****RIFF WAVE CHUNK*/ unsigned char a[4];//四個字節存放'R','I','F','F' long int b; //整個文件的長度-8;每一個Chunk的size字段,都是表示除了本Chunk的ID和SIZE字段外的長度; unsigned char c[4];//四個字節存放'W','A','V','E' /****RIFF WAVE CHUNK*/ /****Format CHUNK*/ unsigned char d[4];//四個字節存放'f','m','t','' long int e; //16後沒有附加消息,18後有附加消息;通常爲16,其餘格式轉來的話爲18 short int f; //編碼方式,通常爲0x0001; short int g; //聲道數目,1單聲道,2雙聲道; long int h; //採樣頻率; long int i; //每秒所需字節數; short int j; //每一個採樣須要多少字節,若聲道是雙,則兩個一塊兒考慮; short int k; //即量化位數 /****Format CHUNK*/ /***Data Chunk**/ unsigned char p[4];//四個字節存放'd','a','t','a' long int q; //語音數據部分長度,不包括文件頭的任何部分 }wavehead;//定義WAVE文件的文件頭結構體 int startRecord(void) { long loops; int rc; int size; snd_pcm_t *handle; snd_pcm_hw_params_t *params; unsigned int val; int dir; snd_pcm_uframes_t frames; char *buffer; int fd_f; int status; /*如下wave 文件頭賦值*/ wavehead.a[0]='R'; wavehead.a[1]='I'; wavehead.a[2]='F'; wavehead.a[3]='F'; wavehead.b=LENGTH*RATE*CHANNELS*SIZE/8-8; wavehead.c[0]='W'; wavehead.c[1]='A'; wavehead.c[2]='V'; wavehead.c[3]='E'; wavehead.d[0]='f'; wavehead.d[1]='m'; wavehead.d[2]='t'; wavehead.d[3]=' '; wavehead.e=16; wavehead.f=1; wavehead.g=CHANNELS; wavehead.h=RATE; wavehead.i=RATE*CHANNELS*SIZE/8; wavehead.j=CHANNELS*SIZE/8; wavehead.k=SIZE; wavehead.p[0]='d'; wavehead.p[1]='a'; wavehead.p[2]='t'; wavehead.p[3]='a'; wavehead.q=LENGTH*RATE*CHANNELS*SIZE/8; /*以上wave 文件頭賦值*/ /* Open PCM device for recording (capture). */ rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, 0); if (rc < 0) { fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc)); exit(1); } /* Allocate a hardware parameters object. */ snd_pcm_hw_params_alloca(¶ms); /* Fill it in with default values. */ snd_pcm_hw_params_any(handle, params); /* Set the desired hardware parameters. */ /* Interleaved mode */ snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); /* Signed 16-bit little-endian format */ snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); /* Two channels (stereo) */ snd_pcm_hw_params_set_channels(handle, params, CHANNELS); /* 44100 bits/second sampling rate (CD quality) */ val = RATE; snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); /* Set period size to 32 frames. */ frames = 32; snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir); /* Write the parameters to the driver */ rc = snd_pcm_hw_params(handle, params); if (rc < 0) { fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc)); exit(1); } /* Use a buffer large enough to hold one period */ snd_pcm_hw_params_get_period_size(params, &frames, &dir); size = frames * 2; /* 2 bytes/sample, 2 channels */ buffer = (char *) malloc(size); /* We want to loop for 5 seconds */ snd_pcm_hw_params_get_period_time(params, &val, &dir); loops = 5000000 / val; if(( fd_f = open("./sound.wav", O_CREAT|O_RDWR,0777))==-1)//建立一個wave格式語音文件 { perror("cannot creat the sound file"); } if((status = write(fd_f, &wavehead, sizeof(wavehead)))==-1)//寫入wave文件的文件頭 { perror("write to sound'head wrong!!"); } while (loops > 0) { loops--; rc = snd_pcm_readi(handle, buffer, frames); if (rc == -EPIPE) { /* EPIPE means overrun */ fprintf(stderr, "overrun occurred\n"); snd_pcm_prepare(handle); } else if (rc < 0) { fprintf(stderr, "error from read: %s\n", snd_strerror(rc)); } else if (rc != (int)frames) { fprintf(stderr, "short read, read %d frames\n", rc); } if(write(fd_f, buffer, size)==-1) { perror("write to sound wrong!!"); } if (rc != size) fprintf(stderr, "short write: wrote %d bytes\n", rc); } snd_pcm_drain(handle); snd_pcm_close(handle); free(buffer); close(fd_f); return 0; }
OSS的編程
Linux下和聲卡相關的文件有許多,如採集數字樣本的/dev/dsp文件,針對混音器的/dev/mixer文件以及用於音序器的/dev /sequencer等。文件/dev/audio是一個基於兼容性考慮的聲音設備文件,它實際是到上述數字設備的一個映射,它最大的特點或許是對諸如 wav這類文件格式的直接支持。咱們下面的例子即便用了此設備文件實現了一個簡單的錄音機:咱們從聲卡設備(固然要用麥克風)讀取音頻數據,並將它存放到 文件test.wav中去。要播放這個wav文件,只要如前面所述,使用命令cat test.wav >/dev/audio便可,固然你也能夠用Linux下其餘的多媒體軟件來播放這個文件。
/* 此文件中定義了下面全部形如SND_的變量*/ #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <linux/soundcard.h> #define OPEN_DSP_FAILED 0x00000001 /*打開 dsp 失敗!*/ #define SAMPLERATE_STATUS 0x00000002 /*samplerate status failed*/ #define SET_SAMPLERATE_FAILED 0x00000003 /*set samplerate failed*/ #define CHANNELS_STATUS 0x00000004 /*Channels status failed*/ #define SET_CHANNELS_FAILED 0x00000005 /*set channels failed*/ #define FMT_STATUS 0x00000006 /*FMT status failed*/ #define SET_FMT_FAILED 0x00000007 /*set fmt failed*/ #define OPEN_FILE_FAILED 0x00000008 /*opem filed failed*/ int P8100_Audio_Play(char *pathname,int nSampleRate,int nChannels,int fmt) { int dsp_fd,mix_fd,status,arg; dsp_fd = open("/dev/dsp" , O_RDWR); /*open dsp*/ if(dsp_fd < 0) { return OPEN_DSP_FAILED; } arg = nSampleRate; status = ioctl(dsp_fd,SOUND_PCM_WRITE_RATE,&arg); /*set samplerate*/ if(status < 0) { close(dsp_fd); return SAMPLERATE_STATUS; } if(arg != nSampleRate) { close(dsp_fd); return SET_SAMPLERATE_FAILED; } arg = nChannels; /*set channels*/ status = ioctl(dsp_fd, SOUND_PCM_WRITE_CHANNELS, &arg); if(status < 0) { close(dsp_fd); return CHANNELS_STATUS; } if( arg != nChannels) { close(dsp_fd); return SET_CHANNELS_FAILED; } arg = fmt; /*set bit fmt*/ status = ioctl(dsp_fd, SOUND_PCM_WRITE_BITS, &arg); if(status < 0) { close(dsp_fd); return FMT_STATUS; } if(arg != fmt) { close(dsp_fd); return SET_FMT_FAILED; }/*到此設置好了DSP的各個參數*/ FILE *file_fd = fopen(pathname,"r"); if(file_fd == NULL) { close(dsp_fd); return OPEN_FILE_FAILED; } int num = 3*nChannels*nSampleRate*fmt/8; int get_num; char buf[num]; while(feof(file_fd) == 0) { get_num = fread(buf,1,num,file_fd); write(dsp_fd,buf,get_num); if(get_num != num) { close(dsp_fd); fclose(file_fd); return 0; } } close(dsp_fd); fclose(file_fd); return 0; } int main() { int value; value = P8100_Audio_Play("/windows/C/WINDOWS/Media/Windows Startup.wav",44100,2,16); //注意播放文件的路徑哦!! fprintf(stderr,"value is %d",value); return 0; }