基於ALSA的WAV播放和錄音程式
這段時間在探索ALSA架構,從ALSA Core到ALSA Lib,再到Android Audio System。在看ALSA Lib時,寫了一個比較典型的基於ALSA的播放錄音程式。程式包包含四個部分:
WAV Parser是對WAV檔案的分析和封裝,這裡只針對Standard WAV File;
SND Common是Playback 和Record共同操作,如SetParams、ReadPCM和WritePCM等;
Playback和Record就分別是播放錄音的主體了。
原理很簡單,以Playback為例:從WAV檔案讀取PCM資料,通過I2S或AC97依次送到Audio Codec。難點在於對snd_pcm_hw_params_t的設定,尤其要確定每次要送到Audio Codec的資料幀大小(peroid_size),這個稍後解釋。
1、從WAV檔案的頭資訊可以分析出:sample_format、channels number、sample_rate、sample_length,這些引數要通過snd_pcm_hw_params_set_XXX()介面設定到snd_pcm_hw_params_t中。
2、接著我們要設定buffer_time 和peroid_time。通過snd_pcm_hw_params_get_buffer_time_max()介面可以獲取該Audio Codec可以支援的最大buffer_time,這裡我們設定buffer_time = (MAX_BUFFER_TIME > 500000) ? 500000 : MAX_BUFFER_TIME; peroid_time = buffer_time/4。
關於peroid的概念有這樣的描述:The “period” is a term that corresponds to a fragment in the OSS world. The period defines the size at which a PCM interrupt is generated. 從底層驅動看來,應該是PCM DMA單次傳送資料幀的大小。其實真正關注底層驅動的話,它並不是關心peroid_time,它關心的是peroid_size,這兩者有轉換關係。具體見struct snd_pcm_hardware結構體。
3、通過snd_pcm_hw_params_get_period_size()取得peroid_size,注意在ALSA中peroid_size是以frame為單位的。The configured buffer and period sizes are stored in “frames” in the runtime. 1 frame = channels * sample_size. 所以要對peroid_size進行轉換:chunk_bytes = peroid_size * sample_length / 8。chunk_bytes就是我們單次從WAV讀PCM資料的大小。
之後的過程就乏善可陳了。唯一要留意的是snd_pcm_writei()和snd_pcm_readi()的第三個引數size也是以frame為單位,不要忘記frames和bytes的轉換。
- //File : wav_parser.h
- //Author : Loon <[email protected]>
- #ifndef __WAV_PARSER_H
- #define __WAV_PARSER_H
- typedef unsigned char uint8_t;
- typedef unsigned short uint16_t;
- typedef unsigned int uint32_t;
- #if __BYTE_ORDER == __LITTLE_ENDIAN
- #define COMPOSE_ID(a,b,c,d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24))
- #define LE_SHORT(v) (v)
- #define LE_INT(v) (v)
- #define BE_SHORT(v) bswap_16(v)
- #define BE_INT(v) bswap_32(v)
- #elif __BYTE_ORDER == __BIG_ENDIAN
- #define COMPOSE_ID(a,b,c,d) ((d) | ((c)<<8) | ((b)<<16) | ((a)<<24))
- #define LE_SHORT(v) bswap_16(v)
- #define LE_INT(v) bswap_32(v)
- #define BE_SHORT(v) (v)
- #define BE_INT(v) (v)
- #else
- #error "Wrong endian"
- #endif
- #define WAV_RIFF COMPOSE_ID('R','I','F','F')
- #define WAV_WAVE COMPOSE_ID('W','A','V','E')
- #define WAV_FMT COMPOSE_ID('f','m','t',' ')
- #define WAV_DATA COMPOSE_ID('d','a','t','a')
- /* WAVE fmt block constants from Microsoft mmreg.h header */
- #define WAV_FMT_PCM 0x0001
- #define WAV_FMT_IEEE_FLOAT 0x0003
- #define WAV_FMT_DOLBY_AC3_SPDIF 0x0092
- #define WAV_FMT_EXTENSIBLE 0xfffe
- /* Used with WAV_FMT_EXTENSIBLE format */
- #define WAV_GUID_TAG "/x00/x00/x00/x00/x10/x00/x80/x00/x00/xAA/x00/x38/x9B/x71"
- /* it's in chunks like .voc and AMIGA iff, but my source say there
- are in only in this combination, so I combined them in one header;
- it works on all WAVE-file I have
- */
- typedefstruct WAVHeader {
- uint32_t magic; /* 'RIFF' */
- uint32_t length; /* filelen */
- uint32_t type; /* 'WAVE' */
- } WAVHeader_t;
- typedefstruct WAVFmt {
- uint32_t magic; /* 'FMT '*/
- uint32_t fmt_size; /* 16 or 18 */
- uint16_t format; /* see WAV_FMT_* */
- uint16_t channels;
- uint32_t sample_rate; /* frequence of sample */
- uint32_t bytes_p_second;
- uint16_t blocks_align; /* samplesize; 1 or 2 bytes */
- uint16_t sample_length; /* 8, 12 or 16 bit */
- } WAVFmt_t;
- typedefstruct WAVFmtExtensible {
- WAVFmt_t format;
- uint16_t ext_size;
- uint16_t bit_p_spl;
- uint32_t channel_mask;
- uint16_t guid_format; /* WAV_FMT_* */
- uint8_t guid_tag[14]; /* WAV_GUID_TAG */
- } WAVFmtExtensible_t;
- typedefstruct WAVChunkHeader {
- uint32_t type; /* 'data' */
- uint32_t length; /* samplecount */
- } WAVChunkHeader_t;
- typedefstruct WAVContainer {
- WAVHeader_t header;
- WAVFmt_t format;
- WAVChunkHeader_t chunk;
- } WAVContainer_t;
- int WAV_ReadHeader(int fd, WAVContainer_t *container);
- int WAV_WriteHeader(int fd, WAVContainer_t *container);
- #endif /* #ifndef __WAV_PARSER_H */
- //File : wav_parser.c
- //Author : Loon <[email protected]>
- #include <assert.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include "wav_parser.h"
- #define WAV_PRINT_MSG
- char *WAV_P_FmtString(uint16_t fmt)
- {
- switch (fmt) {
- case WAV_FMT_PCM:
- return"PCM";
- break;
- case WAV_FMT_IEEE_FLOAT:
- return"IEEE FLOAT";
- break;
- case WAV_FMT_DOLBY_AC3_SPDIF:
- return"DOLBY AC3 SPDIF";
- break;
- case WAV_FMT_EXTENSIBLE:
- return"EXTENSIBLE";
- break;
- default:
- break;
- }
- return"NON Support Fmt";
- }
- void WAV_P_PrintHeader(WAVContainer_t *container)
- {
- printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++/n");
- printf("/n");
- printf("File Magic: [%c%c%c%c]/n",
- (char)(container->header.magic),
- (char)(container->header.magic>>8),
- (char)(container->header.magic>>16),
-
(char
相關推薦
基於ALSA的WAV播放和錄音程式
這段時間在探索ALSA架構,從ALSA Core到ALSA Lib,再到Android Audio System。在看ALSA Lib時,寫了一個比較典型的基於ALSA的播放錄音程式。程式包包含四個部分: WAV Parser是對WAV檔案的分析和封裝,
win10 插入16k采樣的耳機無法播放和錄音的問題定位
解決辦法 疑難問題 問題 采樣率 解決辦法。 聲音 了解 增強 沒有 平時做智能耳機,需要經常在windows上測試不同采樣率的聲音信號。可是,最近在16k雙聲道輸入的情況下, 無論系統都使用該耳機進行播放,該問題思索了好久,一直沒有解決辦法。 今天無意中使用了wi
MFC 聲音的播放和錄音的實現(一)
程式設計中經常會又到播放聲音的操作,現總結一下在MFC中關於聲音有關的問題。這一篇介紹一下播放聲音的操作。下一篇介紹一下錄音操作的實現。 (一)呼叫Windows API函式實現聲音的播放 VC++
小程式列表視訊控制播放和設定封面與標題
程式碼主要實現視訊列表中當播放當前視訊需要點選下一個的時候,上一個視訊關閉,點選視訊播放上一個視訊並顯示封面和標題(回到當初的面貌) 1.wxml檔案 注:這裡我沒有寫for迴圈,列舉三個表達下效果。myVideo1可以代表為傳過來的視訊id {{ index == 1
微信小程式音訊相關問題:播放,錄音等相關
wx.startRecord(OBJECT) 開始錄音。當主動呼叫wx.stopRecord,或者錄音超過1分鐘時自動結束錄音,返回錄音檔案的臨時檔案路徑。當用戶離開小程式時,此介面無法呼叫。 wx.stopRecord() 主動呼叫停止錄音。 wx.
【MFC-8】VS2010更改基於對話方塊的MFC程式標題欄圖示和生產的執行檔案的圖示
一、開發環境 1、VS2010; 2、C++ / MFC; 二、更改步驟 1)建立一個新工程,可以什麼都不加。開啟“資源檢視”, 右鍵點選專案名稱,選擇“新增資源”,匯入“Icon”資原始檔(事先準備好); 2)修改上一步加入的“Icon”資源屬性ID為“IDI_IC
MFC播放聲音和錄音的實現(三)
上一篇通過Win32控制檯程式簡單地完成了聲音的錄取和回放,但是這個過程都只是是在記憶體中進行的,沒有進行檔案的操作,這樣錄取的聲音也就無法儲存。這一篇介紹一下用MFC實現錄音並生成wave檔案,最後儲存到指定的目錄的方法。 新建一個MFC對話方塊應用程式,命名為Voice
【OpenCV】基於libvlc SDK和Opencv播放rtsp流
RTST流:使用vlc作為rtsp伺服器 vlc2.1.2 VS2013+OpenCV3.0 C++ 1、編譯時記得匯入vlc 的vlc.dll、vlccore.dll和plugins資料夾,這些可
【Alsa】播放聲音和錄音詳細流程
不用 數字信號 一個 放音 fcc 根據 dma 時間 int linux中,無論是oss還是alsa體系,錄音和放音的數據流必須分析清楚。先分析alsa驅動層,然後關聯到alsa庫層和應用層。 二,鏈接分析: 1)鏈路一 usr/src/linux-source-3
ssh2項目整合 struts2.1+hibernate3.3+spring3 基於hibernate註解和struts2註解
模塊 port aware -- ids tle des 項目 @service 項目文件夾結構例如以下: 核心配置文件: web.xml <?xml version="1.0" encoding="UTF-8"
Nginx基於用戶名和密碼的訪問控制
密碼 nginx 用戶名 1 安裝相關包yum install -y httpd-tools2 創建校驗文件htpasswd -cb /etc/nginx/.htpasswd user1 ‘passwd1‘ chown nginx:nginx /etc/nginx/.htpasswd chmod
基於正則和叠代模式的計算器源碼
pre 默認參數 utf-8 nco 退出 spl pan ner imp 源碼如下: 1 # encoding:utf-8 2 # Author:"richie" 3 # Date:2017/8/8 4 import re 5 # 待處理數據 6 s =
基於梯度場和Hessian特征值分別獲得圖像的方向場
htm name tar 我們 值範圍 con tco png mali 一、?我們想要求的方向場的定義為:對於任意一點(x,y),該點的方向可以定義為其所在脊線(或谷線)位置的切線方向與水平軸之間的夾角:將一條直線順時針或逆時針旋轉 180°,直線的方向保持不變。因此,指
mp4格式-播放和斷點續播
環保 margin ont width center span ces mp4格式 false video 標簽(autopaly自動播放屬性) <video id="videoPlay" class="video" autoplay="autoplay
基於gin框架和jwt-go中間件實現小程序用戶登陸和token驗證
expires 微信 處理 如果 .net local 切入點 小程序 err 本文核心內容是利用jwt-go中間件來開發golang webapi用戶登陸模塊的token下發和驗證,小程序登陸功能只是一個切入點,這套邏輯同樣適用於其他客戶端的登陸處理。 小程序登陸邏輯
Android視頻播放和橫豎屏切換
相關信息 fonts android systemui video rap profile ase home 最近做了一個項目,裏面用到了視頻播放這一塊,當時想考慮Vitamio,demo也做了出來,但是後來發現它是商業收費的,並且收費相當可觀,所以只能放棄了。然後
【轉】Red5流服務器搭建(實現在線直播,流媒體視頻播放和在線視頻會議)
htm tps 實現 gho 共享 麥克風 一個 編碼工具 localhost 來自:http://blog.csdn.net/sunroyi666/article/details/52981639 一. 先介紹一下流媒體技術:所謂流媒體技術,是指將連續的影像和聲音信息經過
基於Orangpi Zero和Linux ALSA實現WIFI無線音箱(二)
memfree 線程 取數據 edit 這一 緩沖 一起 說了 cpp 作品已經完成,先上源碼: https://files.cnblogs.com/files/qzrzq1/WIFISpeaker.zip 全文包含三篇,這是第二篇,主要講述發送端程序的原理和過程。 第一篇
基於Orangpi Zero和Linux ALSA實現WIFI無線音箱(三)
http 和源 cal 快速實現 播放音樂 lis 類型 ive 此外 作品已經完成,先上源碼: https://files.cnblogs.com/files/qzrzq1/WIFISpeaker.zip 全文包含三篇,這是第三篇,主要講述接收端程序的原理和過程。 第一篇
kvm的Pool創建基於physical disk 和一些問題
CentOS-7.2 最近幾天遇到physical disk創建pool的問題,主要集中在centos7.2 1.一個是基於mbr的分區,因為小於2GB,然後磁盤上的標識是dos。在virt-manager裏,首先是創建pool,遇到問題,具體的忘記了。然後用cli創建,成功後不穩定,然後在創建