HarmonyOS音頻模塊支持音頻業(yè)務的開發(fā),提供音頻相關的功能,主要包括音頻播放、音頻采集、音量管理和短音播放等。
基本概念
- 采樣 采樣是指將連續(xù)時域上的模擬信號按照一定的時間間隔采樣,獲取到離散時域上離散信號的過程。
- 采樣率 采樣率為每秒從連續(xù)信號中提取并組成離散信號的采樣次數(shù),單位用赫茲(Hz)來表示。通常人耳能聽到頻率范圍大約在20Hz~20kHz之間的聲音。常用的音頻采樣頻率有:8kHz、11.025kHz、22.05kHz、16kHz、37.8kHz、44.1kHz、48kHz、96kHz、192kHz等。
- 聲道 聲道是指聲音在錄制或播放時在不同空間位置采集或回放的相互獨立的音頻信號,所以聲道數(shù)也就是聲音錄制時的音源數(shù)量或回放時相應的揚聲器數(shù)量。
- 音頻幀 音頻數(shù)據(jù)是流式的,本身沒有明確的幀的概念,在實際的應用中,為了音頻算法處理/傳輸?shù)姆奖?,一般約定俗成取2.5ms~60ms為單位的數(shù)據(jù)量為一幀音頻。這個時間被稱之為“采樣時間”,其長度沒有特別的標準,它是根據(jù)編解碼器和具體應用的需求來決定的。
- PCM PCM(Pulse Code Modulation),即脈沖編碼調(diào)制,是一種將模擬信號數(shù)字化的方法,是將時間連續(xù)、取值連續(xù)的模擬信號轉換成時間離散、抽樣值離散的數(shù)字信號的過程。
- 短音 使用源于應用程序包內(nèi)的資源或者是文件系統(tǒng)里的文件為樣本,將其解碼成一個16bit單聲道或者立體聲的PCM流并加載到內(nèi)存中,這使得應用程序可以直接用壓縮數(shù)據(jù)流同時擺脫CPU加載數(shù)據(jù)的壓力和播放時重解壓的延遲。
- tone音 根據(jù)特定頻率生成的波形,比如撥號盤的聲音。
- 系統(tǒng)音 系統(tǒng)預置的短音,比如按鍵音,刪除音等。
約束與限制
- 在使用完AudioRenderer音頻播放類和AudioCapturer音頻采集類后,需要調(diào)用release()方法進行資源釋放。
- 音頻采集所使用的最終采樣率與采樣格式取決于輸入設備,不同設備支持的格式及采樣率范圍不同,可以通過AudioManager類的getDevices接口查詢。
- 該功能使用需要對應硬件支持,僅支持真機調(diào)試。
- 在進行開發(fā)之前,需要申請相關權限,保證應用使用音頻相關能力的權限,涉及權限如下表。
權限名 |
說明 |
---|---|
ohos.permission.MICROPHONE |
允許應用使用麥克風進行錄音。 |
ohos.permission.READ_MEDIA |
允許應用讀取用戶外部存儲中的媒體文件信息。 |
ohos.permission.WRITE_MEDIA |
允許應用讀寫用戶外部存儲中的媒體文件信息。 |
音頻播放
場景介紹
音頻播放的主要工作是將音頻數(shù)據(jù)轉碼為可聽見的音頻模擬信號并通過輸出設備進行播放,同時對播放任務進行管理。
接口說明
音頻播放類AudioRenderer的主要接口
接口名 |
描述 |
---|---|
AudioRenderer(AudioRendererInfo audioRendererInfo, PlayMode pm) |
構造函數(shù),設置播放相關音頻參數(shù)和播放模式,使用默認播放設備。 |
AudioRenderer(AudioRendererInfo audioRendererInfo, PlayMode pm, AudioDeviceDescriptor outputDevice) |
構造函數(shù),設置播放相關音頻參數(shù)、播放模式和播放設備。 |
start() |
播放音頻流。 |
write(byte[] data, int offset, int size) |
將音頻數(shù)據(jù)以byte流寫入音頻接收器以進行播放。 |
write(short[] data, int offset, int size) |
將音頻數(shù)據(jù)以short流寫入音頻接收器以進行播放。 |
write?(float[] data, int offset, int size) |
將音頻數(shù)據(jù)以float流寫入音頻接收器以進行播放。 |
write?(java.nio.ByteBuffer data, int size) |
將音頻數(shù)據(jù)以ByteBuffer流寫入音頻接收器以進行播放。 |
pause() |
暫停播放音頻流。 |
stop() |
停止播放音頻流。 |
release() |
釋放播放資源。 |
getCurrentDevice() |
獲取當前工作的音頻播放設備。 |
setPlaybackSpeed(float speed) |
設置播放速度。 |
setPlaybackSpeed?(AudioRenderer.SpeedPara speedPara) |
設置播放速度與音調(diào)。 |
setVolume(ChannelVolume channelVolume) |
設置指定聲道上的輸出音量。 |
setVolume(float vol) |
設置所有聲道上的輸出音量。 |
getMinBufferSize?(int sampleRate, AudioStreamInfo.EncodingFormat format, AudioStreamInfo.ChannelMask channelMask) |
獲取Stream播放模式所需的buffer大小。 |
getState() |
獲取音頻播放的狀態(tài)。 |
getRendererSessionId() |
獲取音頻播放的session ID。 |
getSampleRate() |
獲取采樣率。 |
getPosition() |
獲取音頻播放的幀數(shù)位置。 |
setPosition?(int position) |
設置起始播放幀位置。 |
getRendererInfo?() |
獲取音頻渲染信息。 |
duckVolume?() |
降低音量并將音頻與另一個擁有音頻焦點的應用程序混合。 |
unduckVolume?() |
恢復音量。 |
getPlaybackSpeed() |
獲取播放速度、音調(diào)參數(shù)。 |
setSpeed(SpeedPara speedPara) |
設置播放速度、音調(diào)參數(shù)。 |
getAudioTime() |
獲取播放時間戳信息。 |
flush() |
刷新當前的播放流數(shù)據(jù)隊列。 |
getMaxVolume() |
獲取播放流可設置的最大音量。 |
getMinVolume() |
獲取播放流可設置的最小音量。 |
getStreamType() |
獲取播放流的音頻流類型。 |
開發(fā)步驟
1. 構造音頻流參數(shù)的數(shù)據(jù)結構AudioStreamInfo,推薦使用AudioStreamInfo.Builder類來構造,模板如下,模板中設置的均為AudioStreamInfo.Builder類的默認值,根據(jù)音頻流的具體規(guī)格來設置具體參數(shù)。
AudioStreamInfo audioStreamInfo = new AudioStreamInfo.Builder()
.sampleRate(AudioStreamInfo.SAMPLE_RATE_UNSPECIFIED)
.audioStreamFlag(AudioStreamInfo.AudioStreamFlag.AUDIO_STREAM_FLAG_NONE)
.encodingFormat(AudioStreamInfo.EncodingFormat.ENCODING_INVALID)
.channelMask(AudioStreamInfo.ChannelMask.CHANNEL_INVALID)
.streamUsage(AudioStreamInfo.StreamUsage.STREAM_USAGE_UNKNOWN)
.build();
復制
以真實的播放pcm流為例:
AudioStreamInfo audioStreamInfo = new AudioStreamInfo.Builder().sampleRate(44100) // 44.1kHz
.audioStreamFlag(AudioStreamInfo.AudioStreamFlag.AUDIO_STREAM_FLAG_MAY_DUCK) // 混音
.encodingFormat(AudioStreamInfo.EncodingFormat.ENCODING_PCM_16BIT) // 16-bit PCM
.channelMask(AudioStreamInfo.ChannelMask.CHANNEL_OUT_STEREO) // 雙聲道輸出
.streamUsage(AudioStreamInfo.StreamUsage.STREAM_USAGE_MEDIA) // 媒體類音頻
.build();
復制
2. 使用創(chuàng)建的音頻流構建音頻播放的參數(shù)結構AudioRendererInfo,推薦使用AudioRendererInfo.Builder類來構造,模板如下,模板中設置的均為AudioRendererInfo.Builder類的默認值,根據(jù)音頻播放的具體規(guī)格來設置具體參數(shù)。
AudioRendererInfo audioRendererInfo = new AudioRendererInfo.Builder().audioStreamInfo(audioStreamInfo)
.audioStreamOutputFlag(AudioRendererInfo.AudioStreamOutputFlag.AUDIO_STREAM_OUTPUT_FLAG_NONE)
.bufferSizeInBytes(0)
.isOffload(false)
.sessionID(AudioRendererInfo.SESSION_ID_UNSPECIFIED)
.build();
復制
以真實的播放pcm流為例:
AudioRendererInfo audioRendererInfo = new AudioRendererInfo.Builder().audioStreamInfo(audioStreamInfo)
.audioStreamOutputFlag(AudioRendererInfo.AudioStreamOutputFlag.AUDIO_STREAM_OUTPUT_FLAG_DIRECT_PCM) // pcm格式的輸出流
.bufferSizeInBytes(100)
.isOffload(false) // false表示分段傳輸buffer并播放,true表示整個音頻流一次性傳輸?shù)紿AL層播放
.build();
復制
3. 根據(jù)要播放音頻流指定PlayMode,不同的PlayMode在寫數(shù)據(jù)時存在差異,詳情見步驟7,其余播放流程是無區(qū)別的。并通過構造函數(shù)獲取AudioRenderer類的實例化對象。
4. 使用構造函數(shù)獲取AudioRenderer類的實例化對象,其中步驟2、步驟3中的數(shù)據(jù)為構造函數(shù)的必選參數(shù),指定播放設備為可選參數(shù),根據(jù)使用場景選擇不同的構造函數(shù)。
5. (可選)構造音頻播放回調(diào),首先構造對象AudioInterrupt,其中setInterruptListener方法的入?yún)⑿枰獙崿F(xiàn)接口類InterruptListener,setStreamInfo方法使用步驟1的AudioStreamInfo作為入?yún)ⅰH缓笳{(diào)用AudioManager類的activateAudioInterrupt(AudioInterrupt interrupt)方法進行音頻播放回調(diào)注冊。代碼示例如下:
AudioRenderer renderer = new AudioRenderer(audioRendererInfo, AudioRenderer.PlayMode.MODE_STREAM);
AudioInterrupt audioInterrupt = new AudioInterrupt();
AudioManager audioManager = new AudioManager();
audioInterrupt.setStreamInfo(audioStreamInfo);
audioInterrupt.setInterruptListener(new AudioInterrupt.InterruptListener() {
@Override
public void onInterrupt(int type, int hint) {
if (type == AudioInterrupt.INTERRUPT_TYPE_BEGIN
&& hint == AudioInterrupt.INTERRUPT_HINT_PAUSE) {
renderer.pause();
} else if (type == AudioInterrupt.INTERRUPT_TYPE_BEGIN
&& hint == AudioInterrupt.INTERRUPT_HINT_NONE) {
} else if (type == AudioInterrupt.INTERRUPT_TYPE_END && (
hint == AudioInterrupt.INTERRUPT_HINT_NONE
|| hint == AudioInterrupt.INTERRUPT_HINT_RESUME)) {
renderer.start();
} else {
HiLog.warn(TAG, "unexpected type or hint");
}
}
});
audioManager.activateAudioInterrupt(audioInterrupt);
復制
6.?調(diào)用AudioRenderer實例化對象的start()方法啟動播放任務
AudioRenderer renderer = new AudioRenderer(audioRendererInfo, AudioRenderer.PlayMode.MODE_STREAM);
renderer.start();
復制
7.?將要播放的音頻數(shù)據(jù)讀取為byte流或short流,對于選擇MODE_STREAM模式的PlayMode,需要循環(huán)調(diào)用write方法進行數(shù)據(jù)寫入。對于選擇MODE_STATIC模式的PlayMode,只能通過調(diào)用一次write方法將要播放的音頻數(shù)據(jù)全部寫入,因此該模式限制在文件規(guī)格較小的音頻數(shù)據(jù)播放場景下才能使用
AudioRenderer renderer = new AudioRenderer(audioRendererInfo, AudioRenderer.PlayMode.MODE_STREAM);
String Path = "resources/***/***.pcm"; // 自定義pcm文件
BufferedInputStream bis1 = null;
try {
RawFileDescriptor rawFileDescriptor = getResourceManager().getRawFileEntry(Path).openRawFileDescriptor();
FileDescriptor fileDescriptor1 = rawFileDescriptor.getFileDescriptor();
bis1 = new BufferedInputStream(new FileInputStream(fileDescriptor1));
int minBufferSize = renderer.getMinBufferSize(44100, AudioStreamInfo.EncodingFormat.ENCODING_PCM_16BIT,
AudioStreamInfo.ChannelMask.CHANNEL_OUT_STEREO);
byte[] buffers = new byte[minBufferSize];
while ((bis1.read(buffers)) != -1) {
boolean write1 = renderer.write(buffers, 0, buffers.length);
renderer.flush();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bis1!=null){
try {
bis1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
BufferedInputStream bis2 = null;
try {
RawFileDescriptor rawFileDescriptor = getResourceManager().getRawFileEntry(Path).openRawFileDescriptor();
FileDescriptor fileDescriptor1 = rawFileDescriptor.getFileDescriptor();
bis2 = new BufferedInputStream(new FileInputStream(fileDescriptor1));
int minBufferSize = renderer.getMinBufferSize(44100, AudioStreamInfo.EncodingFormat.ENCODING_PCM_16BIT,
AudioStreamInfo.ChannelMask.CHANNEL_OUT_STEREO);
byte[] buffers = new byte[minBufferSize];
int len ;
while ((len = bis2.read(buffers)) != -1) {
short[] shorts = new short[len];
boolean write2 = renderer.write(shorts, 0, shorts.length);
renderer.flush();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bis2!=null){
try {
bis2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
AudioRenderer renderer1 = new AudioRenderer(audioRendererInfo, AudioRenderer.PlayMode.MODE_STATIC);
String Path1 = "resources/***/***.pcm";
BufferedInputStream bis3 = null;
try {
RawFileDescriptor rawFileDescriptor = getResourceManager().getRawFileEntry(Path1).openRawFileDescriptor();
FileDescriptor fileDescriptor1 = rawFileDescriptor.getFileDescriptor();
bis3 = new BufferedInputStream(new FileInputStream(fileDescriptor1));
byte[] bytes = new byte[bis3.available()];
boolean write3 = renderer1.write(bytes, 0, bytes.length);
} catch (IOException e) {
e.printStackTrace();
}finally {
if (bis3!=null){
try {
bis3.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
BufferedInputStream bis4 = null;
try {
RawFileDescriptor rawFileDescriptor = getResourceManager().getRawFileEntry(Path1).openRawFileDescriptor();
FileDescriptor fileDescriptor1 = rawFileDescriptor.getFileDescriptor();
bis4 = new BufferedInputStream(new FileInputStream(fileDescriptor1));
short[] shorts = new short[bis4.available()];
boolean write4 = renderer1.write(shorts, 0, shorts.length);
} catch (IOException e) {
e.printStackTrace();
}finally {
if (bis4!=null){
try {
bis4.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
復制
8.?(可選)當需要對音頻播放進行暫?;蛲V箷r,調(diào)用AudioRenderer實例化對象的pause()或stop()方法進行暫?;蛲V共シ拧?/p>
AudioRenderer renderer = new AudioRenderer(audioRendererInfo, AudioRenderer.PlayMode.MODE_STREAM);
renderer.pause();
復制
9.?(可選)調(diào)用AudioRenderer實例化對象的setSpeed調(diào)節(jié)播放速度,setVolume調(diào)節(jié)播放音量。
renderer.setSpeed(0.5f);
renderer.setVolume(0.5f);
renderer.stop();
復制
10.?播放任務結束后,調(diào)用AudioRenderer實例化對象的release()釋放資源。
renderer.release();
最后,為了能讓大家更好的去學習提升鴻蒙 (Harmony OS) 開發(fā)技術,小編連夜整理了一份30個G純血版學習資料(含視頻、電子書、學習文檔等)以及一份在Github上持續(xù)爆火霸榜的《純血版華為鴻蒙 (Harmony OS)開發(fā)手冊》(共計890頁),希望對大家有所幫助。
純血版鴻蒙 HarmonyOS 4.0 視頻學習資料
?需要以上視頻學習資料小伙伴
請點擊→純血版全套鴻蒙HarmonyOS學習資料文章來源:http://www.zghlxwxcb.cn/news/detail-821525.html
《純血版華為鴻蒙 (Harmony OS)開發(fā)手冊》
這份手冊涵蓋了當前鴻蒙 (Harmony OS) 開發(fā)技術必掌握的核心知識點
純血版鴻蒙 (Harmony OS)開發(fā)手冊部分精彩內(nèi)容
HarmonyOS 概念:
- 系統(tǒng)定義
- 技術架構
- 技術特性
- 系統(tǒng)安全
如何快速入門?
- 基本概念
- 構建第一個ArkTS應用
- 構建第一個JS應用
- ……
開發(fā)基礎知識:?
- 應用基礎知識
- 配置文件
- 應用數(shù)據(jù)管理
- 應用安全管理
- 應用隱私保護
- 三方應用調(diào)用管控機制
- 資源分類與訪問
- 學習ArkTS語言
- ……
基于ArkTS 開發(fā):
- Ability開發(fā)
- UI開發(fā)
- 公共事件與通知
- 窗口管理
- 媒體
- 安全
- 網(wǎng)絡與鏈接
- 電話服務
- 數(shù)據(jù)管理
- 后臺任務(Background Task)管理
- 設備管理
- 設備使用信息統(tǒng)計
- DFX
- 國際化開發(fā)
- 折疊屏系列
- .……
獲取以上文中提到的這份純血版鴻蒙 (Harmony OS) 開發(fā)資料的小伙伴?
請點擊→純血版全套鴻蒙HarmonyOS學習資料
??寫在最后
- 如果你覺得這篇內(nèi)容對你還蠻有幫助,我想邀請你幫我三個小忙:
- 點贊,轉發(fā),有你們的 『點贊和評論』,才是我創(chuàng)造的動力。
- 關注小編,同時可以期待后續(xù)文章ing??,不定期分享原創(chuàng)知識。
- 想要獲取更多完整鴻蒙最新VIP學習資料,請點擊→純血版全套鴻蒙HarmonyOS學習資料
文章來源地址http://www.zghlxwxcb.cn/news/detail-821525.html
到了這里,關于鴻蒙HarmonyOS開發(fā)實戰(zhàn)—多媒體開發(fā)(音頻開發(fā) 一)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!