音频系统,Alsa 里面的buff 是怎么计算的?
相關(guān)文章
(干貨)Ai音箱和Linux音頻驅(qū)動小談
Linux ALSA 圖解
我在MTK平臺下調(diào)試音頻ALSA
我們知道聲音是模擬信號,模擬信號轉(zhuǎn)成數(shù)字信號就一定有大小,既然有大小,那我們就需要開辟內(nèi)存來保存這些數(shù)據(jù)。
---- 我們知道,視頻流的一幀就是一張圖像 ------ 但是音頻不一樣,音頻的一幀不能表示是一句話,因為你不知道一個人說話的時間長度。
java讀取音頻代碼
int?bufferLen?=?mSampleRateInHz?*?channels?*?2?/?10;?//?100ms?data//int?bufferLen?=?2048;if?((channels?==?1)?&&?(mSampleRateInHz?==?32000)?&&?(mAudioSource?==?6)?&&?(mMaxChannels?>?0)){?//?get?raw?databufferLen?=?16000?*?mMaxChannels?*?2?/?10;?//?100ms?data}byte[]?buffer?=?new?byte[bufferLen];mAudioRecorder?=?new?AudioRecord(mAudioSource,?mSampleRateInHz,?mChannelConfig,AudioFormat.ENCODING_PCM_16BIT,?bufferLen?*?10);?//1?sec?bufferwhile(true){size?=?mAudioRecorder.read(buffer,?0,?bufferLen);?//100ms}tinycap 里面的 pcm_read 代碼
int?pcm_read(struct?pcm?*pcm,?void?*data,?unsigned?int?count) {struct?snd_xferi?x;if?(!(pcm->flags?&?PCM_IN))return?-EINVAL;x.buf?=?data;x.frames?=?count?/?(pcm->config.channels?*pcm_format_to_bits(pcm->config.format)?/?8);for?(;;)?{if?(!pcm->running)?{if?(pcm_start(pcm)?<?0)?{fprintf(stderr,?"start?error");return?-errno;}}if?(ioctl(pcm->fd,?SNDRV_PCM_IOCTL_READI_FRAMES,?&x))?{pcm->prepared?=?0;pcm->running?=?0;if?(errno?==?EPIPE)?{/*?we?failed?to?make?our?window?--?try?to?restart?*/pcm->underruns++;continue;}return?oops(pcm,?errno,?"cannot?read?stream?data");}return?0;} }提煉下重點
我們在里面看的一個英文單詞 frames ,frames 相當(dāng)一幀的數(shù)據(jù)。
----但是這個一幀跟視頻流里面的一張圖像又不是一個概念,這里的一幀相當(dāng)于聲音里面的最小計量單位。
音頻幀圖解解釋一下上面的圖片
假設(shè)我們使用的是一個立體聲 16位 16k的音頻流,不管是錄音還是播放都一樣,那么
立體聲 = 2通道
1次ADC轉(zhuǎn)換樣本數(shù)據(jù)是 16bits = 2bytes
1個幀 代表 所有通道的ADC轉(zhuǎn)換數(shù)據(jù)。那么我們現(xiàn)在是雙通道,所以
1幀 = (通道數(shù)) * (樣本大小bytes) = 2 * 2 = 4bytes
為了能支持2 * 16k的采樣率,系統(tǒng)必須支持如下的速度
bsp_rate = (通道數(shù)) * (1個樣本長度) * (采樣率) = 1幀 * 采樣率 =
2 * 2 *16k = 64000bytes/sec(秒)
假設(shè)現(xiàn)在 alsa每秒中斷DMA一次。那么我們每秒都需要64000bytes數(shù)據(jù)準(zhǔn)備好,才能滿足一個 雙通道 16 位 16k的音頻流。
如果半秒中斷一次,那么每次中斷就是 64000bytes/ 2 = 32000bytes
如果我們100ms 產(chǎn)生一次中斷,那么每次中斷就是 64000bytes / 10 = 6400bytes
我們可以通過設(shè)置period size 來控制pcm中斷的產(chǎn)生。
反推一下
---- 如果我們設(shè)置一個16位雙通道16k的音頻流, 并且每次都有1600幀數(shù)據(jù)
---- 4 byte * 1600frams = 6400字節(jié)
---- 一次中斷會需要6400字節(jié)的數(shù)據(jù)
----那么他就是100ms中斷一次「看上面的推斷」。
alsa會自己適應(yīng)實際的buffer_size 和period_size,根據(jù)請求的通道數(shù),和他們其他的一些屬性。
把音頻格式轉(zhuǎn)換成bits的代碼
unsigned?int?pcm_format_to_bits(enum?pcm_format?format) {switch?(format)?{case?PCM_FORMAT_S32_LE:case?PCM_FORMAT_S24_LE:return?32;case?PCM_FORMAT_S24_3LE:return?24;default:case?PCM_FORMAT_S16_LE:return?16;}; }我們會使用這個函數(shù)拿到對應(yīng)格式的音頻bit「正常是16bit 和 32bit」,但是,我們讀寫數(shù)據(jù)是字節(jié)對齊bytes對齊的,這也是我們看到很多地方有除以8這個操作的原因。
?x.buf?=?data;x.frames?=?count?/?(pcm->config.channels?*pcm_format_to_bits(pcm->config.format)?/?8);測試的小程序
---- 用來錄音的測試程序
#include?<stdio.h>#define?UNUSED(x)?(void)(x)int?main(int?argc,?char?**argv)?{UNUSED(argc);UNUSED(argv);char?*cmd?=?"tinycap?/sdcard/1.pcm?-D?0?-d?3?-r?16000?-c?2?-b?16";char?buf[256];FILE?*fp?=?popen(cmd,?"r");for?(int?i=0;?i<16;?i++)?{int?result?=?fread(buf,?1,?sizeof(buf),?fp);printf("read?%d?bytes\n",?result);}pclose(fp);return?0; }這個程序會打開聲卡 0 第 3 個pcm通路去錄音。
我們這里沒有設(shè)置「-p」這個屬性,加上這個屬性之后,就會知道在1秒內(nèi)的中斷次數(shù),從而知道1秒內(nèi)的音頻大小了。當(dāng)然了,我們不設(shè)置,也會有一個默認(rèn)值的。
? 推薦閱讀:
? ??專輯|Linux文章匯總
? ??專輯|程序人生
? ??專輯|C語言
嵌入式Linux
微信掃描二維碼,關(guān)注我的公眾號?
總結(jié)
以上是生活随笔為你收集整理的音频系统,Alsa 里面的buff 是怎么计算的?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jar反编译工具 比jd-gui 功能更
- 下一篇: 0基础可以考CPDA数据分析师证书吗