導航:首頁 > 操作系統 > android開發播放聲音

android開發播放聲音

發布時間:2023-09-06 08:47:04

android開發中如何實現播放聲音時根據聲音大小做一個動態能量條

音量變化是比較頻繁的,通常是低於50毫秒。

所以你取得的音量大小是一條密集的點組成的曲線,要動態的展示這些密集的點,有兩種不同的實現方式,效果也不一致。

  1. 把這些點分成不同的區間。比如5個區間,每個區間對應一張圖片(也可以是動態的圖片AnimationDrawable),取得音量後判斷是哪個區間,設置對應的圖片。打個比方,如果是用格數來表示,就有五張圖片表示1-5格,音量最大值可以通過mediaRecorder.getMaxAmplitude()獲得。分成五個區間,每個區間顯示對應格數的圖片。當然,這個圖片也可以是類似水波在盪漾的動態圖片,用AnimationDrawable來播放。

  2. 平滑的處理這些點。把上一次的位置與這一次的位置做一個動畫,如果採集頻率為50毫秒,動畫的ration就是50ms。比如是做一個圓圈,隨著音量大小變化,那麼可以參照如下的屬性動畫:

    PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("scaleX", lastScale, scale);

    PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleY", lastScale, scale);

    valumeAnimator = ObjectAnimator.ofPropertyValuesHolder(speakVolumeImageV, pvhX, pvhY);

    valumeAnimator.setDuration(MIN_TIME).start();


    通過放大和縮小speakVolumeImageV來展示當前音量。其中scale是此次的縮放比,lastScale是上次的縮放比。縮放比初始為1.0f,如果最大隻能放大到speakVolumeImageV的兩倍大,那麼可以這樣計算


    Float scale = 1.0f;

    if (volume == 0) {

    scale = 1.0f;

    } else {

    scale = 1.0f + (volume / MAX_VOLUME * 1.0f);

    }

㈡ Android音頻播放

最近需要在Android的客戶端中使用PCM聲音播放和錄制,簡單學習了一下。有不正確的地方還請指出。

首先有幾個概念需要了解一下:采樣頻率、聲道數、采樣位數。

采樣頻率一般是sample rate, 代表的是數字化音頻時每秒采樣的次數。常見的有44.1KHz(CD品質)、48KHz等。

這個很好理解,單聲道Mono就是聲音從一個方向傳出來;雙聲道Stereo也叫立體聲,聲音是從兩個方向傳來。通常的流行音樂中,仔細聽能發現每個聲道可能側重不同的樂曲聲部,比如左聲道吉他,右聲道鋼琴,人聲似乎兩個聲道都有,聽起來就像站在中間一樣。(這里沒有考證,隨便舉例)

每一個采樣都是一個數據點,采樣位數是指這個數據點使用了幾位來記錄。AudioTrack類只支持8位和16位的PCM音頻。8位就是2的8次方,即256個值;而16位則是2的16次方,有65536個值。

這個在音頻的編解碼中還是比較常用的。在PCM格式中,1秒鍾音頻的數據大小是SampleRate×Channel×Bit/8,單位是byte位元組。由於PCM本身沒有音頻幀的概念,所以通過這個公式就能計算出任意時長音頻的大小,或者得到任意大小音頻的時長。如果規定1個音頻幀是「每個聲道256個采樣」,雙聲道下就是512個采樣,那麼1幀的數據量就是256×Channel×Bit/8,同理可以推斷出1秒鍾有多少音頻幀等等。音頻幀的概念在各種編解碼中各有不同,但計算公式大同小異,這里不展開。

Android中音頻的播放使用的是AudioTrack類,具體用法非常簡單。
首先設置buffer大小。AudioTrack播放時需要先寫入buffer,如果這個buffer沒有寫滿,那麼這部分是不會播放的。所以buffer不能設置太小,這樣會導致播放不連貫;而buffer也不能設置太小,這樣不間斷寫入會消耗許多CPU資源。AudioTrack自帶了getMinBufferSize方法可以給出一個最小buffer,一般用這個值就可以。getMinBufferSize方法三個參數分別是sample rate、channel和bit。

設置完buffer size就可以實例化一個AudioTrack。其中第一個參數streamType是指不同的音頻流類型,包括STREAM_MUSIC、STREAM_ALARM、STREAM_VOICE_CALL、STREAM_RING等,是Android對不同音頻的分類。中間三個參數很好理解,第四個是buffer size,剛剛計算出來了。最後一個參數mode有兩種:MODE_STREAM和MODE_STATIC。前者是以流形式播放,後者則是一次性全部寫入然後播放。

調用實例的play()方法就可以開始播放了。不過播放得要有數據吧?要填寫數據就要用到write()方法。write方法中第一個參數是一個byte[]類型,是要寫入的數據源,可以是從文件流中讀取出來的;第二個參數offset是初始位移,即從source的哪個位置開始;第三個參數則是輸入長度。

當write方法寫滿一個AudioTrack的buffer時,就會有聲音播放出來了。
當播放完成後記得要把AudioTrack停止並釋放。

㈢ Android音視頻【八】音頻基礎

前些文章講了視頻,我們開始音頻。

開始介紹前,先看一個聲音的波形圖:

聲音是一種壓力波,當敲擊鍵盤或者撞擊物體時,它們的震動會引起空氣的震動,使空氣產生疏密變化,由此就形成了一種聲波。

聲波的三要素是頻率、振幅、和波形,頻率代表音階的高低,振幅代表響度,波形代表音色。

頻率 : 頻率 越高,波長越短,低頻聲響的波長則越長,所以更容易越過障礙物,能量衰減就小,聲音傳播的就遠。反之則會得到相反的結論。

振幅:用不同的力度敲擊物體,它的聲音大小不一樣,它的能量也不一樣,聲音越大振幅越高。

波形/音色: 音色就是在同樣的頻率(音調)和響度(振幅)下,敲擊鍵盤或者撞擊物體是完全不同的。波的形狀代表了聲音的音色。

如何進行聲音進行保存呢? 對聲音的采樣常用麥克風等設備將聲音信號轉換成電信號,再用模/數轉換器將電信號轉換成一串用1和0表示的二進制數字(數字信號)。每秒對聲音采樣上萬次,獲得上萬個按照時間順序排列的二進制數字,然後將連續變化不斷的聲音轉化成了計算機可儲存並識別的二進制數字。

為了將模擬信號數字化,需要進行:采樣,量化,編碼。

首先要對模擬信號進行采樣,所謂采樣就是在時間軸上對信號進行數字化。根據奈奎斯特定理(也稱采樣定理),按比聲音最高頻率高 2 倍以上的頻率對聲音進行采樣,對於高質量的音頻信號,其頻率范圍在 20Hz ~ 20kHz ,所以采樣頻率一般為 44.1kHz ,這樣就保證采樣聲音達到 20kHz 也能被數字化,從而使得經過數字化處理之後,人耳聽到的聲音質量不會被降低。而所謂的 44.1 kHz 就是代表 1 s 會采樣 44100 次。

每個采樣又該如何表示呢?進行量化。量化是指在幅度軸上對信號進行數字化。量化位數越大,聲音的質量越高。常用的量化位數有8位、16位和32位。量化位數指用幾位二進制數來存儲采樣獲得的數據。量化位數為8即指用8位二進制數來存儲數據,如0001011

比如用 16 bit 的二進制信號來表示聲音的一個采樣,而 16 bit 所表示的范圍是 [-32768 , 32767] , 共有 65536 個可能取值,因此最終模擬的音頻信號在幅度上也分為了 65536 層。

編碼,就是按照一定的格式記錄采樣和量化後的數字數據,比如順序存儲或壓縮存儲等等。

這里涉及了很多種格式,通常所說的音頻的裸數據就是 PCM (Pulse Code Molation) 數據。描述一段 PCM 數據一般需要以下幾個概念:量化格式(sampleFormat)、采樣率(sampleRate)、聲道數 (channel) 。以 CD 的音質為例:量化格式為 16 bit (2 byte),采樣率 44100 ,聲道數為 2 ,這些信息就描述了 CD 的音質。而對於聲音的格式,還有一個概念用來描述它的大小,稱為數據比特率,即 1s 時間內的比特數目,它用於衡量音頻數據單位時間內的容量大小。而對於 CD 音質的數據,比特率為多少呢? 計算如下:

那麼在一分鍾里,這類 CD 音質的數據需要佔據多大的存儲空間呢?計算如下:

當然,如果 sampleFormat 更加精確 (比如用 4 個位元組來描述一個采樣),或者 sampleRate 更加密集 (比如 48kHz 的采樣率), 那麼所佔的存儲空間就會更大,同時能夠描述的聲音細節就會越精確。存儲的這段二進制數據即表示將模擬信號轉為數字信號了,以後就可以對這段二進制數據進行存儲,播放,復制,或者進行其它操作。

關於這3個過程,可以看下這篇文章,圖形表示采樣,量化,編碼的過程更容易理解。 https://www.bilibili.com/read/cv1771961/

所以說:

1)采樣:在時間軸上對信號數字化;

2)量化:在幅度軸上對信號數字化;

3)編碼:按一定格式記錄采樣和量化後的數字數據。

聲道(sound channel)是指聲音在錄制或播放時在不同空間位置採集或回放的相互獨立的音頻信號,所以聲道數也就是聲音錄制時的聲音源數量或者回放時相應的揚聲器數量。

常見的有:單聲道,立體聲道,4聲道,5.1聲道,7.1聲道等。在移動端一般是單聲道,立體聲道。

上面提到了 CD 音質的數據采樣格式,曾計算出每分鍾需要的存儲空間約為 10.09 MB ,如果僅僅是將其存儲在光碟或者硬碟中,可能是可以接受的,但是若要在網路中實時在線傳輸的話,那麼這個數據量可能就太大了,所以必須對其進行壓縮編碼。壓縮編碼的基本指標之一就是壓縮比,壓縮比通常小於 1 。壓縮演算法包括有損壓縮和無損壓縮。無損壓縮是指解壓後的數據可以完全復原。在常用的壓縮格式中,用的較多的是有損壓縮,有損壓縮是指解壓後的數據不能完全恢復,會丟失一部分信息,壓縮比越小,丟失的信息就比越多,信號還原後的失真就會越大。根據不同的應用場景 (包括存儲設備、傳輸網路環境、播放設備等),可以選用不同的壓縮編碼演算法,如 PCM 、WAV、AAC 、MP3 、Ogg 等。

WAV 編碼就是在 PCM 數據格式的前面加了 44 個位元組,分別用來存儲 PCM 的采樣率、聲道數、數據格式等信息。

特點: 音質好,大量軟體支持。

場景: 多媒體開發的中間文件、保存音樂和音效素材。

MP3 具有不錯的壓縮比,使用 LAME 編碼 (MP3 編碼格式的一種實現)的中高碼率的 MP3 文件,聽感上非常接近源 WAV 文件,當然在不同的應用場景下,應該調整合適的參數以達到最好的效果。

特點: 音質在 128 Kbit/s 以上表現還不錯,壓縮比比較高,大量軟體和硬體都支持,兼容性好。

場景: 高比特率下對兼容性有要求的音樂欣賞。

AAC 是新一代的音頻有損壓縮技術,它通過一些附加的編碼技術(比如 PS 、SBR) 等,衍生出了 LC-AAC 、HE-AAC 、HE-AAC v2 三種主要的編碼格式。LC-AAC 是比較傳統的 AAC ,相對而言,其主要應用於中高碼率場景的編碼 (>=80Kbit/s) ; HE-AAC 相當於 AAC + SBR 主要應用於中低碼率的編碼 (<= 80Kbit/s); 而新推出的 HE-AAC v2 相當於 AAC + SBR + PS 主要用於低碼率場景的編碼 (<= 48Kbit/s) 。事實上大部分編碼器都設置為 <= 48Kbit/s 自動啟用 PS 技術,而 > 48Kbit/s 則不加 PS ,相當於普通的 HE-AAC。

特點: 在小於 128Kbit/s 的碼率下表現優異,並且多用於視頻中的音頻編碼。

場景: 128 Kbit/s 以下的音頻編碼,多用於視頻中音頻軌的編碼。

Ogg 是一種非常有潛力的編碼,在各種碼率下都有比較優秀的表現,尤其是在中低碼率場景下。Ogg 除了音質好之外,還是完全免費的,這為 Ogg 獲得更多的支持打好了基礎,Ogg 有著非常出色的演算法,可以用更小的碼率達到更好的音質,128 Kbit/s 的 Ogg 比 192kbit/s 甚至更高碼率的 MP3 還要出色。但是目前因為還沒有媒體服務軟體的支持,因此基於 Ogg 的數字廣播還無法實現。Ogg 目前受支持的情況還不夠好,無論是軟體上的還是硬體上的支持,都無法和 MP3 相提並論。

特點: 可以用比 MP3 更小的碼率實現比 MP3 更好的音質,高中低碼率下均有良好的表現,兼容性不夠好,流媒體特性不支持。

場景: 語言聊天的音頻消息場景。

壓縮編碼的原理實際上就是壓縮調冗餘信號,冗餘信號是指哪些不能被人感知到的信號,包含人耳聽覺范圍之外的音頻信號以及被屏蔽掉的音頻信號等,這些冗餘信息進行編碼處理。

一般在音視頻通話,直播中,短視頻,以及大部分的視頻都是用aac編碼。

本篇主要是介紹了音頻的一些基礎知識和概念,對於後續學習音頻的編解碼有幫助,而不會一臉懵。

備注

㈣ android音視頻開發一安卓常用API

Android SDK 提供了兩套音頻採集的API,分別是:MediaRecorder 和 AudioRecord,前者是一個更加上層一點的API,它可以直接把手機麥克風錄入的音頻數據進行編碼壓縮(如AMR、MP3等)並存成文件,而後者則更接近底層,能夠更加自由靈活地控制,可以得到原始的一幀幀PCM音頻數據。如果想簡單地做一個錄音機,錄製成音頻文件,則推薦使用 MediaRecorder,而如果需要對音頻做進一步的演算法處理、或者採用第三方的編碼庫進行壓縮、以及網路傳輸等應用,則建議使用 AudioRecord,其實 MediaRecorder 底層也是調用了 AudioRecord 與 Android Framework 層的 AudioFlinger 進行交互的。直播中實時採集音頻自然是要用AudioRecord了。

2.1 播放聲音可以用MediaPlayer和AudioTrack,兩者都提供了java API供應用開發者使用。雖然都可以播放聲音,但兩者還是有很大的區別的。

2.2 其中最大的區別是MediaPlayer可以播放多種格式的聲音文件,例如MP3,AAC,WAV,OGG,MIDI等。MediaPlayer會在framework層創建對應的音頻解碼器。而AudioTrack只能播放已經解碼的PCM流,如果對比支持的文件格式的話則是AudioTrack只支持wav格式的音頻文件,因為wav格式的音頻文件大部分都是PCM流。AudioTrack不創建解碼器,所以只能播放不需要解碼的wav文件。

2.3 MediaPlayer在framework層還是會創建AudioTrack,把解碼後的PCM數流傳遞給AudioTrack,AudioTrack再傳遞給AudioFlinger進行混音,然後才傳遞給硬體播放,所以是MediaPlayer包含了AudioTrack。

2.4 在接觸Android音頻播放API的時候,發現SoundPool也可以用於播放音頻。下面是三者的使用場景:MediaPlayer 更加適合在後台長時間播放本地音樂文件或者在線的流式資源; SoundPool 則適合播放比較短的音頻片段,比如游戲聲音、按鍵聲、鈴聲片段等等,它可以同時播放多個音頻; 而 AudioTrack 則更接近底層,提供了非常強大的控制能力,支持低延遲播放,適合流媒體和VoIP語音電話等場景。

使用 Camera API 採集視頻數據並保存到文件,分別使用 SurfaceView、TextureView 來預覽 Camera 數據,取到 NV21 的數據回調。

4.1 一個音視頻文件是由音頻和視頻組成的,我們可以通過MediaExtractor、MediaMuxer把音頻或視頻給單獨抽取出來,抽取出來的音頻和視頻能單獨播放; 

4.2 MediaMuxer的作用是生成音頻或視頻文件;還可以把音頻與視頻混合成一個音視頻文件。

文獻資料  https://www.cnblogs.com/renhui/p/7452572.html

㈤ 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

閱讀全文

與android開發播放聲音相關的資料

熱點內容
安卓手機快充需要什麼數據線 瀏覽:789
程序中存在未轉換未編譯部分 瀏覽:319
編譯匯編鏈接優化 瀏覽:79
程序員打字和作家哪個打字快 瀏覽:573
安卓手機怎麼用cad命令行 瀏覽:383
2200工程機接收命令瞬間消失 瀏覽:253
壓縮機工藝管是多大的 瀏覽:312
安卓刷什麼系統穩定 瀏覽:35
程序員寫炫酷代碼 瀏覽:930
大話存儲pdf 瀏覽:524
中銘機器人怎麼編程 瀏覽:812
把字母變為數字的加密法 瀏覽:523
噬血狂襲第三季哪個app能看 瀏覽:422
江蘇螺桿壓縮機 瀏覽:980
android底部彈出對話框 瀏覽:502
怎麼查伺服器同行fc號 瀏覽:1000
什麼伺服器雲鳥最便宜 瀏覽:221
vs編譯器反匯編 瀏覽:571
程序員直播做項目創業 瀏覽:403
linux下samba配置 瀏覽:797