• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 使用SoundPool开发音频播放功能
2
3使用SoundPool(音频池)提供的接口,可以实现低时延短音播放。
4
5当应用开发时,经常需要使用一些急促简短的音效(如相机快门音效、系统通知音效等),此时建议调用SoundPool,实现一次加载,多次低时延播放。
6
7SoundPool当前支持播放1MB以下的音频资源,大小超过1MB的长音频将截取1MB大小数据进行播放。
8
9本开发指导将以SoundPool进行一次低时延播放音频的过程为例,向开发者讲解如何使用SoundPool。详细的API声明请参考[SoundPool API参考](../reference/apis/js-apis-inner-multimedia-soundPool.md)。
10
11过程包括:创建SoundPool实例,加载音频资源(包括资源的解封装与解码:解码格式参考[音频解码支持](audio-decoding.md#音频解码)),设置播放参数(倍速/循环模式/播放优先级等),播放控制(播放/停止),释放资源。
12
13在应用开发过程中,开发者应通过监听方法检查当前播放状态并按照一定顺序调用接口,执行对应操作,否则系统可能会抛出异常或生成其他未定义的行为。具体顺序可参考下列开发步骤及对应说明。
14
15## 开发步骤及注意事项
16
171. 调用createSoundPool方法创建SoundPool实例。
18
19    ```ts
20    let soundPool: media.SoundPool;
21    let audioRendererInfo: audio.AudioRendererInfo = {
22        content : audio.StreamUsage.STREAM_USAGE_VOICE_COMMUNICATION
23        usage : audio.StreamUsage.STREAM_USAGE_MUSIC,
24        rendererFlags : 1
25    }
26
27    media.createSoundPool(5, audioRendererInfo).then((soundpool_: media.SoundPool) => {
28      if (soundpool_ != null) {
29        soundPool = soundpool_;
30        console.info('create SoundPool success');
31      } else {
32        console.error('create SoundPool fail');
33      }
34    }).catch((error: BusinessError) => {
35      console.error(`soundpool catchCallback, error message:${error.message}`);
36    });
37    ```
38
392. 调用load方法进行音频资源加载。
40    可以传入uri或fd加载资源,此处使用传入uri的方式为例,更多方法请参考[API文档](../reference/apis/js-apis-inner-multimedia-soundPool.md#load)。
41
42    ```ts
43    let soundID: number;
44    await fs.open('/test_01.mp3', fs.OpenMode.READ_ONLY).then((file: fs.File) => {
45      console.info("file fd: " + file.fd);
46      uri = 'fd://' + (file.fd).toString()
47    }); // '/test_01.mp3' 作为样例,使用时需要传入文件对应路径。
48    soundPool.load(uri).then((soundId: number) => {
49      console.info('soundPool load uri success');
50      soundID = soundId;
51    }).catch((err) => {
52      console.error('soundPool load failed and catch error is ' + err.message);
53    });
54    ```
55
563. 调用on('loadComplete')方法,用于监听“资源加载完成”。
57
58    ```ts
59    soundPool.on('loadComplete', (soundId_: number) => {
60      console.info('loadComplete, soundId: ' + soundId_);
61    });
62    ```
63
644. 调用on('playFinished')方法,用于监听“播放完成”。
65
66    ```ts
67    soundPool.on('playFinished', () => {
68      console.info("recive play finished message");
69    });
70    ```
71
725. 调用on('error')方法,设置错误类型监听。
73
74    ```ts
75    soundPool.on('error', (error) => {
76      console.info('error happened,message is :' + error.message);
77    });
78    ```
79
806. 配置播放参数PlayParameters,并调用play方法播放音频。多次调用play播放同一个soundID,只会播放一次。
81
82    ```ts
83    let soundID: number;
84    let streamID: number;
85    let playParameters: media.PlayParameters = {
86        loop = 0, // 循环0次
87        rate = 2, // 2倍速
88        leftVolume = 0.5, // range = 0.0-1.0
89        rightVolume = 0.5, // range = 0.0-1.0
90        priority = 0, // 最低优先级
91        parallelPlayFlag: boolean = false // 不和其它正在播放的音频并行播放
92      }
93    soundPool.play(soundID, playParameters, (error: BusinessError, streamId: number) => {
94      if (error) {
95        console.info(`play sound Error: errCode is ${error.code}, errMessage is ${error.message}`)
96      } else {
97        streamID = streamId;
98        console.info('play success soundid:' + streamId);
99      }
100    });
101    ```
102
1037. 调用setLoop方法设置循环次数。
104
105    ```ts
106    let streamID: number;
107    soundPool.setLoop(streamID, 1).then(() => {
108      console.info('setLoop success streamID:' + streamID);
109    }).catch((err: BusinessError) => {
110      console.error('soundpool setLoop failed and catch error is ' + err.message);
111    });
112    ```
113
1148. 调用setPriority方法设置优先级。
115
116    ```ts
117    let streamID: number;
118    soundPool.setPriority(streamID, 1);
119    ```
120
1219. 调用setRate方法设置播放倍速。
122
123    ```ts
124    let streamID: number;
125    let selectedAudioRendererRate: audio.AudioRendererRate = audio.AudioRendererRate.RENDER_RATE_NORMAL; // 默认正常速率
126    // 先调用play方法获取到对应资源的streamID
127
128    soundPool.setRate(streamID, selectedAudioRendererRate).then(() => {
129      console.info('setRate success');
130    }).catch((err: BusinessError) => {
131      console.error('soundpool setRate failed and catch error is ' + err.message);
132    });
133    ```
134
13510. 调用setVolume方法设置音量。
136
137    ```ts
138    let streamID: number;
139    // 先调用play方法获取到对应资源的streamID
140
141    soundPool.setVolume(streamID, 0.5, 0.5).then(() => {
142      console.info('setVolume success');
143    }).catch((err: BusinessError) => {
144      console.error('soundpool setVolume failed and catch error is ' + err.message);
145    });
146    ```
147
14811. 调用stop方法终止指定流的播放。
149
150    ```ts
151    let streamID: number;
152    //先调用play方法给拿到对应的streamID
153
154    soundPool.stop(streamID).then(() => {
155      console.info('stop success');
156    }).catch((err: BusinessError) => {
157      console.error('soundpool load stop and catch error is ' + err.message);
158    });
159    ```
160
16112. 调用unload方法卸载音频资源。
162
163    ```ts
164    let soundID: number;
165    // 先调用load方法获取到对应资源的soundID
166
167    soundPool.unload(soundID).then(() => {
168      console.info('unload success');
169    }).catch((err: BusinessError) => {
170      console.error('soundpool unload failed and catch error is ' + err.message);
171    });
172    ```
173
17413. 调用off('loadComplete')方法注销加载完成监听。
175
176    ```ts
177    soundPool.off('loadComplete');
178    ```
179
18014. 调用off('playFinished')方法注销播放完成监听。
181
182    ```ts
183    soundPool.off('playFinished');
184    ```
185
18615. 调用off('error')方法注销错误错误类型监听。
187
188    ```ts
189    soundPool.off('error');
190    ```
191
19216. 调用release方法释放SoundPool实例。
193
194    ```ts
195    soundPool.release().then(() => {
196      console.info('release success');
197    }).catch((err: BusinessError) => {
198      console.error('soundpool release failed and catch error is ' + err.message);
199    });
200    ```
201
202### 完整示例
203
204下面展示了使用SoundPool进行低时延播放的完整示例代码。
205
206```ts
207
208import audio from '@ohos.multimedia.audio';
209import media from '@ohos.multimedia.media';
210import fs from '@ohos.file.fs'
211struct Soundpool {
212  private soundPool: media.SoundPool;
213  private streamId: number = 0;
214  private soundId: number = 0;
215  private audioRendererInfo: audio.AudioRendererInfo = {
216    content: audio.ContentType.CONTENT_TYPE_SPEECH,
217    usage: audio.StreamUsage.STREAM_USAGE_MEDIA,
218    rendererFlags: 1
219  }
220  private PlayParameters: media.PlayParameters = {
221    loop: number = 3, // 循环4次
222    rate: audio.AudioRendererRate = audio.AudioRendererRate.RENDER_RATE_NORMAL, // 正常倍速
223    leftVolume: number = 0.5, // range = 0.0-1.0
224    rightVolume: number = 0.5, // range = 0.0-1.0
225    priority: number = 0, // 最低优先级
226    parallelPlayFlag: boolean = false // 不和其它正在播放的音频并行播放
227  }
228  private uri: string = "";
229  async create(): Promise<void> {
230    //创建soundPool实例
231    this.soundPool = await media.createSoundPool(5, this.audioRendererInfo);
232    //注册监听
233    this.loadCallback();
234    this.finishPlayCallback();
235    this.setErrorCallback();
236    // 加载音频资源
237    await fs.open('/test_01.mp3', fs.OpenMode.READ_ONLY).then((file: fs.File) => {
238      console.info("file fd: " + file.fd);
239      this.uri = 'fd://' + (file.fd).toString()
240    }); // '/test_01.mp3' 作为样例,使用时需要传入文件对应路径。
241    this.soundId = await this.soundPool.load(this.uri);
242  }
243  async loadCallback(): Promise<void> {
244    // 加载完成回调
245    this.soundPool.on('loadComplete', (soundId_: number) => {
246      console.info('loadComplete, soundId: ' + soundId_);
247    })
248  }
249  //设置播放完成监听
250  async finishPlayCallback(): Promise<void> {
251    // 播放完成回调
252    this.soundPool.on('playFinished', () => {
253      console.info("recive play finished message");
254      // 可进行下次播放
255    })
256  }
257  //设置错误类型监听
258  setErrorCallback(): void {
259    this.soundPool.on('error', (error) => {
260      console.info('error happened,message is :' + error.message);
261    })
262  }
263  async PlaySoundPool(): Promise<void> {
264    // 开始播放,这边play也可带播放播放的参数PlayParameters
265    this.streamId = await this.soundPool.play(this.soundId);
266    // 设置循环播放次数
267    this.soundPool.setLoop(this.streamId, 2); // 播放3次
268    // 设置对应流的优先级
269    this.soundPool.setPriority(this.streamId, 1);
270    // 设置播放倍速
271    this.soundPool.setRate(this.streamId, audio.AudioRendererRate.RENDER_RATE_HALF); // 半倍速播放
272    // 设置音量
273    this.soundPool.setVolume(this.streamId, 0.5, 0.5);
274  }
275  async release(): Promise<void> {
276    // 终止指定流的播放
277    this.soundPool.stop(this.streamId);
278    // 卸载音频资源
279    await this.soundPool.unload(this.soundId);
280    //关闭监听
281    this.setOffCallback();
282    // 释放SoundPool
283    await this.soundPool.release();
284  }
285  //关闭监听
286  setOffCallback() {
287    this.soundPool.off('loadComplete');
288    this.soundPool.off('playFinished');
289    this.soundPool.off('error');
290  }
291}
292```
293