一. 概述
ALSA是Advanced Linux Sound Architecture 的縮寫,目前已經(jīng)成為了linux的主流音頻體系結(jié)構(gòu)。
在內(nèi)核設(shè)備驅(qū)動(dòng)層,ALSA提供了alsa-driver,同時(shí)在應(yīng)用層,ALSA為咱們提供了alsa-lib,應(yīng)用程序只要調(diào)用alsa-lib提供的API,便可以完成對(duì)底層音頻硬件的控制。

二.常用命令
aplay -l 顯示實(shí)際聲卡序號(hào)

查看聲卡:
cat /proc/asound/cards
錄音:
arecord -D hw:0,0 -c 2 -r 44100 -f S16_LE test.wav
播放:
aplay -Dplughw:0,0 test.wav
打開耳機(jī)功能
amixer cset numid=1,iface=MIXER,name='Playback Path' 3

打開MIC(麥克風(fēng))功能:
amixer cset numid=2,iface=MIXER,name='Capture MIC Path' 1

三.音頻參數(shù)理解
聲道
單聲道:mono
雙聲道:stereo。最常見的類型,包含左聲道以及右聲道
采樣率
音頻采樣,是把聲音從模擬信號(hào)轉(zhuǎn)換為數(shù)字信號(hào)。采樣率,就是每秒對(duì)聲音進(jìn)行采集的次數(shù),同樣也是所得的數(shù)字信號(hào)的每秒樣本數(shù)文章來源:http://www.zghlxwxcb.cn/news/detail-597055.html
采樣越高,聲音的還原就越真實(shí)越自然,人對(duì)頻率的識(shí)別范圍是 20HZ - 22000HZ, 如果每秒鐘能對(duì)聲音做 22000 個(gè)采樣, 回放時(shí)就足可以滿足人耳的需求. 所以 22050 的采樣頻率是常用的, 根據(jù)奈奎斯特采樣定理44100Hz是不失真的情況下的采樣率, 超過48000的采樣對(duì)人耳已經(jīng)沒有意義。文章來源地址http://www.zghlxwxcb.cn/news/detail-597055.html
四.用戶空間打開PCM設(shè)備錄制聲音
#define ALSA_PCM_NEW_HW_PARAMS_API
#include <alsa/asoundlib.h>
int main() {
long loops;
int rc;
int size;
unsigned int val;
int dir;
char *buffer;
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
snd_pcm_uframes_t frames;
/*以錄制模式打開*/
/* 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");
exit(EXIT_FAILURE);
}
/*分配一個(gè)參數(shù)對(duì)象*/
/* Allocate a hardware parameters object. */
snd_pcm_hw_params_alloca(¶ms);
/*初始化參數(shù)對(duì)象*/
/* Fill it in with default values. */
rc = snd_pcm_hw_params_any(handle, params);
if (rc < 0) {
printf("Err\n");
}
/* Set the desired hardware parameters. */
/*交錯(cuò)模式*/
/* Interleaved mode */
rc = snd_pcm_hw_params_set_access(handle, params,
SND_PCM_ACCESS_RW_INTERLEAVED);
if (rc < 0) {
printf("Err\n");
}
/*PCM格式*/
/* Signed 16-bit little-endian format */
rc = snd_pcm_hw_params_set_format(handle, params,
SND_PCM_FORMAT_S16_LE);
if (rc < 0) {
printf("Err\n");
}
/*設(shè)置通道數(shù)*/
/* Two channels (stereo) */
rc = snd_pcm_hw_params_set_channels(handle, params, 2);
if (rc < 0) {
printf("Err\n");
}
/*設(shè)置采樣率*/
/* 44100 bits/second sampling rate (CD quality) */
val = 44100;
rc = snd_pcm_hw_params_set_rate_near(handle, params,
&val, &dir);
if (rc < 0) {
printf("Err\n");
}
/*沒周期的幀數(shù)*/
/* Set period size to 32 frames. */
frames = 32;
rc = snd_pcm_hw_params_set_period_size_near(handle,
params, &frames, &dir);
if (rc < 0) {
printf("Err\n");
}
/* 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 */
rc = snd_pcm_hw_params_get_period_size(params,
&frames, &dir);
if (rc < 0) {
printf("Err\n");
}
size = frames * 4; /* 2 bytes/sample, 2 channels */
buffer = (char *) malloc(size);
/* We want to loop for 5 seconds */
rc = snd_pcm_hw_params_get_period_time(params, &val, &dir);
loops = 5000000 / val;
while (loops > 0) {
loops--;
rc = snd_pcm_readi(handle, buffer, frames);
if (rc == -EPIPE) {
/* EPIPE means overrun */
fprintf(stderr, "overrun occurred/n");
//把PCM流置于PREPARED狀態(tài),這樣下次我們向該P(yáng)CM流中數(shù)據(jù)時(shí),它就能重新開始處理數(shù)據(jù)。
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);
}
rc = write(1, buffer, size);
if (rc != size)
fprintf(stderr,
"short write: wrote %d bytes/n", rc);
}
//調(diào)用snd_pcm_drain把所有掛起沒有傳輸完的聲音樣本傳輸完全
rc = snd_pcm_drain(handle);
//關(guān)閉該音頻流,釋放之前動(dòng)態(tài)分配的緩沖區(qū),退出
rc = snd_pcm_close(handle);
free(buffer);
return 0;
}
五.用戶空間打開PCM設(shè)備播放聲音
#define ALSA_PCM_NEW_HW_PARAMS_API
#include <alsa/asoundlib.h>
int main() {
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;
/* Open PCM device for playback. */
rc = snd_pcm_open(&handle, "default",
SND_PCM_STREAM_PLAYBACK, 0);
if (rc < 0) {
fprintf(stderr,
"unable to open pcm device: %s/n",
snd_strerror(rc));
exit(1);
}
/*分配一個(gè)參數(shù)對(duì)象*/
/* Allocate a hardware parameters object. */
snd_pcm_hw_params_alloca(¶ms);
/*初始化參數(shù)對(duì)象*/
/* Fill it in with default values. */
snd_pcm_hw_params_any(handle, params);
/* Set the desired hardware parameters. */
/*交錯(cuò)模式*/
/* Interleaved mode */
snd_pcm_hw_params_set_access(handle, params,
SND_PCM_ACCESS_RW_INTERLEAVED);
/*設(shè)置PCM格式*/
/* Signed 16-bit little-endian format */
snd_pcm_hw_params_set_format(handle, params,
SND_PCM_FORMAT_S16_LE);
/*設(shè)置通道數(shù)*/
/* Two channels (stereo) */
snd_pcm_hw_params_set_channels(handle, params, 2);
/*設(shè)置采樣率*/
/* 44100 bits/second sampling rate (CD quality) */
val = 44100;
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 * 4; /* 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);
/* 5 seconds in microseconds divided by
* period time */
loops = 5000000 / val;
while (loops > 0) {
loops--;
rc = read(0, buffer, size);
if (rc == 0) {
fprintf(stderr, "end of file on input/n");
break;
} else if (rc != size) {
fprintf(stderr,
"short read: read %d bytes/n", rc);
}
rc = snd_pcm_writei(handle, buffer, frames);
if (rc == -EPIPE) {
/* EPIPE means underrun */
fprintf(stderr, "underrun occurred/n");
//把PCM流置于PREPARED狀態(tài),這樣下次我們向該P(yáng)CM流中數(shù)據(jù)時(shí),它就能重新開始處理數(shù)據(jù)。
snd_pcm_prepare(handle);
} else if (rc < 0) {
fprintf(stderr,
"error from writei: %s/n",
snd_strerror(rc));
} else if (rc != (int)frames) {
fprintf(stderr,
"short write, write %d frames/n", rc);
}
}
//調(diào)用snd_pcm_drain把所有掛起沒有傳輸完的聲音樣本傳輸完全
snd_pcm_drain(handle);
//關(guān)閉該音頻流,釋放之前動(dòng)態(tài)分配的緩沖區(qū),退出
snd_pcm_close(handle);
free(buffer);
return 0;
}
到了這里,關(guān)于Linux alsa 音頻 錄制與播放的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!