audio-playback.md 12.1 KB
Newer Older
W
wusongqing 已提交
1
# 音频播放开发指导
M
mamingshuai 已提交
2

W
wusongqing 已提交
3
## 场景介绍
M
mamingshuai 已提交
4

W
wusongqing 已提交
5
音频播放的主要工作是将音频数据转码为可听见的音频模拟信号并通过输出设备进行播放,同时对播放任务进行管理。
M
mamingshuai 已提交
6

W
wusongqing 已提交
7
**图1** 音频播放状态机
8

W
wusongqing 已提交
9
![zh-ch_image_audio_state_machine](figures/zh-ch_image_audio_state_machine.png)
10

Z
zengyawen 已提交
11

12

W
wusongqing 已提交
13
**图2** 音频播放零层图
14

W
wusongqing 已提交
15
![zh-ch_image_audio_player](figures/zh-ch_image_audio_player.png)
16

W
wusongqing 已提交
17
## 开发步骤
18

Z
zengyawen 已提交
19
详细API含义可参考:[媒体服务API文档AudioPlayer](../reference/apis/js-apis-media.md)
20

21
### 全流程场景
22

W
wusongqing 已提交
23
包含流程:创建实例,设置uri,播放音频,跳转播放位置,设置音量,暂停播放,获取轨道信息,停止播放,重置,释放资源等流程。
24

W
wusongqing 已提交
25
AudioPlayer支持的src媒体源输入类型可参考:[src属性说明](../reference/apis/js-apis-media.md#audioplayer_属性)
26 27

```js
28 29 30
import media from '@ohos.multimedia.media'
import fileIO from '@ohos.fileio'

31 32 33 34 35 36 37 38 39 40 41
//打印码流轨道信息
function printfDescription(obj) {
    for (let item in obj) {
        let property = obj[item];
        console.info('audio key is ' + item);
        console.info('audio value is ' + property);
    }
}

//设置播放器回调函数
function setCallBack(audioPlayer) {
W
wusongqing 已提交
42
    audioPlayer.on('dataLoad', () => {              //设置'dataLoad'事件回调,src属性设置成功后,触发此回调
43
        console.info('audio set source success');
44
        audioPlayer.play();                         //需等待'dataLoad'事件回调完成后,才可调用play进行播放,触发'play'事件回调
45
    });
W
wusongqing 已提交
46
    audioPlayer.on('play', () => {                  //设置'play'事件回调
47
        console.info('audio play success');
48
        audioPlayer.pause();                        //触发'pause'事件回调,暂停播放
49
    });
W
wusongqing 已提交
50
    audioPlayer.on('pause', () => {                 //设置'pause'事件回调
51
        console.info('audio pause success');
52
        audioPlayer.seek(5000);                     //触发'timeUpdate'事件回调,seek到5000ms处播放
53
    });
W
wusongqing 已提交
54
    audioPlayer.on('stop', () => {                  //设置'stop'事件回调
55
        console.info('audio stop success');
56
        audioPlayer.reset();                        //触发'reset'事件回调后,重新设置src属性,可完成切歌
57
    });
W
wusongqing 已提交
58
    audioPlayer.on('reset', () => {                 //设置'reset'事件回调
59
        console.info('audio reset success');
60 61
        audioPlayer.release();                      //audioPlayer资源被销毁
        audioPlayer = undefined;
62
    });
W
wusongqing 已提交
63
    audioPlayer.on('timeUpdate', (seekDoneTime) => {//设置'timeUpdate'事件回调
64 65
        if (typeof(seekDoneTime) == 'undefined') {
            console.info('audio seek fail');
M
mamingshuai 已提交
66 67
            return;
        }
68
        console.info('audio seek success, and seek time is ' + seekDoneTime);
69
        audioPlayer.setVolume(0.5);                 //触发'volumeChange'事件回调
70
    });
W
wusongqing 已提交
71
    audioPlayer.on('volumeChange', () => {          //设置'volumeChange'事件回调
72
        console.info('audio volumeChange success');
73 74 75 76 77 78 79 80 81 82
        audioPlayer.getTrackDescription((error, arrlist) => {  //通过回调方式获取音频轨道信息
            if (typeof (arrlist) != 'undefined') {
                for (let i = 0; i < arrlist.length; i++) {
                    printfDescription(arrlist[i]);
                }
            } else {
                console.log(`audio getTrackDescription fail, error:${error.message}`);
            }
            audioPlayer.stop();                      //触发'stop'事件回调,停止播放
        });
83
    });
84
    audioPlayer.on('finish', () => {                 //设置'finish'事件回调,播放完成触发
85 86
        console.info('audio play finish');
    });
87
    audioPlayer.on('error', (error) => {             //设置'error'事件回调
88 89 90 91 92 93
        console.info(`audio error called, errName is ${error.name}`);
        console.info(`audio error called, errCode is ${error.code}`);
        console.info(`audio error called, errMessage is ${error.message}`);
    });
}

94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
async function audioPlayerDemo() {
    // 1. 创建实例
    let audioPlayer = media.createAudioPlayer();
    setCallBack(audioPlayer);                          //设置事件回调
    //2. 用户选择音频,设置uri
    let fdPath = 'fd://'
    // path路径的码流可通过"hdc file send D:\xxx\01.mp3 /data/app/el1/bundle/public/ohos.acts.multimedia.audio.audioplayer/ohos.acts.multimedia.audio.audioplayer/assets/entry/resources/rawfile" 命令,将其推送到设备上
    let path = '/data/app/el1/bundle/public/ohos.acts.multimedia.audio.audioplayer/ohos.acts.multimedia.audio.audioplayer/assets/entry/resources/rawfile/01.mp3';
    await fileIO.open(path).then((fdNumber) => {
        fdPath = fdPath + '' + fdNumber;
        console.info('open fd sucess fd is' + fdPath);
    }, (err) => {
        console.info('open fd failed err is' + err);
    }).catch((err) => {
        console.info('open fd failed err is' + err);
    });
    audioPlayer.src = fdPath; //设置src属性,并触发'dataLoad'事件回调
111 112 113
}
```

W
wusongqing 已提交
114
### 正常播放场景
115 116

```js
117 118
import media from '@ohos.multimedia.media'
import fileIO from '@ohos.fileio'
119 120 121
export class AudioDemo {
  // 设置播放器回调函数
  setCallBack(audioPlayer) {
W
wusongqing 已提交
122
    audioPlayer.on('dataLoad', () => {              //设置'dataLoad'事件回调,src属性设置成功后,触发此回调
123 124
      console.info('audio set source success');
      audioPlayer.play();                           //调用play方法开始播放,触发'play'事件回调
125
    });
W
wusongqing 已提交
126
    audioPlayer.on('play', () => {                  //设置'play'事件回调
127
      console.info('audio play success');
128
    });
W
wusongqing 已提交
129
    audioPlayer.on('finish', () => {                //设置'finish'事件回调,播放完成触发
130 131 132
      console.info('audio play finish');
      audioPlayer.release();                        //audioPlayer资源被销毁
      audioPlayer = undefined;
133
    });
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
  }

  async audioPlayerDemo() {
    let audioPlayer = media.createAudioPlayer();     //创建一个音频播放实例
    this.setCallBack(audioPlayer);                   //设置事件回调
    let fdPath = 'fd://'
    // path路径的码流可通过"hdc file send D:\xxx\01.mp3 /data/app/el1/bundle/public/ohos.acts.multimedia.audio.audioplayer/ohos.acts.multimedia.audio.audioplayer/assets/entry/resources/rawfile" 命令,将其推送到设备上
    let path = '/data/app/el1/bundle/public/ohos.acts.multimedia.audio.audioplayer/ohos.acts.multimedia.audio.audioplayer/assets/entry/resources/rawfile/01.mp3';
    await fileIO.open(path).then((fdNumber) => {
      fdPath = fdPath + '' + fdNumber;
      console.info('open fd sucess fd is' + fdPath);
    }, (err) => {
      console.info('open fd failed err is' + err);
    }).catch((err) => {
      console.info('open fd failed err is' + err);
    });
    audioPlayer.src = fdPath; //设置src属性,并触发'dataLoad'事件回调
  }
152
}
153 154
```

W
wusongqing 已提交
155
### 切歌场景
156 157

```js
158 159
import media from '@ohos.multimedia.media'
import fileIO from '@ohos.fileio'
160 161 162 163
export class AudioDemo {
// 设置播放器回调函数
  private isNextMusic = false;
  setCallBack(audioPlayer) {
W
wusongqing 已提交
164
    audioPlayer.on('dataLoad', () => {              //设置'dataLoad'事件回调,src属性设置成功后,触发此回调
165 166
      console.info('audio set source success');
      audioPlayer.play();                           //调用play方法开始播放,触发'play'事件回调
167
    });
W
wusongqing 已提交
168
    audioPlayer.on('play', () => {                  //设置'play'事件回调
169
      console.info('audio play success');
170
      audioPlayer.reset();                          //调用reset方法,触发'reset'事件回调
171
    });
172 173 174 175 176
    audioPlayer.on('reset', () => {                 //设置'reset'事件回调
      console.info('audio play success');
      if (!this.isNextMusic) {                      //当isNextMusic 为false时,实现切歌功能
        this.nextMusic(audioPlayer);                //实现切歌功能
      } else {
W
wusongqing 已提交
177
        audioPlayer.release();                      //audioPlayer资源被销毁
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
        audioPlayer = undefined;
      }
    });
  }

  async nextMusic(audioPlayer) {
    this.isNextMusic = true;
    let nextFdPath = 'fd://'
    // path路径的码流可通过"hdc file send D:\xxx\02.mp3 /data/app/el1/bundle/public/ohos.acts.multimedia.audio.audioplayer/ohos.acts.multimedia.audio.audioplayer/assets/entry/resources/rawfile" 命令,将其推送到设备上
    let nextpath = '/data/app/el1/bundle/public/ohos.acts.multimedia.audio.audioplayer/ohos.acts.multimedia.audio.audioplayer/assets/entry/resources/rawfile/02.mp3';
    await fileIO.open(nextpath).then((fdNumber) => {
      nextFdPath = nextFdPath + '' + fdNumber;
      console.info('open fd sucess fd is' + nextFdPath);
    }, (err) => {
      console.info('open fd failed err is' + err);
    }).catch((err) => {
      console.info('open fd failed err is' + err);
    });
    audioPlayer.src = nextFdPath; //设置src属性,并重新触发触发'dataLoad'事件回调
  }

  async audioPlayerDemo() {
    let audioPlayer = media.createAudioPlayer();       //创建一个音频播放实例
    this.setCallBack(audioPlayer);                     //设置事件回调
    let fdPath = 'fd://'
    // path路径的码流可通过"hdc file send D:\xxx\01.mp3 /data/app/el1/bundle/public/ohos.acts.multimedia.audio.audioplayer/ohos.acts.multimedia.audio.audioplayer/assets/entry/resources/rawfile" 命令,将其推送到设备上
    let path = '/data/app/el1/bundle/public/ohos.acts.multimedia.audio.audioplayer/ohos.acts.multimedia.audio.audioplayer/assets/entry/resources/rawfile/01.mp3';
    await fileIO.open(path).then((fdNumber) => {
      fdPath = fdPath + '' + fdNumber;
      console.info('open fd sucess fd is' + fdPath);
    }, (err) => {
      console.info('open fd failed err is' + err);
    }).catch((err) => {
      console.info('open fd failed err is' + err);
212
    });
213 214
    audioPlayer.src = fdPath; //设置src属性,并触发'dataLoad'事件回调
  }
215 216 217
}
```

W
wusongqing 已提交
218
### 单曲循环场景
219 220

```js
221 222
import media from '@ohos.multimedia.media'
import fileIO from '@ohos.fileio'
223 224 225
export class AudioDemo {
  // 设置播放器回调函数
  setCallBack(audioPlayer) {
W
wusongqing 已提交
226
    audioPlayer.on('dataLoad', () => {              //设置'dataLoad'事件回调,src属性设置成功后,触发此回调
227 228 229
      console.info('audio set source success');
      audioPlayer.loop = true;                      //设置循环播放属性
      audioPlayer.play();                           //调用play方法开始播放,触发'play'事件回调
230
    });
231 232
    audioPlayer.on('play', () => {                  //设置'play'事件回调,开始循环播放
      console.info('audio play success');
233
    });
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
  }

  async audioPlayerDemo() {
    let audioPlayer = media.createAudioPlayer();      //创建一个音频播放实例
    this.setCallBack(audioPlayer);                    //设置事件回调
    let fdPath = 'fd://'
    // path路径的码流可通过"hdc file send D:\xxx\01.mp3 /data/app/el1/bundle/public/ohos.acts.multimedia.audio.audioplayer/ohos.acts.multimedia.audio.audioplayer/assets/entry/resources/rawfile" 命令,将其推送到设备上
    let path = '/data/app/el1/bundle/public/ohos.acts.multimedia.audio.audioplayer/ohos.acts.multimedia.audio.audioplayer/assets/entry/resources/rawfile/01.mp3';
    await fileIO.open(path).then((fdNumber) => {
      fdPath = fdPath + '' + fdNumber;
      console.info('open fd sucess fd is' + fdPath);
    }, (err) => {
      console.info('open fd failed err is' + err);
    }).catch((err) => {
      console.info('open fd failed err is' + err);
249
    });
250 251
    audioPlayer.src = fdPath; //设置src属性,并触发'dataLoad'事件回调
  }
252
}
Z
zengyawen 已提交
253 254 255 256 257 258
```

## 相关实例

针对音频播放开发,有以下相关实例可供参考:

Z
zengyawen 已提交
259
- [`JsDistributedMusicPlayer`:分布式音乐播放(JS)(API7)](https://gitee.com/openharmony/app_samples/tree/master/ability/JsDistributedMusicPlayer)
Z
zengyawen 已提交
260
- [`JsAudioPlayer`:音频播放和管理(JS)(API7)](https://gitee.com/openharmony/app_samples/tree/master/media/JsAudioPlayer)
261
- [`eTsAudioPlayer`: 音频播放器(eTS)](https://gitee.com/openharmony/app_samples/blob/master/media/Recorder/entry/src/main/ets/MainAbility/pages/Play.ets)
Z
zengyawen 已提交
262
- [音频播放器](https://gitee.com/openharmony/codelabs/tree/master/Media/Audio_OH_ETS)