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