audio-playback.md 11.8 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

11 12
**说明**:当前为Idle状态,设置src不会改变状态;且src设置成功后,不能再次设置其它src,需调用reset()接口后,才能重新设置src。

Z
zengyawen 已提交
13

14

W
wusongqing 已提交
15
**图2** 音频播放零层图
16

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

W
wusongqing 已提交
19
## 开发步骤
20

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

23
### 全流程场景
24

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

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

```js
30 31 32
import media from '@ohos.multimedia.media'
import fileIO from '@ohos.fileio'

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);
    }
}

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

96 97 98
async function audioPlayerDemo() {
    // 1. 创建实例
    let audioPlayer = media.createAudioPlayer();
99 100
    setCallBack(audioPlayer); // 设置事件回调
    // 2. 用户选择音频,设置uri
101 102 103 104 105
    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;
JoyboyCZ's avatar
JoyboyCZ 已提交
106
        console.info('open fd success fd is' + fdPath);
107 108 109 110 111
    }, (err) => {
        console.info('open fd failed err is' + err);
    }).catch((err) => {
        console.info('open fd failed err is' + err);
    });
112
    audioPlayer.src = fdPath; // 设置src属性,并触发'dataLoad'事件回调
113 114 115
}
```

W
wusongqing 已提交
116
### 正常播放场景
117 118

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

  async audioPlayerDemo() {
139 140
    let audioPlayer = media.createAudioPlayer(); // 创建一个音频播放实例
    this.setCallBack(audioPlayer); // 设置事件回调
141 142 143 144 145
    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;
JoyboyCZ's avatar
JoyboyCZ 已提交
146
      console.info('open fd success fd is' + fdPath);
147 148 149 150 151
    }, (err) => {
      console.info('open fd failed err is' + err);
    }).catch((err) => {
      console.info('open fd failed err is' + err);
    });
152
    audioPlayer.src = fdPath; // 设置src属性,并触发'dataLoad'事件回调
153
  }
154
}
155 156
```

W
wusongqing 已提交
157
### 切歌场景
158 159

```js
160 161
import media from '@ohos.multimedia.media'
import fileIO from '@ohos.fileio'
162 163 164 165
export class AudioDemo {
// 设置播放器回调函数
  private isNextMusic = false;
  setCallBack(audioPlayer) {
166
    audioPlayer.on('dataLoad', () => { // 设置'dataLoad'事件回调,src属性设置成功后,触发此回调
167
      console.info('audio set source success');
168
      audioPlayer.play(); // 调用play方法开始播放,触发'play'事件回调
169
    });
170
    audioPlayer.on('play', () => { // 设置'play'事件回调
171
      console.info('audio play success');
172
      audioPlayer.reset(); // 调用reset方法,触发'reset'事件回调
173
    });
174
    audioPlayer.on('reset', () => { // 设置'reset'事件回调
175
      console.info('audio play success');
176 177
      if (!this.isNextMusic) { // 当isNextMusic 为false时,实现切歌功能
        this.nextMusic(audioPlayer); // 实现切歌功能
178
      } else {
179
        audioPlayer.release(); // audioPlayer资源被销毁
180 181 182 183 184 185 186 187 188 189 190 191
        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;
JoyboyCZ's avatar
JoyboyCZ 已提交
192
      console.info('open fd success fd is' + nextFdPath);
193 194 195 196 197
    }, (err) => {
      console.info('open fd failed err is' + err);
    }).catch((err) => {
      console.info('open fd failed err is' + err);
    });
198
    audioPlayer.src = nextFdPath; // 设置src属性,并重新触发触发'dataLoad'事件回调
199 200 201
  }

  async audioPlayerDemo() {
202 203
    let audioPlayer = media.createAudioPlayer();       // 创建一个音频播放实例
    this.setCallBack(audioPlayer);                     // 设置事件回调
204 205 206 207 208
    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;
JoyboyCZ's avatar
JoyboyCZ 已提交
209
      console.info('open fd success fd is' + fdPath);
210 211 212 213
    }, (err) => {
      console.info('open fd failed err is' + err);
    }).catch((err) => {
      console.info('open fd failed err is' + err);
214
    });
215
    audioPlayer.src = fdPath; // 设置src属性,并触发'dataLoad'事件回调
216
  }
217 218 219
}
```

W
wusongqing 已提交
220
### 单曲循环场景
221 222

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

  async audioPlayerDemo() {
239 240
    let audioPlayer = media.createAudioPlayer(); // 创建一个音频播放实例
    this.setCallBack(audioPlayer); // 设置事件回调
241 242 243 244 245
    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;
JoyboyCZ's avatar
JoyboyCZ 已提交
246
      console.info('open fd success fd is' + fdPath);
247 248 249 250
    }, (err) => {
      console.info('open fd failed err is' + err);
    }).catch((err) => {
      console.info('open fd failed err is' + err);
251
    });
252
    audioPlayer.src = fdPath; // 设置src属性,并触发'dataLoad'事件回调
253
  }
254
}
Z
zengyawen 已提交
255 256 257 258 259 260
```

## 相关实例

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

261 262 263
- [`JsDistributedMusicPlayer:`分布式音乐播放(JS)(API8)(Full SDK)](https://gitee.com/openharmony/applications_app_samples/tree/master/ability/JsDistributedMusicPlayer)
- [`JsAudioPlayer`:音频播放和管理(JS)(API8)](https://gitee.com/openharmony/applications_app_samples/tree/master/media/JsAudioPlayer)
- [`eTsAudioPlayer`: 音频播放器(eTS)(API8)](https://gitee.com/openharmony/applications_app_samples/blob/master/media/Recorder/entry/src/main/ets/MainAbility/pages/Play.ets)
264
- [音频播放器(eTS)(API9)](https://gitee.com/openharmony/codelabs/tree/master/Media/Audio_OH_ETS)