• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Using SoundPool for Audio Playback
2
3The **SoundPool** class provides APIs to implement low-latency playback of short sounds.
4
5Short sound effects (such as the camera shutter sound effect and system notification sound effect) are often required during application development. You can call the APIs provided by **SoundPool** to implement one-time loading of short sounds and multiple times of low-latency playback.
6
7Currently, the **SoundPool** APIs can be used to play an audio file that is less than 1 MB. If the size of an audio file exceeds 1 MB, 1 MB data is captured and played.
8
9This topic walks you through on how to use the **SoundPool** APIs to implement low-latency playback. For details about the API, see [SoundPool](../reference/apis/js-apis-inner-multimedia-soundPool.md).
10
11The full process includes creating a **SoundPool** instance, loading a sound (including decapsulation and decoding), setting playback parameters (playback rate, loop mode, and priority), playing the sound, stopping the playback, and releasing the instance. (For details about the decoding formats, see [Audio Decoding](audio-decoding.md).)
12
13During application development, you must subscribe to playback state changes and call the APIs in the defined sequence. Otherwise, an exception or undefined behavior may occur.
14
15## How to Develop
16
171. Call **createSoundPool()** to create a **SoundPool** instance.
18
19    ```ts
20    let soundPool: media.SoundPool;
21    media.createSoundPool(5, audioRendererInfo).then((soundpool_: media.SoundPool) => {
22      if (soundpool_ != null) {
23        soundPool = soundpool_;
24        console.info('create SoundPool success');
25      } else {
26        console.error('create SoundPool fail');
27      }
28    }).catch((error) => {
29      console.error(`soundpool catchCallback, error message:${error.message}`);
30    });
31    ```
32
332. Call **load()** to load a sound.
34
35    You can pass in a URI or an FD to load the sound. The following uses the URI as an example. For more methods, see [SoundPool](../reference/apis/js-apis-inner-multimedia-soundPool.md#load).
36
37    ```ts
38    let soundID: number;
39    await fs.open('/test_01.mp3', fs.OpenMode.READ_ONLY).then((file: fs.File) => {
40      console.info("file fd: " + file.fd);
41      uri = 'fd://' + (file.fd).toString()
42    }); // '/test_01.mp3' here is only an example. You need to pass in the actual URI.
43    soundPool.load(uri).then((soundId: number) => {
44      console.info('soundPool load uri success');
45      soundID = soundId;
46    }).catch((err) => {
47      console.error('soundPool load failed and catch error is ' + err.message);
48    });
49    ```
50
513. Call **on('loadComplete')** to listen for the completion of sound loading.
52
53    ```ts
54    soundPool.on('loadComplete', (soundId_: number) => {
55      console.info('loadComplete, soundId: ' + soundId_);
56    })
57    ```
58
594. Call **on('playFinished')** to listen for the completion of sound playing.
60
61    ```ts
62    soundPool.on('playFinished', () => {
63      console.info("recive play finished message");
64    })
65    ```
66
675. Call **on('error')** to listen for errors that may occur.
68
69    ```ts
70    soundPool.on('error', (error) => {
71      console.info('error happened,message is :' + error.message);
72    })
73    ```
74
756. Set the playback parameters and call **play()** to play the sound. If **play()** with the same sound ID passed in is called for multiple times, the sound is played only once.
76
77    ```ts
78    let soundID: number;
79    let streamID: number;
80    let PlayParameters: media.PlayParameters = {
81        loop: number = 0, // The sound does not loop. It is played once.
82        rate: AudioRendererRate = 2, // The sound is played at twice its original frequency.
83        leftVolume: number = 0.5, // range = 0.0-1.0
84        rightVolume: number = 0.5, // range = 0.0-1.0
85        priority: number = 0 // The sound playback has the lowest priority.
86        parallelPlayFlag: boolean = false // The sound is not played in parallel with other active audio streams.
87      }
88    soundPool.play(soundID, PlayParameters, (error, streamId: number) => {
89      if (error) {
90        console.info(`play sound Error: errCode is ${error.code}, errMessage is ${error.message}`)
91      } else {
92        streamID = streamId;
93        console.info('play success soundid:' + streamId);
94      }
95    })
96    ```
97
987. Call **setLoop()** to set the number of loops.
99
100    ```ts
101    let streamID: number;
102    soundPool.setLoop(streamID, 1).then(() => {
103      console.info('setLoop success streamID:' + streamID);
104    }).catch((err) => {
105      console.error('soundpool setLoop failed and catch error is ' + err.message);
106    });
107    ```
108
1098. Call **setPriority()** to set the playback priority.
110
111    ```ts
112    let streamID: number;
113    soundPool.setPriority(streamID, 1);
114    ```
115
1169. Call **setRate()** to set the playback rate.
117
118    ```ts
119    let streamID: number;
120    let selectedAudioRendererRate: audio.AudioRendererRate = audio.AudioRendererRate.RENDER_RATE_NORMAL; // The sound is played at the original frequency.
121    // Call play() to obtain the stream ID.
122
123    soundPool.setRate(streamID, selectedAudioRendererRate).then(() => {
124      console.info('setRate success');
125    }).catch((err) => {
126      console.error('soundpool setRate failed and catch error is ' + err.message);
127    });
128    ```
129
13010. Call **setVolume()** to set the playback volume.
131
132    ```ts
133    let streamID: number;
134    // Call play() to obtain the stream ID.
135
136    soundPool.setVolume(streamID, 0.5, 0.5).then(() => {
137      console.info('setVolume success');
138    }).catch((err) => {
139      console.error('soundpool setVolume failed and catch error is ' + err.message);
140    });
141    ```
142
14311. Call **stop()** to stop the playback.
144
145    ```ts
146    let streamID: number;
147    // Call play() to obtain the stream ID.
148
149    soundPool.stop(streamID).then(() => {
150      console.info('stop success');
151    }).catch((err) => {
152      console.error('soundpool load stop and catch error is ' + err.message);
153    });
154    ```
155
15612. Call **unload()** to unload a sound.
157
158    ```ts
159    let soundID: number;
160    // Call load() to obtain the sound ID.
161
162    soundPool.unload(soundID).then(() => {
163      console.info('unload success');
164    }).catch((err) => {
165      console.error('soundpool unload failed and catch error is ' + err.message);
166    });
167    ```
168
16913. Call **off('loadComplete')** to stop listening for the completion of sound loading.
170
171    ```ts
172    soundPool.off('loadComplete');
173    ```
174
17514. Call **off('playFinished')** to stop listening for the completion of sound playing.
176
177    ```ts
178    soundPool.off('playFinished');
179    ```
180
18115. Call **off('error')** to stop listening for errors.
182
183    ```ts
184    soundPool.off('error');
185    ```
186
18716. Call **release()** to release the **SoundPool** instance.
188
189    ```ts
190    soundPool.release().then(() => {
191      console.info('release success');
192    }).catch((err) => {
193      console.error('soundpool release failed and catch error is ' + err.message);
194    });
195    ```
196
197### Sample Code
198
199The following sample code implements low-latency playback using **SoundPool**.
200
201```ts
202
203import audio from '@ohos.multimedia.audio';
204import media from '@ohos.multimedia.media';
205import fs from '@ohos.file.fs'
206struct Soundpool {
207  private soundPool: media.SoundPool;
208  private streamId: number = 0;
209  private soundId: number = 0;
210  private audioRendererInfo: audio.AudioRendererInfo = {
211    content: audio.ContentType.CONTENT_TYPE_SPEECH,
212    usage: audio.StreamUsage.STREAM_USAGE_MEDIA,
213    rendererFlags: 1
214  }
215  private PlayParameters: media.PlayParameters = {
216    loop: number = 3, // The sound is played four times (three loops).
217    rate: audio.AudioRendererRate = audio.AudioRendererRate.RENDER_RATE_NORMAL, // The sound is played at the original frequency.
218    leftVolume: number = 0.5, // range = 0.0-1.0
219    rightVolume: number = 0.5, // range = 0.0-1.0
220    priority: number = 0 // The sound playback has the lowest priority.
221    parallelPlayFlag: boolean = false // The sound is not played in parallel with other active audio streams.
222  }
223  private uri: string = "";
224  async create(): Promise<void> {
225    // Create a SoundPool instance.
226    this.soundPool = await media.createSoundPool(5, this.audioRendererInfo);
227    // Register listeners.
228    this.loadCallback();
229    this.finishPlayCallback();
230    this.setErrorCallback();
231    // Load a sound.
232    await fs.open('/test_01.mp3', fs.OpenMode.READ_ONLY).then((file: fs.File) => {
233      console.info("file fd: " + file.fd);
234      uri = 'fd://' + (file.fd).toString()
235    }); // '/test_01.mp3' here is only an example. You need to pass in the actual URI.
236    this.soundId = await this.soundPool.load(this.uri);
237  }
238  async loadCallback(): Promise<void> {
239    // Callback invoked when the sound finishes loading.
240    this.soundPool.on('loadComplete', (soundId_: number) => {
241      console.info('loadComplete, soundId: ' + soundId_);
242    })
243  }
244  // Set the listener when the sound finishes playing.
245  async finishPlayCallback(): Promise<void> {
246    // Callback invoked when the sound finishes playing.
247    this.soundPool.on('playFinished', () => {
248      console.info("recive play finished message");
249      // The sound can be played again.
250    })
251  }
252  // Set the listener for errors.
253  setErrorCallback(): void {
254    this.soundPool.on('error', (error) => {
255      console.info('error happened,message is :' + error.message);
256    })
257  }
258  async PlaySoundPool(): Promise<void> {
259    // Start playback. PlayParameters can be carried in the play() API.
260    this.streamId = await this.soundPool.play(this.soundId);
261    // Set the number of loops.
262    this.soundPool.setLoop (this.streamId, 2); // The sound is played three times (two loops).
263    // Set the priority.
264    this.soundPool.setPriority(this.streamId, 1);
265    // Set the playback rate.
266    this.soundPool.setRate(this.streamId, audio.AudioRendererRate.RENDER_RATE_HALF); // The sound is played at half its original frequency.
267    // Set the volume.
268    this.soundPool.setVolume(this.streamId, 0.5, 0.5);
269  }
270  async release(): Promise<void> {
271    // Stop the playback of the stream.
272    this.soundPool.stop(this.streamId);
273    // Unload the sound.
274    await this.soundPool.unload(this.soundId);
275    // Unregister the listeners.
276    this.setOffCallback();
277    // Release the SoundPool instance.
278    await this.soundPool.release();
279  }
280  // Unregister the listeners.
281  setOffCallback() {
282    this.soundPool.off('loadComplete');
283    this.soundPool.off('playFinished');
284    this.soundPool.off('error');
285  }
286}
287```
288