5.ALSA錄放音

簡介

高級 Linux 聲音體系(Advanced Linux Sound Architecture,ALSA)是Linux中提供聲音設備驅動的內核組件萤捆,用來代替原來的開放聲音系統(tǒng)(Open Sound System怨咪,OSSv3)赋铝。除了聲音設備驅動,ALSA還包含一個用戶空間的函數(shù)庫谍肤,開發(fā)者可以通過這些高級 API 使用驅動,不必直接與內核驅動進行交互(1)灶轰。

安裝

sudo apt install libasound2-dev

流程

  • 打開設備
  • 分配參數(shù)內存
  • 填充默認參數(shù)
  • 設置參數(shù)(詳細的參見 ALSA - PCM接口)
    • 通道數(shù)
    • 采樣率(碼率谣沸,用來指定時間和文件大小,frames/s)
    • 幀數(shù)(每次讀取的數(shù)據(jù)長度與該參數(shù)有關)
    • 數(shù)據(jù)格式(影響輸出數(shù)據(jù)笋颤、緩存大小)
    • 設備訪問類型(直接讀寫乳附、內存映射,交錯模式伴澄、非交錯模式)
  • 讀取赋除、寫入數(shù)據(jù)

簡單的例子

  • 包含頭文件
#include <alsa/asoundlib.h>
  • 查看設備,根據(jù)最后兩個數(shù)字確定設備名稱非凌,通常default就行了
aplay -L
  • 定義相關參數(shù)举农,錄放音都要經過相同的步驟,放一起定義
// 設備名稱敞嗡,這里采用默認颁糟,還可以選取"hw:0,0","plughw:0,0"等
const char *device = "default";
// 設備句柄
// 以下均定義兩個,根據(jù)前綴區(qū)分喉悴,c->capture,p->playback,沒有前綴的表示參數(shù)相同
snd_pcm_t *chandle;
snd_pcm_t *phandle;
// 硬件參數(shù)
snd_pcm_hw_params_t *cparams;
snd_pcm_hw_params_t *pparams;
// 數(shù)據(jù)訪問類型棱貌,讀寫方式:內存映射或者讀寫,數(shù)據(jù)
snd_pcm_access_t access_type = SND_PCM_ACCESS_RW_INTERLEAVED;
// 格式箕肃,
snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
// 碼率婚脱,采樣率,8000Hz,44100Hz
unsigned int rate = 44100;
// 通道數(shù)
unsigned int channels = 2;
// 幀數(shù),這里取32
snd_pcm_uframes_t frames = 32;
// 以下為可選參數(shù)
unsigned int bytes_per_frame;
// 軟件重采樣
unsigned int soft_resample;
  • 打開設備
snd_pcm_open(&chandle, device, SND_PCM_STREAM_CAPTURE, 0);
snd_pcm_open(&phandle, device, SND_PCM_STREAM_PLAYBACK, 0);

增加一個錯誤判斷

int err;
if ((err = snd_pcm_open(&chandle, device, SND_PCM_STREAM_CAPTURE, 0)) < 0)
{
    std::cout << "Capture device open failed.";
}
if ((err = snd_pcm_open(&phandle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
{
    std::cout << "Playback device open failed.";
}
  • 設置參數(shù),這里就不增加錯誤判斷了障贸,不然顯得有些長了
// 先計算每幀數(shù)據(jù)的大小
bytes_per_frame = snd_pcm_format_width(format) / 8 * 2;
// 計算需要分配的緩存空間的大小
buffer_size = frames * bytes_per_frame;

// 為參數(shù)分配空間
snd_pcm_hw_params_alloca(&params);
// 填充參數(shù)空間
snd_pcm_hw_params_any(handle, params);
// 設置數(shù)據(jù)訪問方式
snd_pcm_hw_params_set_access(handle, params, access_type);
// 設置格式
snd_pcm_hw_params_set_format(handle, params, format);
// 設置通道
snd_pcm_hw_params_set_channels(handle, params, channels);
// 設置采樣率
snd_pcm_hw_params_set_rate_near(handle, params, &rate, 0);

// 可選項错森,不改不影響
// 設置緩存大小
buffer_size = period_size * 2;
snd_pcm_hw_params_set_buffer_size_near(handle, params, &buffer_size);
// 設置段大小,period與OSS中的segment類似
period_size = buffer_size / 2;
snd_pcm_hw_params_set_period_size_near(handle, params, &period_size, 0));

//設置參數(shù)
snd_pcm_hw_params(handle, params);
  • 讀寫數(shù)據(jù)
// 分配緩存空間篮洁,大小上面通過buffer_size計算出了
char *buffer = (char *)malloc(buffer_size);
// 讀寫數(shù)據(jù)
snd_pcm_readi(chandle, buffer, frames);
snd_pcm_writei(phandle, buffer, frames);
  • 循環(huán)播放
while(1)
{
    snd_pcm_readi(chandle, buffer, frames);
    snd_pcm_writei(phandle, buffer, frames);
}
  • 捕獲一定時間的音頻數(shù)據(jù)到文件流
ofstream output("test.pcm", ios::trunc);

int loop_sec;
int frames_readed;
loop_sec = 10;
unsigned long loop_limit;
// 計算循環(huán)大小
loop_limit = loop_sec * rate;

for (size_t i = 0; i < loop_limit; )
{
    // 這里還需要判斷一下返回值是否為負
    frames_readed = snd_pcm_readi(chandle, buffer, frames);
    output.write(buffer, buffer_size);
    i += frames_readed;
}
  • 關閉設備涩维、釋放指針
snd_pcm_close(chandle);
snd_pcm_close(phandle);
free(buffer);

封裝一下

問題

  • [已解決] 錄放音過程中出現(xiàn)高音,多半是讀寫設備是緩存大小設置的問題嘀粱。
  • [已解決] 放音過程中也許會出現(xiàn)"Broken pipe"的錯誤激挪,添加如下需要重新準備設備
err = snd_pcm_writei(handle, input_buffer, frames);
if (err == -EPIPE)
{
    snd_pcm_prepare(handle);
    continue;
    // 或者
    // return 0;
}
  • [未解決] 如果錄音之后立即放音,開始不會有延時锋叨,但是時間長了以后延時會累加垄分。

相關鏈接

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市娃磺,隨后出現(xiàn)的幾起案子薄湿,更是在濱河造成了極大的恐慌,老刑警劉巖偷卧,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件豺瘤,死亡現(xiàn)場離奇詭異,居然都是意外死亡听诸,警方通過查閱死者的電腦和手機坐求,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來晌梨,“玉大人桥嗤,你說我怎么就攤上這事∽序颍” “怎么了泛领?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長敛惊。 經常有香客問我渊鞋,道長,這世上最難降的妖魔是什么瞧挤? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任锡宋,我火速辦了婚禮,結果婚禮上特恬,老公的妹妹穿的比我還像新娘员辩。我一直安慰自己,他們只是感情好鸵鸥,可當我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般妒穴。 火紅的嫁衣襯著肌膚如雪宋税。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天讼油,我揣著相機與錄音杰赛,去河邊找鬼。 笑死矮台,一個胖子當著我的面吹牛乏屯,可吹牛的內容都是我干的。 我是一名探鬼主播瘦赫,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼辰晕,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了确虱?” 一聲冷哼從身側響起含友,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎校辩,沒想到半個月后窘问,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡宜咒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年惠赫,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片故黑。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡儿咱,死狀恐怖,靈堂內的尸體忽然破棺而出倍阐,到底是詐尸還是另有隱情概疆,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布峰搪,位于F島的核電站岔冀,受9級特大地震影響,放射性物質發(fā)生泄漏概耻。R本人自食惡果不足惜使套,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鞠柄。 院中可真熱鬧侦高,春花似錦、人聲如沸厌杜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至瞧壮,卻和暖如春登馒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背咆槽。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工陈轿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人秦忿。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓麦射,卻偏偏與公主長得像,于是被迫代替她去往敵國和親灯谣。 傳聞我的和親對象是個殘疾皇子潜秋,可洞房花燭夜當晚...
    茶點故事閱讀 44,941評論 2 355

推薦閱讀更多精彩內容

  • 一.聲音參數(shù)基本概念: 聲音是連續(xù)模擬量,計算機將它離散化之后用數(shù)字表示酬屉,就有了以下幾個名詞術語半等。 樣本長度(sa...
    cs1001閱讀 5,398評論 0 3
  • 一.聲音參數(shù)基本概念: 聲音是連續(xù)模擬量,計算機將它離散化之后用數(shù)字表示呐萨,就有了以下幾個名詞術語杀饵。 樣本長度(sa...
    cs1001閱讀 2,735評論 0 2
  • 姓名:吳兆陽 學號:14020199009 轉自韋東山 嵌牛導讀:對嵌入式初學者,沒有足夠的視野選擇一個合適投入方...
    吳兆陽閱讀 2,387評論 0 4
  • Ubuntu的發(fā)音 Ubuntu谜悟,源于非洲祖魯人和科薩人的語言,發(fā)作 oo-boon-too 的音北秽。了解發(fā)音是有意...
    螢火蟲de夢閱讀 99,271評論 9 467
  • 什么是嵌入式 IEEE(Institute of Electrical and Electronics Engin...
    Leon_Geo閱讀 3,707評論 1 20