嵌入式音訊程式設計——alsa庫使用
0 資料庫:alsa程式設計基本思路及程式設計框架
1 嵌入式上層音訊程式設計原理:上層開發------>> 呼叫中間層(alsa庫)<<------驅動開發關聯中間層 <<------硬體。 所以只需遵循alsa庫規則開發上層應用程式,在任何一個遵循alsa庫開發的驅動關聯的硬體,該應用程式都可以移植到該平臺,我們的重新如何使用alsa庫開發自己想要的東西。
2 alsa 庫安裝:
(1)PC 版:
下載alsa庫:alsa庫安裝包
tar -xf alsa-lib-1.1.5.tar.bz2 (切記,不要使用sudo 許可權解壓,否則後面交叉編譯時會出現問題)
配置生成Makefile檔案
[email protected]:~/alsa-lib-1.1.5$ ./configure
[email protected]:~/alsa-lib-1.1.5$ make
[email protected]:~/alsa-lib-1.1.5$ sudo make install --安裝
編譯程式:(一般需要在PC測試源程式,後在交叉編譯移植到開發板)
gcc -o record record.c -lasound
(2)ARM版
交叉編譯配置
[email protected]:~/alsa-lib-1.1.5$ make clean
[email protected]:~/alsa-lib-1.1.5$ ./configure --prefix=/opt/alsa --host=arm-linux
(prefix:指定安裝路徑,這個有個技巧:交叉編譯後,這個庫也要移植到開發板上,為了方便移植,我們一般安裝指定在一個路徑下,
在開發上建立同樣的路徑存放,在新增環境變數即可;host:指定運用平臺,這個必須的)
[email protected]:~/alsa-lib-1.1.5$ make
[email protected]:~/alsa-lib-1.1.5$ sudo make install --安裝
交叉編譯
[email protected]:/mnt/hgfs/aud_video/code$ arm-linux-gcc -o armrecord alsa_record.c -I/opt/alsa/include -L/opt/alsa/lib -lasound (asound:表示庫)
移植庫
/opt/ 下面的alsa拷貝開發板對應/opt目錄下
[email protected]:/opt$ sudo tar -jcf alsa.tar.bz2 alsa/
生成:alsa.tar.bz2,把alsa.tar.bz2下載到開發板/opt目錄下並且解壓
設定環境變數
/etc/profile 檔案中新增:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/alsa/lib
source /etc/profile ---生效
3 程式案列:錄音通過UDP傳送給播放器播放
(1)播放器:
#include <stdio.h>
#include <alsa/asoundlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
int main(int argc, char **argv)
{
snd_pcm_t *handle;//pcm控制代碼
snd_pcm_hw_params_t *params;//pcm屬性
//開啟裝置
int r = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK,0);
if(r < 0)
{
perror("snd pcm open fail");
return -1;
}
//設定引數
//初始化pcm屬性
snd_pcm_hw_params_alloca(¶ms);
snd_pcm_hw_params_any(handle, params);
//交錯模式---
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
//設定雙聲道,小端格式,16位
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
snd_pcm_hw_params_set_channels(handle, params, 2);
//設定取樣率(44100標準MP3取樣頻率)
int val = 44100;
snd_pcm_hw_params_set_rate_near(handle,params,&val,0);
//設在取樣週期,(最好是讓系統自動設定,這一步可以省略)
int frames;
//snd_pcm_hw_params_set_period_size_near(handle,params,(snd_pcm_uframes_t*)&frames,0);
//設定好的引數回寫裝置
r = snd_pcm_hw_params(handle, params);
if(r < 0)
{
perror("snd pcm params fail");
return -1;
}
//16--2--(一幀資料4個位元組)
//獲取一個週期有多少幀資料,一個週期一個週期方式處理音訊資料。
snd_pcm_hw_params_get_period_size(params,(snd_pcm_uframes_t*)&frames,0);
unsigned char *buffer = malloc(4*frames);//由於雙通道,16bit,每個通道2個位元組,一個週期所需要的空間為4個位元組*幀數
//初始化網路
int sockfd = socket (AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(atoi(argv[1]));//埠號,比如9000
addr.sin_addr.s_addr = htonl(INADDR_ANY);//本地IP
//繫結
int bret = bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
if(bret < 0)
{
perror("bind fail");
exit(1);
}
while(1)
{
//接收資料
bret = recvfrom(sockfd, buffer, frames*4, 0, NULL, NULL);
if(bret <= 0){break;}
printf("recv:%d\n", bret);
snd_pcm_writei(handle,buffer,frames);
}
close(sockfd);
//關閉
snd_pcm_drain(handle);
snd_pcm_close(handle);
free(buffer);
return 0;
}
(2)錄音器
#include <stdio.h>
#include <alsa/asoundlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <arpa/inet.h>
int main(int argc, char **argv)
{
snd_pcm_t *handle;//pcm控制代碼
snd_pcm_hw_params_t *params;//pcm屬性
//開啟裝置
int r = snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE,0);
if(r < 0)
{
perror("open fail");
return -1;
}
//設定引數
//初始化pcm屬性
snd_pcm_hw_params_alloca(¶ms);
snd_pcm_hw_params_any(handle, params);
//交錯模式---
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
//設定雙聲道,小端格式,16位
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
snd_pcm_hw_params_set_channels(handle, params, 2);
//設定取樣率
int val = 44100;
snd_pcm_hw_params_set_rate_near(handle,params,&val,0);
//設在取樣週期
int frames;
//snd_pcm_hw_params_set_period_size_near(handle,params,(snd_pcm_uframes_t*)&frames,0);
//設定好的引數回寫裝置
r = snd_pcm_hw_params(handle, params);
if(r < 0)
{
perror("set params fail");
return -1;
}
//16--2--(一幀資料4個位元組)
//獲取一個週期有多少幀資料
snd_pcm_hw_params_get_period_size(params,(snd_pcm_uframes_t*)&frames,0);
snd_pcm_hw_params_get_rate(params,&val,0);
printf("frames=%d, rate=%d\n", frames, val);
unsigned char *buffer = malloc(4*frames);
//初始化網路
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(atoi(argv[2]));//伺服器的埠號
addr.sin_addr.s_addr = inet_addr(argv[1]);//伺服器IP
int ret = 0;
while(1)
{
//錄音---返回幀數
ret = snd_pcm_readi(handle,buffer,frames);
if(ret != frames)
{
snd_pcm_prepare(handle);
continue;
}
//udp傳送--
ret = sendto(sockfd, buffer, frames*4, 0, (struct sockaddr*)&addr, sizeof(addr));
if(ret != frames*4)
{
break;
}
}
close(sockfd);
//關閉
snd_pcm_drain(handle);
snd_pcm_close(handle);
free(buffer);
return 0;
}
4 知識拓展
1. 可以呼叫Fmpeg庫對音訊進行程式設計。
2.alsa 庫產生的音訊資料是很大,必須經過壓縮再儲存、傳輸。