HarmonyOS音訊開發指導:使用AudioRenderer開發音訊播放功能
AudioRenderer是音訊渲染器,用於播放PCM(Pulse Code Modulation)音訊資料,相比AVPlayer而言,可以在輸入前新增資料預處理,更適合有音訊開發經驗的開發者,以實現更靈活的播放功能。
開發指導
使用AudioRenderer播放音訊涉及到AudioRenderer例項的建立、音訊渲染引數的配置、渲染的開始與停止、資源的釋放等。本開發指導將以一次渲染音訊資料的過程為例,向開發者講解如何使用AudioRenderer進行音訊渲染,建議搭配 AudioRenderer的API說明閱讀。
下圖展示了AudioRenderer的狀態變化,在建立例項後,呼叫對應的方法可以進入指定的狀態實現對應的行為。需要注意的是在確定的狀態執行不合適的方法可能導致AudioRenderer發生錯誤,建議開發者在呼叫狀態轉換的方法前進行狀態檢查,避免程式執行產生預期以外的結果。
為保證UI執行緒不被阻塞,大部分AudioRenderer呼叫都是非同步的。對於每個API均提供了callback函式和Promise函式,以下示例均採用callback函式。
圖1 AudioRenderer狀態變化示意圖
在進行應用開發的過程中,建議開發者透過on('stateChange')方法訂閱AudioRenderer的狀態變更。因為針對AudioRenderer的某些操作,僅在音訊播放器在固定狀態時才能執行。如果應用在音訊播放器處於錯誤狀態時執行操作,系統可能會丟擲異常或生成其他未定義的行為。
● prepared狀態: 透過呼叫createAudioRenderer()方法進入到該狀態。
● running狀態: 正在進行音訊資料播放,可以在prepared狀態透過呼叫start()方法進入此狀態,也可以在paused狀態和stopped狀態透過呼叫start()方法進入此狀態。
● paused狀態: 在running狀態可以透過呼叫pause()方法暫停音訊資料的播放並進入paused狀態,暫停播放之後可以透過呼叫start()方法繼續音訊資料播放。
● stopped狀態: 在paused/running狀態可以透過stop()方法停止音訊資料的播放。
● released狀態: 在prepared、paused、stopped等狀態,使用者均可透過release()方法釋放掉所有佔用的硬體和軟體資源,並且不會再進入到其他的任何一種狀態了。
開發步驟及注意事項
1. 配置音訊渲染引數並建立AudioRenderer例項,音訊渲染引數的詳細資訊可以檢視 AudioRendererOptions 。
import audio from '@ohos.multimedia.audio'; let audioStreamInfo = { samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_44100, channels: audio.AudioChannel.CHANNEL_1, sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW }; let audioRendererInfo = { content: audio.ContentType.CONTENT_TYPE_SPEECH, usage: audio.StreamUsage.STREAM_USAGE_VOICE_COMMUNICATION, rendererFlags: 0 }; let audioRendererOptions = { streamInfo: audioStreamInfo, rendererInfo: audioRendererInfo }; audio.createAudioRenderer(audioRendererOptions, (err, data) => { if (err) { console.error(`Invoke createAudioRenderer failed, code is ${err.code}, message is ${err.message}`); return; } else { console.info('Invoke createAudioRenderer succeeded.'); let audioRenderer = data; } });
2. 呼叫start()方法進入running狀態,開始渲染音訊。
audioRenderer.start((err) => { if (err) { console.error(`Renderer start failed, code is ${err.code}, message is ${err.message}`); } else { console.info('Renderer start success.'); } });
3. 指定待渲染檔案地址,開啟檔案呼叫write()方法向緩衝區持續寫入音訊資料進行渲染播放。如果需要對音訊資料進行處理以實現個性化的播放,在寫入之前操作即可。
const bufferSize = await audioRenderer.getBufferSize(); let file = fs.openSync(filePath, fs.OpenMode.READ_ONLY); let buf = new ArrayBuffer(bufferSize); let readsize = await fs.read(file.fd, buf); let writeSize = await new Promise((resolve, reject) => { audioRenderer.write(buf, (err, writeSize) => { if (err) { reject(err); } else { resolve(writeSize); } }); });
4. 呼叫stop()方法停止渲染。
audioRenderer.stop((err) => { if (err) { console.error(`Renderer stop failed, code is ${err.code}, message is ${err.message}`); } else { console.info('Renderer stopped.'); } });
5. 呼叫release()方法銷燬例項,釋放資源。
audioRenderer.release((err) => { if (err) { console.error(`Renderer release failed, code is ${err.code}, message is ${err.message}`); } else { console.info('Renderer released.'); } });
完整示例
下面展示了使用AudioRenderer渲染音訊檔案的示例程式碼。
import audio from '@ohos.multimedia.audio'; import fs from '@ohos.file.fs'; const TAG = 'AudioRendererDemo'; export default class AudioRendererDemo { private renderModel = undefined; private audioStreamInfo = { samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // 取樣率 channels: audio.AudioChannel.CHANNEL_2, // 通道 sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // 取樣格式 encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // 編碼格式 } private audioRendererInfo = { content: audio.ContentType.CONTENT_TYPE_MUSIC, // 媒體型別 usage: audio.StreamUsage.STREAM_USAGE_MEDIA, // 音訊流使用型別 rendererFlags: 0 // 音訊渲染器標誌 } private audioRendererOptions = { streamInfo: this.audioStreamInfo, rendererInfo: this.audioRendererInfo } // 初始化,建立例項,設定監聽事件 init() { audio.createAudioRenderer(this.audioRendererOptions, (err, renderer) => { // 建立AudioRenderer例項 if (!err) { console.info(`${TAG}: creating AudioRenderer success`); this.renderModel = renderer; this.renderModel.on('stateChange', (state) => { // 設定監聽事件,當轉換到指定的狀態時觸發回撥 if (state == 2) { console.info('audio renderer state is: STATE_RUNNING'); } }); this.renderModel.on('markReach', 1000, (position) => { // 訂閱markReach事件,當渲染的幀數達到1000幀時觸發回撥 if (position == 1000) { console.info('ON Triggered successfully'); } }); } else { console.info(`${TAG}: creating AudioRenderer failed, error: ${err.message}`); } }); } // 開始一次音訊渲染 async start() { let stateGroup = [audio.AudioState.STATE_PREPARED, audio.AudioState.STATE_PAUSED, audio.AudioState.STATE_STOPPED]; if (stateGroup.indexOf(this.renderModel.state) === -1) { // 當且僅當狀態為prepared、paused和stopped之一時才能啟動渲染 console.error(TAG + 'start failed'); return; } await this.renderModel.start(); // 啟動渲染 const bufferSize = await this.renderModel.getBufferSize(); let context = getContext(this); let path = context.filesDir; const filePath = path + '/test.wav'; // 使用沙箱路徑獲取檔案,實際路徑為/data/storage/el2/base/haps/entry/files/test.wav let file = fs.openSync(filePath, fs.OpenMode.READ_ONLY); let stat = await fs.stat(filePath); let buf = new ArrayBuffer(bufferSize); let len = stat.size % bufferSize === 0 ? Math.floor(stat.size / bufferSize) : Math.floor(stat.size / bufferSize + 1); for (let i = 0; i < len; i++) { let options = { offset: i * bufferSize, length: bufferSize }; let readsize = await fs.read(file.fd, buf, options); // buf是要寫入緩衝區的音訊資料,在呼叫AudioRenderer.write()方法前可以進行音訊資料的預處理,實現個性化的音訊播放功能,AudioRenderer會讀出寫入緩衝區的音訊資料進行渲染 let writeSize = await new Promise((resolve, reject) => { this.renderModel.write(buf, (err, writeSize) => { if (err) { reject(err); } else { resolve(writeSize); } }); }); if (this.renderModel.state === audio.AudioState.STATE_RELEASED) { // 如果渲染器狀態為released,停止渲染 fs.close(file); await this.renderModel.stop(); } if (this.renderModel.state === audio.AudioState.STATE_RUNNING) { if (i === len - 1) { // 如果音訊檔案已經被讀取完,停止渲染 fs.close(file); await this.renderModel.stop(); } } } } // 暫停渲染 async pause() { // 只有渲染器狀態為running的時候才能暫停 if (this.renderModel.state !== audio.AudioState.STATE_RUNNING) { console.info('Renderer is not running'); return; } await this.renderModel.pause(); // 暫停渲染 if (this.renderModel.state === audio.AudioState.STATE_PAUSED) { console.info('Renderer is paused.'); } else { console.error('Pausing renderer failed.'); } } // 停止渲染 async stop() { // 只有渲染器狀態為running或paused的時候才可以停止 if (this.renderModel.state !== audio.AudioState.STATE_RUNNING && this.renderModel.state !== audio.AudioState.STATE_PAUSED) { console.info('Renderer is not running or paused.'); return; } await this.renderModel.stop(); // 停止渲染 if (this.renderModel.state === audio.AudioState.STATE_STOPPED) { console.info('Renderer stopped.'); } else { console.error('Stopping renderer failed.'); } } // 銷燬例項,釋放資源 async release() { // 渲染器狀態不是released狀態,才能release if (this.renderModel.state === audio.AudioState.STATE_RELEASED) { console.info('Renderer already released'); return; } await this.renderModel.release(); // 釋放資源 if (this.renderModel.state === audio.AudioState.STATE_RELEASED) { console.info('Renderer released'); } else { console.error('Renderer release failed.'); } } }
當同優先順序或高優先順序音訊流要使用輸出裝置時,當前音訊流會被中斷,應用可以自行響應中斷事件並做出處理。具體的音訊併發處理方式可參考 多音訊播放的併發策略。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70009402/viewspace-2990452/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- HarmonyOS音訊開發指導:使用OpenSL ES開發音訊播放功能音訊
- Android 音視訊開發 - 使用AudioTrack播放音訊Android音訊
- iOS開發系列--音訊播放、錄音、視訊播放、拍照、視訊錄製(轉)iOS音訊
- FFmpeg開發筆記(八):ffmpeg解碼音訊並使用SDL同步音訊播放筆記音訊
- openwrt 音訊開發音訊
- 音訊開發之錄製播放pcm檔案音訊
- 微信小遊戲開發(10)-音訊播放遊戲開發音訊
- 【秒懂音視訊開發】12_播放WAV
- HarmonyOS:NativeWindow 開發指導
- Windows 平臺上有許多開源的音訊開發庫,涵蓋了從簡單的音訊播放到複雜的音訊處理和生成。以下是一些常見且功能強大的開源音訊開發庫:Windows音訊
- 【秒懂音視訊開發】08_音訊錄製音訊
- Android 音視訊開發 視訊編碼,音訊編碼格式Android音訊
- 【秒懂音視訊開發】13_音訊重取樣音訊
- FFmpeg開發筆記(十八)FFmpeg相容各種音訊格式的播放筆記音訊
- HarmonyOS 裝置管理開發:USB 服務開發指導
- HarmonyOS電話服務開發指導
- win10自帶音訊播放在哪裡開啟 win10自帶音訊播放怎麼開啟Win10音訊
- 【秒懂音視訊開發】06_重識聲音
- 一個WPF開發的、介面簡潔漂亮的音訊播放器音訊播放器
- iOS AVAudioPlayer(音訊播放)iOS音訊
- android 音訊播放 SoundPoolAndroid音訊
- HarmonyOS 應用事件打點開發指導事件
- 【音視訊安卓開發 (十一)】Android初級開發(一)安卓Android
- 【秒懂音視訊開發】05_Qt開發基礎QT
- 騰訊音樂招 iOS 開發, base 深圳,要求:本科、三年、OC,懂音視訊開發優先。iOS
- 音視訊開發:為什麼推薦使用Jetpack CameraX?Jetpack
- 音視訊開發著作《Android音視訊開發》終於發售了,先來一波簽名送書福利!Android
- 音視訊開發-全網最全常用音視訊編碼和格式彙總
- 【秒懂音視訊開發】09_音訊錄製02_程式設計音訊程式設計
- 【秒懂音視訊開發】02_Windows開發環境搭建Windows開發環境
- 多功能音訊播放器:foobar2000 for mac音訊播放器Mac
- Flutter(十) 音訊+影片播放Flutter音訊
- hqplayer pro 4,音訊播放音訊
- 《音視訊開發進階指南》讀書筆記(一) —— 音視訊基礎概念筆記
- 音視訊技術開發週刊67期
- 音視訊技術開發週刊65期
- 音視訊技術開發週刊56期
- 嵌入式音訊應用開發介紹音訊