⑴ iOS Audio Queue播放PCM音頻流
PCM音頻流播放主要步驟如下:
播放PCM音頻流前,我們首先需要確定播放的PCM音頻的格式信息,iOS中,有一個結構體專用於描述音頻格式信息,AudioStreamBasicDescription結構體,組成如下:
我預先錄制好一個PCM文件,根據 https://www.jianshu.com/p/15d95e593451 錄制的音頻文件。
根據我們的PCM文件,我們設置參數如下:
格式確定後我們創建Audio Queue對象,使用如下方法:
參數解釋:
音頻格式填入上一步創建的音頻格式結構體即可,回調函數指針填入後面創建的函數名即可,自定義回調函數數據填入自己需要的對象即可,回調函數的RunLoop和RunLoopMode無特殊要求填寫NULL即使用默認值,保留保留標志位寫0。創建AudioQueueRef對象成功則返回0,失敗則返回其他錯誤值。
創建音頻緩沖區函數如下:
參數解釋:
緩沖區創建數量越少則延遲越小,同時同步要求更高。這里就創建三個即可,可根據自己需求進行調整。
函數的第一個參數為我們創建的AudioQueueRef對象,第二個參數填NULL則代表即可開始,我們填寫NULL即可。函數返回0則代表成功。
我們先從文件中依次循環讀取二進制數據進行填充,填充函數如下:
參數解釋:
inAQ參數填我們剛才創建的AudioQueueRef對象,inNumPacketDescs填0,inPacketDescs填NULL即可。inBuffer則為我們剛才創建的緩沖區對象,對象為結構體,屬性如下:
我們為第二個和第三個屬性賦值即可,根據從文件讀取到的實際值填入即可,不可超過緩沖對象的最大緩存空間。
回調函數類型如下:
第一個參數為自定義的對象,第二個為我們創建的AudioQueueRef對象,第三個為已經處理完畢的AudioQueueBufferRef緩沖區對象。
我們把函數名稱填入第二步的創建函數中的第二個參數即可。
當AudioQueueBufferRef播放完一個緩沖區對象的音頻數據後就會調用回調函數,在回調函數返回已經播放了的緩沖區對象,我們的回調函數裡面處理空的AudioQueueBufferRef對象,為空AudioQueueBufferRef對象重新填充新的數據,並重新調用AudioQueueEnqueueBuffer()函數填充到播放隊列中去。循環調用回調函數,我們依次從文件讀取數據循環填充,即實現播放功能。
當我們需要停止播放時,調用停止的方法即可,方法也非常簡單,如下:
第一個參數為需要停止的AudioQueueRef對象,第二個參數表示是否需要立即停止,我們傳入YES即可。當傳入NO時,該函數會立即返回,但並不立即停止,而是處理完以填充在隊里裡面的緩存區對象後停止,停止為非同步操作;傳入YES時則會立即停止,並等待AudioQueue停止後返回,停止為同步操作。
如果我們有需要也可以在停止後立即重置播放隊列,函數如下:
參數為我們需要重置播放的隊列對象,該方法會重置AudioQueueRef對象,並清空正在播放的緩沖區對象,我們又可以重新開始填充播放新的音頻數據。
最後歡迎大家留言交流,同時附上Demo和文檔地址。
Demo地址: https://github.com/XMSECODE/ESAudioQueueDemo
AudioQueue框架的更詳細的使用及文檔可以查閱蘋果官方文檔: https://developer.apple.com/documentation/audiotoolbox/audio_queue_services
⑵ Android音視頻【十二】使用OpenSLES和AudioTrack進行播放PCM
本節我們學習下如何播放pcm數據,在Android中有兩種方法:一種是使用java層的 AudioTrack 方法,一種是使用底層的 OpenSLES 直接在 jni 層調用系統的 OpenSLES的c方法 實現。
兩種使用場景不一樣:
AudioTrack 一般用於 比如本地播放一個pcm文件/流,又或者播放解碼後的音頻的pcm流,API較簡單。
OpenSLES 一般用於一些播放器中開發中,比如音頻/視頻播放器,聲音/音頻的播放採用的OpenSLES,一是播放器一般是c/c++實現,便於直接在c層調用OpenSLES的API,二也是如果用AudioTrack進行播放,務必會帶來java和jni層的反射調用的開銷,API較復雜。
可以根據業務自行決定來進行選擇。
AudioTrack的方式使用較簡單,直接在java層。
指定采樣率,采樣位數,聲道數進行創建。
其中44100是采樣率, AudioFormat.CHANNEL_OUT_STEREO 為雙聲道,還有 CHANNEL_OUT_MONO 單聲道。 AudioFormat.ENCODING_PCM_16BIT 為采樣位數16位,還有 ENCODING_PCM_8BIT 8位。 minBufferSize 是播放器緩沖的大小,也是根據采樣率和采樣位數,聲道數 進行獲取,只有滿足最小的buffer才去操作底層進程播放。
最後一個參數mode。可以指定的值有 AudioTrack.MODE_STREAM 和 AudioTrack.MODE_STATIC 。
MODE_STREAM 適用於大多數的場景,比如動態的處理audio buffer,或者播放很長的音頻文件,它是將audio buffers從java層傳遞到native層。音頻播放時音頻數據從Java流式傳輸到native層的創建模式。
MODE_STATIC 適用場景,比如播放很短的音頻,它是一次性將全部的音頻資源從java傳遞到native層。音頻數據在音頻開始播放前僅從Java傳輸到native層的創建模式。
是的,就這么一個方法。注意此方法是同步方法,是個耗時方法,一般是開啟一個線程循環調用 write 方法進行寫入。
注意在調用 write 方法前需要調用 audioTrack.play() 方法開始播放。
因為是pcm裸數據,無法像mediaplayer一樣提供了API。所以需要自己處理下。可以利用 getPlaybackHeadPosition 方法。
getPlaybackHeadPosition() 的意思是返回以幀為單位表示的播放頭位置
getPlaybackRate() 的意思是返回以Hz為單位返回當前播放采樣率。
所以當前播放時間可以通過如下方式獲取
OpenSLES:(Open Sound Library for Embedded Systems).
OpenSLES是跨平台是針對嵌入式系統精心優化的硬體音頻加速API。使用OpenSLES進行音頻播放的好處是可以不依賴第三方。比如一些音頻或者視頻播放器中都是用OpenSLES進行播放解碼後的pcm的,這樣免去了和java層的交互。
在Android中使用OpenSLES首先需要把Android 系統提供的so鏈接到外面自己的so。在CMakeLists.txt腳本中添加鏈接庫OpenSLES。庫的名字可以在 類似如下目錄中
需要去掉lib
然後導入頭文件即可使用了OpenSLES提供的底層方法了。
創建&使用的步驟大致分為:
一個 SLObjectItf 裡面可能包含了多個Interface,獲取Interface通過 GetInterface 方法,而 GetInterface 方法的地2個參數 SLInterfaceID 參數來指定到的需要獲取Object裡面的那個Interface。比如通過指定 SL_IID_ENGINE 的類型來獲取 SLEngineItf 。我們可以通過 SLEngineItf 去創建各種Object,例如播放器、錄音器、混音器的Object,然後在用這些Object去獲取各種Interface去實現各種功能。
如上所說,SLEngineItf可以創建混音器的Object。
在創建播放器前需要創建音頻的配置信息(比如采樣率,聲道數,每個采樣的位數等)
開始播放後會不斷的回調這個 pcmBufferCallBack 函數將音頻數據壓入隊列
(*pcmBufferQueue)->RegisterCallback(pcmBufferQueue, pcmBufferCallBack, this);
如果想要暫停播放參數直接設置為SL_PLAYSTATE_PAUSED,若暫停後繼續播放設置參數為SL_PLAYSTATE_PLAYING即可。若想要停止播放參數設置為SL_PLAYSTATE_STOPPED即可。
首先獲取播放器的用於控制音量的介面SLVolumeItf pcmVolumePlay
然後動態設置
首先也是獲取播放器的用於控制音量的介面SLMuteSoloItf pcmMutePlay
然後動態設置
看起來控制還是蠻簡單的哈。先熟悉這么多,OpenSLES還是蠻強大的。
https://github.com/ta893115871/PCMPlay
⑶ google為什麼要開源webrtc
google開源webrtc的理由如下:【點擊免費試用,0成本啟動】
WebRTC(Web Real-Time Communication)項目的最終目的主要是讓Web開發者能夠基於瀏覽器(ChromeFireFox...)輕易快捷開發出豐富的實時多媒體應用,而無需下載安裝任何插件,Web開發者也無需關注多媒體的數字信號處理過程,只需編寫簡單的Javascript程序即可實現,W3C等組織正在制定Javascript 標准API,目前是WebRTC 1.0版本,Draft狀態;另外WebRTC還希望能夠建立一個多互聯網瀏覽器間健壯的實時通信的平台,形成開發者與瀏覽器廠商良好的生態環境。同時,Google也希望和致力於讓WebRTC的技術成為HTML5標准之一,可見Google布局之深遠。
想要了解更多關於webrtc的相關信息,推薦咨詢ZEGO即構科技。公司自成立伊始,就專注自研音視頻引擎,在音頻前處理、網路自適應和跨平台兼容性等方面,達到國際一流水平,同時充分利用基礎雲服務商的能力,構建了MSDN海量有序自學習數據網路,服務覆蓋全球,涵蓋上百個音視頻互動業務場景,單日時長突破30億分鍾。
⑷ PCM 音頻數據使用和處理
什麼是PCM
PCM: PCM(Pulse Code Molation----脈碼調制錄音)。所謂PCM錄音就是將聲音等模擬信號變成符號化的脈沖列,再予以記錄。PCM信號是由[1]
PCM 采樣、位深與碼率
PCM 數據的一些簡單處理
1:計算分貝 音頻數據與大小
2: 采樣轉換
3:位深轉換
⑸ WebRTC 的音頻網路對抗概述
WebRTC 音頻數據處理中,期望可以實現音頻數據處理及傳輸,延時低,互動性好,聲音平穩無抖動,碼率低消耗帶寬少等。在數據傳輸上,WebRTC 採用基於 UDP 的 RTP/RTCP 協議,RTP/RTCP 本身不提供數據的可靠傳輸及質量保障。公共互聯網這種分組交換網路,天然具有數據包傳輸的丟失、重復、亂序及延時等問題。WebRTC 音頻數據處理的這些目標很難同時實現,WebRTC 的音頻網路對抗實現中針對不同情況對這些目標進行平衡。
這里更仔細地看一下 WebRTC 音頻數據處理管線,並特別關注與音頻網路對抗相關的邏輯。
前面在 WebRTC 的音頻數據編碼及發送控制管線 一文中分析了 WebRTC 的音頻數據編碼及發送控制相關邏輯,這里再來看一下 WebRTC 的音頻數據接收及解碼播放過程。
WebRTC 的音頻數據接收處理的概念抽象層面的完整流程大體如下:
對於 WebRTC 的音頻數據接收處理過程, webrtc::AudioDeviceMole 負責把聲音 PCM 數據通過系統介面送進設備播放出來。 webrtc::AudioDeviceMole 內部一般會起專門的播放線程,由播放線程驅動整個解碼播放過程。 webrtc::AudioTransport 作為一個適配和膠水模塊,它把音頻數據播放和 webrtc::AudioProcessing 的音頻數據處理及混音等結合起來,它通過 webrtc::AudioMixer 同步獲取並混音各個遠端音頻流,這些混音之後的音頻數據除了返回給 webrtc::AudioDeviceMole 用於播放外,還會被送進 webrtc::AudioProcessing ,以作為回聲消除的參考信號。 webrtc::AudioMixer::Source / webrtc::AudioReceiveStream 為播放過程提供解碼之後的數據。RTCP 反饋在 webrtc::AudioMixer::Source / webrtc::AudioReceiveStream 中會通過 webrtc::Transport 發送出去。 webrtc::Transport 也是一個適配和膠水模塊,它通過 cricket::MediaChannel::NetworkInterface 實際將數據包發送網路。 cricket::MediaChannel 從網路中接收音頻數據包並送進 webrtc::AudioMixer::Source / webrtc::AudioReceiveStream 。
如果將音頻數據接收處理流水線上的適配和膠水模塊省掉,音頻數據接收處理流水線將可簡化為類似下面這樣:
webrtc::AudioMixer::Source / webrtc::AudioReceiveStream 是整個過程的中心,其實現位於 webrtc/audio/audio_receive_stream.h / webrtc/audio/audio_receive_stream.cc ,相關的類層次結構如下圖:
在 RTC 中,為了實現交互和低延遲,音頻數據接收處理不能只做包的重排序和解碼,它還要充分考慮網路對抗,如 PLC 及發送 RTCP 反饋等,這也是一個相當復雜的過程。WebRTC 的設計大量採用了控制流與數據流分離的思想,這在 webrtc::AudioReceiveStream 的設計與實現中也有體現。分析 webrtc::AudioReceiveStream 的設計與實現時,也可以從配置及控制,和數據流兩個角度來看。
可以對 webrtc::AudioReceiveStream 執行的配置和控制主要有如下這些:
對於數據流,一是從網路中接收到的數據包被送進 webrtc::AudioReceiveStream ;二是播放時, webrtc::AudioDeviceMole 從 webrtc::AudioReceiveStream 獲得解碼後的數據,並送進播放設備播放出來;三是 webrtc::AudioReceiveStream 發送 RTCP 反饋包給發送端以協助實現擁塞控制,對編碼發送過程產生影響。
webrtc::AudioReceiveStream 的實現中,最主要的數據處理流程 —— 音頻數據接收、解碼及播放過程,及相關模塊如下圖:
這個圖中的箭頭表示數據流動的方向,數據在各個模塊中處理的先後順序為自左向右。圖中下方紅色的框中是與網路對抗密切相關的邏輯。
webrtc::AudioReceiveStream 的實現的數據處理流程中,輸入數據為音頻網路數據包和對端發來的 RTCP 包,來自於 cricket::MediaChannel ,輸出數據為解碼後的 PCM 數據,被送給 webrtc::AudioTransport ,以及構造的 RTCP 反饋包,如 TransportCC、RTCP NACK 包,被送給 webrtc::Transport 發出去。
webrtc::AudioReceiveStream 的實現內部,音頻網路數據包最終被送進 NetEQ 的緩沖區 webrtc::PacketBuffer 里,播放時 NetEQ 做解碼、PLC 等,解碼後的數據提供給 webrtc::AudioDeviceMole 。
這里先來看一下, webrtc::AudioReceiveStream 實現的這個數據處理流水線的搭建過程。
webrtc::AudioReceiveStream 實現的數據處理管線是分步驟搭建完成的。我們圍繞上面的 webrtc::AudioReceiveStream 數據處理流程圖 來看這個過程。
在 webrtc::AudioReceiveStream 對象創建,也就是 webrtc::voe::(anonymous namespace)::ChannelReceive 對象創建時,會創建一些關鍵對象,並建立部分對象之間的聯系,這個調用過程如下:
webrtc::AudioReceiveStream 通過 webrtc::Call 創建,傳入 webrtc::AudioReceiveStream::Config,其中包含與 NACK、jitter buffer 最大大小、payload type 與 codec 的映射相關,及 webrtc::Transport 等各種配置。
webrtc::voe::(anonymous namespace)::ChannelReceive 對象的構造函數如下:
webrtc::voe::(anonymous namespace)::ChannelReceive 對象的構造函數的執行過程如下:
圖中標為綠色的模塊為這個階段已經接入 webrtc::voe::(anonymous namespace)::ChannelReceive 的模塊,標為黃色的則為那些還沒有接進來的模塊;實線箭頭表示這個階段已經建立的連接,虛線箭頭則表示還沒有建立的連接。
在 ChannelReceive 的 () 函數中, webrtc::PacketRouter 被接進來:
這個操作也發生在 webrtc::AudioReceiveStream 對象創建期間。 ChannelReceive 的 () 函數的實現如下:
這里 webrtc::PacketRouter 和 webrtc::MoleRtpRtcpImpl2 被連接起來,前面圖中標號為 5 的這條連接也建立起來了。NetEQ 在需要音頻解碼器時創建音頻解碼器,這個過程這里不再贅述。
這樣 webrtc::AudioReceiveStream 內部的數據處理管線的狀態變為如下圖所示:
webrtc::AudioReceiveStream 的生命周期函數 Start() 被調用時, webrtc::AudioReceiveStream 被加進 webrtc::AudioMixer :
這樣 webrtc::AudioReceiveStream 的數據處理管線就此搭建完成。整個音頻數據處理管線的狀態變為如下圖所示:
WebRTC 音頻數據接收處理的實現中,保存從網路上接收的音頻數據包的緩沖區為 NetEQ 的 webrtc::PacketBuffer ,收到音頻數據包並保存進 NetEQ 的 webrtc::PacketBuffer 的過程如下面這樣:
播放時, webrtc::AudioDeviceMole 最終會向 NetEQ 請求 PCM 數據,此時 NetEQ 會從 webrtc::PacketBuffer 中取出數據包並解碼。網路中傳輸的音頻數據包中包含的音頻采樣點和 webrtc::AudioDeviceMole 每次請求的音頻采樣點不一定是完全相同的,比如采樣率為 48kHz 的音頻, webrtc::AudioDeviceMole 每次請求 10ms 的數據,也就是 480 個采樣點,而 OPUS 音頻編解碼器每個編碼幀中包含 20ms 的數據,也就是 960 個采樣點,這樣 NetEQ 返回 webrtc::AudioDeviceMole 每次請求的采樣點之後,可能會有解碼音頻數據的剩餘,這需要一個專門的 PCM 數據緩沖區。這個數據緩沖區為 NetEQ 的 webrtc::SyncBuffer 。
webrtc::AudioDeviceMole 請求播放數據的大體過程如下面這樣:
更加仔細地審視 WebRTC 的音頻數據處理、編碼和發送過程,更完整地將網路對抗考慮進來, WebRTC 的音頻數據處理、編碼和發送過程,及相關模塊如下圖:
在 WebRTC 的音頻數據處理、編碼和發送過程中,編碼器對於網路對抗起著巨大的作用。WebRTC 通過一個名為 audio network adapter (ANA) 的模塊,根據網路狀況,對編碼過程進行調節。
pacing 模塊平滑地將媒體數據發送到網路,擁塞控制 congestion control 模塊通過影響 pacing 模塊來影響媒體數據發送的過程,以達到控制擁塞的目的。
由 WebRTC 的音頻採集、處理、編碼和發送過程,及音頻的接收、解碼、處理及播放過程,可以粗略梳理出 WebRTC 的音頻網路對抗的復雜機制:
沒看到 WebRTC 有音頻帶外 FEC 機制的實現。
參考文章
干貨|一文讀懂騰訊會議在復雜網路下如何保證高清音頻
Done.
⑹ 全民k歌pcm文件怎麼播放
全民k歌pcm文件播放方法:
1、把app的視頻文件下載下來,在手機上找到那個app的文件夾,把下載的pcm格式導出到電腦上。
2、在電腦上下一個pcm格式批量提取器,就可以實現把視頻下載到電腦上用常用的視頻格式給打開了。
⑺ iOS語音對講(三)FFmpeg實時解碼AAC並播放PCM
具體過程如下:
初始化解碼器
解碼AAC,block中返回解碼後的PCM
釋放解碼器
播放PCM使用 AudioQueue ,具體流程:
通過上圖可以得知,Audio Queue的播放流程即是一個 生產者與消費者 的模式:
創建多個Buffer容器,依次填充(生產)Buffer後插入隊列中,開始播放(消費),然後通過回調將消費過的Buffer reuse,循環整個過程。
創建Buffer和Queue,設置參數並開始執行隊列
填充Buffer
在回調中將容器狀態設置為空,用於循環復用
⑻ 如何取出webrtc裡面pcm數據輸出
取出webrtc裡面pcm數據輸出推薦選擇ZEGO即構科技,ZEGO即構科技是一家全球雲通訊服務商,提供優質的服務,為客戶解決所需解決的問題。【點擊免費試用,0成本啟動】
webrtc的語音QoS機制幾乎可以說是行業的標桿,其實現的方式主要融入了三種技術,包括丟包重傳(NACK),前向糾錯(FEC)以及原GIPS公司的網路均衡器(NetEqualizer,簡稱NetEQ)。前兩種都是在犧牲一定成本的前提下,盡最大努力降低丟包率,而NetEQ是在前兩者的基礎上降低延遲、彌補丟包。
想要了解更多關於webrtc的相關信息,推薦咨詢ZEGO即構科技。ZEGO即構科技自主研發的高音質語音視頻引擎,能夠提供實時清晰的多人語音視頻通話。支持多路視頻畫面,保障每一路語音視頻都清晰流暢提供端到端的SDK、分布式轉碼、接入鑒權雲服務接入、擺脫運維、輕松支撐海量用戶運營。
⑼ tts如何拿pcm數據
1. 開始TTS合成.
2. 合成出來第一段PCM數據後調用tts_media_play函數,開始播放,設置callback函數Pcm_play_callback。(在開始播放後,tts_media_play只應被調用一次,後面
3. TTS繼續合成數據,合成完後就放合適大小(
⑽ 播放PCM文件
如果你的mac的參數樣式和我的是一樣的話,那麼執行上面的命令,應該就能正常播放了之前錄制的pcm,如果不是的話,需要你對照自己的mac參數來進行相關處理
在之前執行ffmpeg的時候,已經安裝了SDL,安裝目錄位於/usr/local/Cellar/sdl2
安裝ffmpeg
如果沒有安裝這個目錄,可以執行brew install sdl2
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void showVersion() {
SDL_version version;
SDL_VERSION(&version);
qDebug() << version.major << version.minor << version.patch;
}
void MainWindow::on_playButton_clicked()
{
if (_playThread) { // 停止播放
_playThread->requestInterruption();
_playThread = nullptr;
ui->playButton->setText("開始播放");
} else { // 開始播放
_playThread = new PlayThread(this);
_playThread->start();
// 監聽線程的結束
connect(_playThread, &PlayThread::finished,
this {
_playThread = nullptr;
ui->playButton->setText("開始播放");
});
ui->playButton->setText("停止播放");
}
}
···
然後Run程序,就可以發現成功播放了pcm文件