使用AVPlayer開(kāi)發(fā)音頻播放功能

2024-02-16 13:52 更新

使用AVPlayer可以實(shí)現(xiàn)端到端播放原始媒體資源,本開(kāi)發(fā)指導(dǎo)將以完整地播放一首音樂(lè)作為示例,向開(kāi)發(fā)者講解AVPlayer音頻播放相關(guān)功能。

播放的全流程包含:創(chuàng)建AVPlayer,設(shè)置播放資源,設(shè)置播放參數(shù)(音量/倍速/焦點(diǎn)模式),播放控制(播放/暫停/跳轉(zhuǎn)/停止),重置,銷(xiāo)毀資源。

在進(jìn)行應(yīng)用開(kāi)發(fā)的過(guò)程中,開(kāi)發(fā)者可以通過(guò)AVPlayer的state屬性主動(dòng)獲取當(dāng)前狀態(tài)或使用on('stateChange')方法監(jiān)聽(tīng)狀態(tài)變化。如果應(yīng)用在音頻播放器處于錯(cuò)誤狀態(tài)時(shí)執(zhí)行操作,系統(tǒng)可能會(huì)拋出異常或生成其他未定義的行為。

圖1 播放狀態(tài)變化示意圖

狀態(tài)的詳細(xì)說(shuō)明請(qǐng)參考AVPlayerState。當(dāng)播放處于prepared / playing / paused / completed狀態(tài)時(shí),播放引擎處于工作狀態(tài),這需要占用系統(tǒng)較多的運(yùn)行內(nèi)存。當(dāng)客戶(hù)端暫時(shí)不使用播放器時(shí),調(diào)用reset()或release()回收內(nèi)存資源,做好資源利用。

開(kāi)發(fā)步驟及注意事項(xiàng)

詳細(xì)的API說(shuō)明請(qǐng)參考AVPlayer API參考。

  1. 創(chuàng)建實(shí)例createAVPlayer(),AVPlayer初始化idle狀態(tài)。
  2. 設(shè)置業(yè)務(wù)需要的監(jiān)聽(tīng)事件,搭配全流程場(chǎng)景使用。支持的監(jiān)聽(tīng)事件包括:

    事件類(lèi)型

    說(shuō)明

    stateChange

    必要事件,監(jiān)聽(tīng)播放器的state屬性改變。

    error

    必要事件,監(jiān)聽(tīng)播放器的錯(cuò)誤信息。

    durationUpdate

    用于進(jìn)度條,監(jiān)聽(tīng)進(jìn)度條長(zhǎng)度,刷新資源時(shí)長(zhǎng)。

    timeUpdate

    用于進(jìn)度條,監(jiān)聽(tīng)進(jìn)度條當(dāng)前位置,刷新當(dāng)前時(shí)間。

    seekDone

    響應(yīng)API調(diào)用,監(jiān)聽(tīng)seek()請(qǐng)求完成情況。

    當(dāng)使用seek()跳轉(zhuǎn)到指定播放位置后,如果seek操作成功,將上報(bào)該事件。

    speedDone

    響應(yīng)API調(diào)用,監(jiān)聽(tīng)setSpeed()請(qǐng)求完成情況。

    當(dāng)使用setSpeed()設(shè)置播放倍速后,如果setSpeed操作成功,將上報(bào)該事件。

    volumeChange

    響應(yīng)API調(diào)用,監(jiān)聽(tīng)setVolume()請(qǐng)求完成情況。

    當(dāng)使用setVolume()調(diào)節(jié)播放音量后,如果setVolume操作成功,將上報(bào)該事件。

    bufferingUpdate

    用于網(wǎng)絡(luò)播放,監(jiān)聽(tīng)網(wǎng)絡(luò)播放緩沖信息,用于上報(bào)緩沖百分比以及緩存播放進(jìn)度。

    audioInterrupt

    監(jiān)聽(tīng)音頻焦點(diǎn)切換信息,搭配屬性audioInterruptMode使用。

    如果當(dāng)前設(shè)備存在多個(gè)音頻正在播放,音頻焦點(diǎn)被切換(即播放其他媒體如通話(huà)等)時(shí)將上報(bào)該事件,應(yīng)用可以及時(shí)處理。

  3. 設(shè)置資源:設(shè)置屬性u(píng)rl,AVPlayer進(jìn)入initialized狀態(tài)。
    說(shuō)明

    下面代碼示例中的url僅作示意使用,開(kāi)發(fā)者需根據(jù)實(shí)際情況,確認(rèn)資源有效性并設(shè)置:

  4. 準(zhǔn)備播放:調(diào)用prepare(),AVPlayer進(jìn)入prepared狀態(tài),此時(shí)可以獲取duration,設(shè)置音量。
  5. 音頻播控:播放play(),暫停pause(),跳轉(zhuǎn)seek(),停止stop() 等操作。
  6. (可選)更換資源:調(diào)用reset()重置資源,AVPlayer重新進(jìn)入idle狀態(tài),允許更換資源url。
  7. 退出播放:調(diào)用release()銷(xiāo)毀實(shí)例,AVPlayer進(jìn)入released狀態(tài),退出播放。

完整示例

參考以下示例,完整地播放一首音樂(lè)。
  1. import media from '@ohos.multimedia.media';
  2. import fs from '@ohos.file.fs';
  3. import common from '@ohos.app.ability.common';
  4. export class AVPlayerDemo {
  5. private avPlayer;
  6. private count: number = 0;
  7. // 注冊(cè)avplayer回調(diào)函數(shù)
  8. setAVPlayerCallback() {
  9. // seek操作結(jié)果回調(diào)函數(shù)
  10. this.avPlayer.on('seekDone', (seekDoneTime) => {
  11. console.info(`AVPlayer seek succeeded, seek time is ${seekDoneTime}`);
  12. })
  13. // error回調(diào)監(jiān)聽(tīng)函數(shù),當(dāng)avPlayer在操作過(guò)程中出現(xiàn)錯(cuò)誤時(shí)調(diào)用reset接口觸發(fā)重置流程
  14. this.avPlayer.on('error', (err) => {
  15. console.error(`Invoke avPlayer failed, code is ${err.code}, message is ${err.message}`);
  16. this.avPlayer.reset(); // 調(diào)用reset重置資源,觸發(fā)idle狀態(tài)
  17. })
  18. // 狀態(tài)機(jī)變化回調(diào)函數(shù)
  19. this.avPlayer.on('stateChange', async (state, reason) => {
  20. switch (state) {
  21. case 'idle': // 成功調(diào)用reset接口后觸發(fā)該狀態(tài)機(jī)上報(bào)
  22. console.info('AVPlayer state idle called.');
  23. this.avPlayer.release(); // 調(diào)用release接口銷(xiāo)毀實(shí)例對(duì)象
  24. break;
  25. case 'initialized': // avplayer 設(shè)置播放源后觸發(fā)該狀態(tài)上報(bào)
  26. console.info('AVPlayerstate initialized called.');
  27. this.avPlayer.prepare().then(() => {
  28. console.info('AVPlayer prepare succeeded.');
  29. }, (err) => {
  30. console.error(`Invoke prepare failed, code is ${err.code}, message is ${err.message}`);
  31. });
  32. break;
  33. case 'prepared': // prepare調(diào)用成功后上報(bào)該狀態(tài)機(jī)
  34. console.info('AVPlayer state prepared called.');
  35. this.avPlayer.play(); // 調(diào)用播放接口開(kāi)始播放
  36. break;
  37. case 'playing': // play成功調(diào)用后觸發(fā)該狀態(tài)機(jī)上報(bào)
  38. console.info('AVPlayer state playing called.');
  39. if (this.count !== 0) {
  40. console.info('AVPlayer start to seek.');
  41. this.avPlayer.seek(this.avPlayer.duration); //seek到音頻末尾
  42. } else {
  43. this.avPlayer.pause(); // 調(diào)用暫停接口暫停播放
  44. }
  45. this.count++;
  46. break;
  47. case 'paused': // pause成功調(diào)用后觸發(fā)該狀態(tài)機(jī)上報(bào)
  48. console.info('AVPlayer state paused called.');
  49. this.avPlayer.play(); // 再次播放接口開(kāi)始播放
  50. break;
  51. case 'completed': // 播放結(jié)束后觸發(fā)該狀態(tài)機(jī)上報(bào)
  52. console.info('AVPlayer state completed called.');
  53. this.avPlayer.stop(); //調(diào)用播放結(jié)束接口
  54. break;
  55. case 'stopped': // stop接口成功調(diào)用后觸發(fā)該狀態(tài)機(jī)上報(bào)
  56. console.info('AVPlayer state stopped called.');
  57. this.avPlayer.reset(); // 調(diào)用reset接口初始化avplayer狀態(tài)
  58. break;
  59. case 'released':
  60. console.info('AVPlayer state released called.');
  61. break;
  62. default:
  63. console.info('AVPlayer state unknown called.');
  64. break;
  65. }
  66. })
  67. }
  68. // 以下demo為使用fs文件系統(tǒng)打開(kāi)沙箱地址獲取媒體文件地址并通過(guò)url屬性進(jìn)行播放示例
  69. async avPlayerUrlDemo() {
  70. // 創(chuàng)建avPlayer實(shí)例對(duì)象
  71. this.avPlayer = await media.createAVPlayer();
  72. // 創(chuàng)建狀態(tài)機(jī)變化回調(diào)函數(shù)
  73. this.setAVPlayerCallback();
  74. let fdPath = 'fd://';
  75. // 通過(guò)UIAbilityContext獲取沙箱地址filesDir,以下為Stage模型獲方式,如需在FA模型上獲取請(qǐng)參考《訪問(wèn)應(yīng)用沙箱》獲取地址
  76. let context = getContext(this) as common.UIAbilityContext;
  77. let pathDir = context.filesDir;
  78. let path = pathDir + '/01.mp3';
  79. // 打開(kāi)相應(yīng)的資源文件地址獲取fd,并為url賦值觸發(fā)initialized狀態(tài)機(jī)上報(bào)
  80. let file = await fs.open(path);
  81. fdPath = fdPath + '' + file.fd;
  82. this.avPlayer.url = fdPath;
  83. }
  84. // 以下demo為使用資源管理接口獲取打包在HAP內(nèi)的媒體資源文件并通過(guò)fdSrc屬性進(jìn)行播放示例
  85. async avPlayerFdSrcDemo() {
  86. // 創(chuàng)建avPlayer實(shí)例對(duì)象
  87. this.avPlayer = await media.createAVPlayer();
  88. // 創(chuàng)建狀態(tài)機(jī)變化回調(diào)函數(shù)
  89. this.setAVPlayerCallback();
  90. // 通過(guò)UIAbilityContext的resourceManager成員的getRawFd接口獲取媒體資源播放地址
  91. // 返回類(lèi)型為{fd,offset,length},fd為HAP包fd地址,offset為媒體資源偏移量,length為播放長(zhǎng)度
  92. let context = getContext(this) as common.UIAbilityContext;
  93. let fileDescriptor = await context.resourceManager.getRawFd('01.mp3');
  94. // 為fdSrc賦值觸發(fā)initialized狀態(tài)機(jī)上報(bào)
  95. this.avPlayer.fdSrc = fileDescriptor;
  96. this.isSeek = false; // 不支持seek操作
  97. }
  98. }
以上內(nèi)容是否對(duì)您有幫助:
在線(xiàn)筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)