1e41f4b71Sopenharmony_ci# Using AudioRenderer for Audio Playback 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ciThe AudioRenderer is used to play Pulse Code Modulation (PCM) audio data. Unlike the [AVPlayer](../media/using-avplayer-for-playback.md), the AudioRenderer can perform data preprocessing before audio input. Therefore, the AudioRenderer is more suitable if you have extensive audio development experience and want to implement more flexible playback features. 4e41f4b71Sopenharmony_ci 5e41f4b71Sopenharmony_ci## Development Guidelines 6e41f4b71Sopenharmony_ci 7e41f4b71Sopenharmony_ciThe full rendering process involves creating an **AudioRenderer** instance, configuring audio rendering parameters, starting and stopping rendering, and releasing the instance. In this topic, you will learn how to use the AudioRenderer to render audio data. Before the development, you are advised to read [AudioRenderer](../../reference/apis-audio-kit/js-apis-audio.md#audiorenderer8) for the API reference. 8e41f4b71Sopenharmony_ci 9e41f4b71Sopenharmony_ciThe figure below shows the state changes of the AudioRenderer. After an **AudioRenderer** instance is created, different APIs can be called to switch the AudioRenderer to different states and trigger the required behavior. If an API is called when the AudioRenderer is not in the given state, the system may throw an exception or generate other undefined behavior. Therefore, you are advised to check the AudioRenderer state before triggering state transition. 10e41f4b71Sopenharmony_ci 11e41f4b71Sopenharmony_ciTo prevent the UI thread from being blocked, most **AudioRenderer** calls are asynchronous. Each API provides the callback and promise functions. The following examples use the callback functions. 12e41f4b71Sopenharmony_ci 13e41f4b71Sopenharmony_ci**Figure 1** AudioRenderer state transition 14e41f4b71Sopenharmony_ci 15e41f4b71Sopenharmony_ci 16e41f4b71Sopenharmony_ci 17e41f4b71Sopenharmony_ciDuring application development, you are advised to use [on('stateChange')](../../reference/apis-audio-kit/js-apis-audio.md#onstatechange-8) to subscribe to state changes of the AudioRenderer. This is because some operations can be performed only when the AudioRenderer is in a given state. If the application performs an operation when the AudioRenderer is not in the given state, the system may throw an exception or generate other undefined behavior. 18e41f4b71Sopenharmony_ci 19e41f4b71Sopenharmony_ci- **prepared**: The AudioRenderer enters this state by calling [createAudioRenderer()](../../reference/apis-audio-kit/js-apis-audio.md#audiocreateaudiorenderer8). 20e41f4b71Sopenharmony_ci 21e41f4b71Sopenharmony_ci- **running**: The AudioRenderer enters this state by calling [start()](../../reference/apis-audio-kit/js-apis-audio.md#start8) when it is in the **prepared**, **paused**, or **stopped** state. 22e41f4b71Sopenharmony_ci 23e41f4b71Sopenharmony_ci- **paused**: The AudioRenderer enters this state by calling [pause()](../../reference/apis-audio-kit/js-apis-audio.md#pause8) when it is in the **running** state. When the audio playback is paused, it can call [start()](../../reference/apis-audio-kit/js-apis-audio.md#start8) to resume the playback. 24e41f4b71Sopenharmony_ci 25e41f4b71Sopenharmony_ci- **stopped**: The AudioRenderer enters this state by calling [stop()](../../reference/apis-audio-kit/js-apis-audio.md#stop8) when it is in the **paused** or **running** state. 26e41f4b71Sopenharmony_ci 27e41f4b71Sopenharmony_ci- **released**: The AudioRenderer enters this state by calling [release()](../../reference/apis-audio-kit/js-apis-audio.md#release8) when it is in the **prepared**, **paused**, or **stopped** state. In this state, the AudioRenderer releases all occupied hardware and software resources and will not transit to any other state. 28e41f4b71Sopenharmony_ci 29e41f4b71Sopenharmony_ci### How to Develop 30e41f4b71Sopenharmony_ci 31e41f4b71Sopenharmony_ci1. Set audio rendering parameters and create an **AudioRenderer** instance. For details about the parameters, see [AudioRendererOptions](../../reference/apis-audio-kit/js-apis-audio.md#audiorendereroptions8). 32e41f4b71Sopenharmony_ci 33e41f4b71Sopenharmony_ci ```ts 34e41f4b71Sopenharmony_ci import { audio } from '@kit.AudioKit'; 35e41f4b71Sopenharmony_ci 36e41f4b71Sopenharmony_ci let audioStreamInfo: audio.AudioStreamInfo = { 37e41f4b71Sopenharmony_ci samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // Sampling rate. 38e41f4b71Sopenharmony_ci channels: audio.AudioChannel.CHANNEL_2, // Channel. 39e41f4b71Sopenharmony_ci sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // Sampling format. 40e41f4b71Sopenharmony_ci encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // Encoding format. 41e41f4b71Sopenharmony_ci }; 42e41f4b71Sopenharmony_ci 43e41f4b71Sopenharmony_ci let audioRendererInfo: audio.AudioRendererInfo = { 44e41f4b71Sopenharmony_ci usage: audio.StreamUsage.STREAM_USAGE_VOICE_COMMUNICATION, 45e41f4b71Sopenharmony_ci rendererFlags: 0 46e41f4b71Sopenharmony_ci }; 47e41f4b71Sopenharmony_ci 48e41f4b71Sopenharmony_ci let audioRendererOptions: audio.AudioRendererOptions = { 49e41f4b71Sopenharmony_ci streamInfo: audioStreamInfo, 50e41f4b71Sopenharmony_ci rendererInfo: audioRendererInfo 51e41f4b71Sopenharmony_ci }; 52e41f4b71Sopenharmony_ci 53e41f4b71Sopenharmony_ci audio.createAudioRenderer(audioRendererOptions, (err, data) => { 54e41f4b71Sopenharmony_ci if (err) { 55e41f4b71Sopenharmony_ci console.error(`Invoke createAudioRenderer failed, code is ${err.code}, message is ${err.message}`); 56e41f4b71Sopenharmony_ci return; 57e41f4b71Sopenharmony_ci } else { 58e41f4b71Sopenharmony_ci console.info('Invoke createAudioRenderer succeeded.'); 59e41f4b71Sopenharmony_ci let audioRenderer = data; 60e41f4b71Sopenharmony_ci } 61e41f4b71Sopenharmony_ci }); 62e41f4b71Sopenharmony_ci ``` 63e41f4b71Sopenharmony_ci 64e41f4b71Sopenharmony_ci2. Call **on('writeData')** to subscribe to the audio data write callback. 65e41f4b71Sopenharmony_ci 66e41f4b71Sopenharmony_ci ```ts 67e41f4b71Sopenharmony_ci import { BusinessError } from '@kit.BasicServicesKit'; 68e41f4b71Sopenharmony_ci import { fileIo } from '@kit.CoreFileKit'; 69e41f4b71Sopenharmony_ci 70e41f4b71Sopenharmony_ci let bufferSize: number = 0; 71e41f4b71Sopenharmony_ci class Options { 72e41f4b71Sopenharmony_ci offset?: number; 73e41f4b71Sopenharmony_ci length?: number; 74e41f4b71Sopenharmony_ci } 75e41f4b71Sopenharmony_ci 76e41f4b71Sopenharmony_ci let path = getContext().cacheDir; 77e41f4b71Sopenharmony_ci // Ensure that the resource exists in the path. 78e41f4b71Sopenharmony_ci let filePath = path + '/StarWars10s-2C-48000-4SW.wav'; 79e41f4b71Sopenharmony_ci let file: fileIo.File = fileIo.openSync(filePath, fileIo.OpenMode.READ_ONLY); 80e41f4b71Sopenharmony_ci 81e41f4b71Sopenharmony_ci let writeDataCallback = (buffer: ArrayBuffer) => { 82e41f4b71Sopenharmony_ci 83e41f4b71Sopenharmony_ci let options: Options = { 84e41f4b71Sopenharmony_ci offset: bufferSize, 85e41f4b71Sopenharmony_ci length: buffer.byteLength 86e41f4b71Sopenharmony_ci } 87e41f4b71Sopenharmony_ci fileIo.readSync(file.fd, buffer, options); 88e41f4b71Sopenharmony_ci bufferSize += buffer.byteLength; 89e41f4b71Sopenharmony_ci } 90e41f4b71Sopenharmony_ci 91e41f4b71Sopenharmony_ci audioRenderer.on('writeData', writeDataCallback); 92e41f4b71Sopenharmony_ci ``` 93e41f4b71Sopenharmony_ci 94e41f4b71Sopenharmony_ci3. Call **start()** to switch the AudioRenderer to the **running** state and start rendering. 95e41f4b71Sopenharmony_ci 96e41f4b71Sopenharmony_ci ```ts 97e41f4b71Sopenharmony_ci import { BusinessError } from '@kit.BasicServicesKit'; 98e41f4b71Sopenharmony_ci 99e41f4b71Sopenharmony_ci audioRenderer.start((err: BusinessError) => { 100e41f4b71Sopenharmony_ci if (err) { 101e41f4b71Sopenharmony_ci console.error(`Renderer start failed, code is ${err.code}, message is ${err.message}`); 102e41f4b71Sopenharmony_ci } else { 103e41f4b71Sopenharmony_ci console.info('Renderer start success.'); 104e41f4b71Sopenharmony_ci } 105e41f4b71Sopenharmony_ci }); 106e41f4b71Sopenharmony_ci ``` 107e41f4b71Sopenharmony_ci 108e41f4b71Sopenharmony_ci4. Call **stop()** to stop rendering. 109e41f4b71Sopenharmony_ci 110e41f4b71Sopenharmony_ci ```ts 111e41f4b71Sopenharmony_ci import { BusinessError } from '@kit.BasicServicesKit'; 112e41f4b71Sopenharmony_ci 113e41f4b71Sopenharmony_ci audioRenderer.stop((err: BusinessError) => { 114e41f4b71Sopenharmony_ci if (err) { 115e41f4b71Sopenharmony_ci console.error(`Renderer stop failed, code is ${err.code}, message is ${err.message}`); 116e41f4b71Sopenharmony_ci } else { 117e41f4b71Sopenharmony_ci console.info('Renderer stopped.'); 118e41f4b71Sopenharmony_ci } 119e41f4b71Sopenharmony_ci }); 120e41f4b71Sopenharmony_ci ``` 121e41f4b71Sopenharmony_ci 122e41f4b71Sopenharmony_ci5. Call **release()** to release the instance. 123e41f4b71Sopenharmony_ci 124e41f4b71Sopenharmony_ci ```ts 125e41f4b71Sopenharmony_ci import { BusinessError } from '@kit.BasicServicesKit'; 126e41f4b71Sopenharmony_ci 127e41f4b71Sopenharmony_ci audioRenderer.release((err: BusinessError) => { 128e41f4b71Sopenharmony_ci if (err) { 129e41f4b71Sopenharmony_ci console.error(`Renderer release failed, code is ${err.code}, message is ${err.message}`); 130e41f4b71Sopenharmony_ci } else { 131e41f4b71Sopenharmony_ci console.info('Renderer released.'); 132e41f4b71Sopenharmony_ci } 133e41f4b71Sopenharmony_ci }); 134e41f4b71Sopenharmony_ci ``` 135e41f4b71Sopenharmony_ci 136e41f4b71Sopenharmony_ci### Selecting the Correct Stream Usage 137e41f4b71Sopenharmony_ci 138e41f4b71Sopenharmony_ciWhen developing a media player, it is important to correctly set the stream usage type according to the intended use case. This will ensure that the player behaves as expected in different scenarios. 139e41f4b71Sopenharmony_ci 140e41f4b71Sopenharmony_ciThe recommended use cases are described in [StreamUsage](../../reference/apis-audio-kit/js-apis-audio.md#streamusage). For example, **STREAM_USAGE_MUSIC** is recommended for music scenarios, **STREAM_USAGE_MOVIE** is recommended for movie or video scenarios, and **STREAM_USAGE_GAME** is recommended for gaming scenarios. 141e41f4b71Sopenharmony_ci 142e41f4b71Sopenharmony_ciAn incorrect configuration of **StreamUsage** may cause unexpected behavior. Example scenarios are as follows: 143e41f4b71Sopenharmony_ci 144e41f4b71Sopenharmony_ci- When **STREAM_USAGE_MUSIC** is incorrectly used in a game scenario, the game cannot be played simultaneously with music applications. However, games usually can coexist with music playback. 145e41f4b71Sopenharmony_ci- When **STREAM_USAGE_MUSIC** is incorrectly used in a navigation scenario, any playing music is interrupted when the navigation application provides audio guidance. However, it is generally expected that the music keeps playing at a lower volume while the navigation is active. 146e41f4b71Sopenharmony_ci 147e41f4b71Sopenharmony_ci### Sample Code 148e41f4b71Sopenharmony_ci 149e41f4b71Sopenharmony_ciRefer to the sample code below to render an audio file using AudioRenderer. 150e41f4b71Sopenharmony_ci 151e41f4b71Sopenharmony_ci```ts 152e41f4b71Sopenharmony_ciimport { audio } from '@kit.AudioKit'; 153e41f4b71Sopenharmony_ciimport { BusinessError } from '@kit.BasicServicesKit'; 154e41f4b71Sopenharmony_ciimport { fileIo } from '@kit.CoreFileKit'; 155e41f4b71Sopenharmony_ci 156e41f4b71Sopenharmony_ciconst TAG = 'AudioRendererDemo'; 157e41f4b71Sopenharmony_ci 158e41f4b71Sopenharmony_ciclass Options { 159e41f4b71Sopenharmony_ci offset?: number; 160e41f4b71Sopenharmony_ci length?: number; 161e41f4b71Sopenharmony_ci} 162e41f4b71Sopenharmony_ci 163e41f4b71Sopenharmony_cilet context = getContext(this); 164e41f4b71Sopenharmony_cilet bufferSize: number = 0; 165e41f4b71Sopenharmony_cilet renderModel: audio.AudioRenderer | undefined = undefined; 166e41f4b71Sopenharmony_cilet audioStreamInfo: audio.AudioStreamInfo = { 167e41f4b71Sopenharmony_ci samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // Sampling rate. 168e41f4b71Sopenharmony_ci channels: audio.AudioChannel.CHANNEL_2, // Channel. 169e41f4b71Sopenharmony_ci sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // Sampling format. 170e41f4b71Sopenharmony_ci encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // Encoding format. 171e41f4b71Sopenharmony_ci} 172e41f4b71Sopenharmony_cilet audioRendererInfo: audio.AudioRendererInfo = { 173e41f4b71Sopenharmony_ci usage: audio.StreamUsage.STREAM_USAGE_MUSIC, // Audio stream usage type. 174e41f4b71Sopenharmony_ci rendererFlags: 0 // AudioRenderer flag. 175e41f4b71Sopenharmony_ci} 176e41f4b71Sopenharmony_cilet audioRendererOptions: audio.AudioRendererOptions = { 177e41f4b71Sopenharmony_ci streamInfo: audioStreamInfo, 178e41f4b71Sopenharmony_ci rendererInfo: audioRendererInfo 179e41f4b71Sopenharmony_ci} 180e41f4b71Sopenharmony_cilet path = getContext().cacheDir; 181e41f4b71Sopenharmony_ci// Ensure that the resource exists in the path. 182e41f4b71Sopenharmony_cilet filePath = path + '/StarWars10s-2C-48000-4SW.wav'; 183e41f4b71Sopenharmony_cilet file: fileIo.File = fileIo.openSync(filePath, fileIo.OpenMode.READ_ONLY); 184e41f4b71Sopenharmony_ci 185e41f4b71Sopenharmony_cilet writeDataCallback = (buffer: ArrayBuffer) => { 186e41f4b71Sopenharmony_ci let options: Options = { 187e41f4b71Sopenharmony_ci offset: bufferSize, 188e41f4b71Sopenharmony_ci length: buffer.byteLength 189e41f4b71Sopenharmony_ci } 190e41f4b71Sopenharmony_ci fileIo.readSync(file.fd, buffer, options); 191e41f4b71Sopenharmony_ci bufferSize += buffer.byteLength; 192e41f4b71Sopenharmony_ci} 193e41f4b71Sopenharmony_ci 194e41f4b71Sopenharmony_ci// Create an AudioRenderer instance, and set the events to listen for. 195e41f4b71Sopenharmony_cifunction init() { 196e41f4b71Sopenharmony_ci audio.createAudioRenderer(audioRendererOptions, (err, renderer) => { // Create an AudioRenderer instance. 197e41f4b71Sopenharmony_ci if (!err) { 198e41f4b71Sopenharmony_ci console.info(`${TAG}: creating AudioRenderer success`); 199e41f4b71Sopenharmony_ci renderModel = renderer; 200e41f4b71Sopenharmony_ci if (renderModel !== undefined) { 201e41f4b71Sopenharmony_ci (renderModel as audio.AudioRenderer).on('writeData', writeDataCallback); 202e41f4b71Sopenharmony_ci } 203e41f4b71Sopenharmony_ci } else { 204e41f4b71Sopenharmony_ci console.info(`${TAG}: creating AudioRenderer failed, error: ${err.message}`); 205e41f4b71Sopenharmony_ci } 206e41f4b71Sopenharmony_ci }); 207e41f4b71Sopenharmony_ci} 208e41f4b71Sopenharmony_ci 209e41f4b71Sopenharmony_ci// Start audio rendering. 210e41f4b71Sopenharmony_cifunction start() { 211e41f4b71Sopenharmony_ci if (renderModel !== undefined) { 212e41f4b71Sopenharmony_ci let stateGroup = [audio.AudioState.STATE_PREPARED, audio.AudioState.STATE_PAUSED, audio.AudioState.STATE_STOPPED]; 213e41f4b71Sopenharmony_ci if (stateGroup.indexOf((renderModel as audio.AudioRenderer).state.valueOf()) === -1) { // Rendering can be started only when the AudioRenderer is in the prepared, paused, or stopped state. 214e41f4b71Sopenharmony_ci console.error(TAG + 'start failed'); 215e41f4b71Sopenharmony_ci return; 216e41f4b71Sopenharmony_ci } 217e41f4b71Sopenharmony_ci // Start rendering. 218e41f4b71Sopenharmony_ci (renderModel as audio.AudioRenderer).start((err: BusinessError) => { 219e41f4b71Sopenharmony_ci if (err) { 220e41f4b71Sopenharmony_ci console.error('Renderer start failed.'); 221e41f4b71Sopenharmony_ci } else { 222e41f4b71Sopenharmony_ci console.info('Renderer start success.'); 223e41f4b71Sopenharmony_ci } 224e41f4b71Sopenharmony_ci }); 225e41f4b71Sopenharmony_ci } 226e41f4b71Sopenharmony_ci} 227e41f4b71Sopenharmony_ci 228e41f4b71Sopenharmony_ci// Pause the rendering. 229e41f4b71Sopenharmony_cifunction pause() { 230e41f4b71Sopenharmony_ci if (renderModel !== undefined) { 231e41f4b71Sopenharmony_ci // Rendering can be paused only when the AudioRenderer is in the running state. 232e41f4b71Sopenharmony_ci if ((renderModel as audio.AudioRenderer).state.valueOf() !== audio.AudioState.STATE_RUNNING) { 233e41f4b71Sopenharmony_ci console.info('Renderer is not running'); 234e41f4b71Sopenharmony_ci return; 235e41f4b71Sopenharmony_ci } 236e41f4b71Sopenharmony_ci // Pause the rendering. 237e41f4b71Sopenharmony_ci (renderModel as audio.AudioRenderer).pause((err: BusinessError) => { 238e41f4b71Sopenharmony_ci if (err) { 239e41f4b71Sopenharmony_ci console.error('Renderer pause failed.'); 240e41f4b71Sopenharmony_ci } else { 241e41f4b71Sopenharmony_ci console.info('Renderer pause success.'); 242e41f4b71Sopenharmony_ci } 243e41f4b71Sopenharmony_ci }); 244e41f4b71Sopenharmony_ci } 245e41f4b71Sopenharmony_ci} 246e41f4b71Sopenharmony_ci 247e41f4b71Sopenharmony_ci// Stop rendering. 248e41f4b71Sopenharmony_ciasync function stop() { 249e41f4b71Sopenharmony_ci if (renderModel !== undefined) { 250e41f4b71Sopenharmony_ci // Rendering can be stopped only when the AudioRenderer is in the running or paused state. 251e41f4b71Sopenharmony_ci if ((renderModel as audio.AudioRenderer).state.valueOf() !== audio.AudioState.STATE_RUNNING && (renderModel as audio.AudioRenderer).state.valueOf() !== audio.AudioState.STATE_PAUSED) { 252e41f4b71Sopenharmony_ci console.info('Renderer is not running or paused.'); 253e41f4b71Sopenharmony_ci return; 254e41f4b71Sopenharmony_ci } 255e41f4b71Sopenharmony_ci // Stop rendering. 256e41f4b71Sopenharmony_ci (renderModel as audio.AudioRenderer).stop((err: BusinessError) => { 257e41f4b71Sopenharmony_ci if (err) { 258e41f4b71Sopenharmony_ci console.error('Renderer stop failed.'); 259e41f4b71Sopenharmony_ci } else { 260e41f4b71Sopenharmony_ci fileIo.close(file); 261e41f4b71Sopenharmony_ci console.info('Renderer stop success.'); 262e41f4b71Sopenharmony_ci } 263e41f4b71Sopenharmony_ci }); 264e41f4b71Sopenharmony_ci } 265e41f4b71Sopenharmony_ci} 266e41f4b71Sopenharmony_ci 267e41f4b71Sopenharmony_ci// Release the instance. 268e41f4b71Sopenharmony_ciasync function release() { 269e41f4b71Sopenharmony_ci if (renderModel !== undefined) { 270e41f4b71Sopenharmony_ci // The AudioRenderer can be released only when it is not in the released state. 271e41f4b71Sopenharmony_ci if (renderModel.state.valueOf() === audio.AudioState.STATE_RELEASED) { 272e41f4b71Sopenharmony_ci console.info('Renderer already released'); 273e41f4b71Sopenharmony_ci return; 274e41f4b71Sopenharmony_ci } 275e41f4b71Sopenharmony_ci // Release the resources. 276e41f4b71Sopenharmony_ci (renderModel as audio.AudioRenderer).release((err: BusinessError) => { 277e41f4b71Sopenharmony_ci if (err) { 278e41f4b71Sopenharmony_ci console.error('Renderer release failed.'); 279e41f4b71Sopenharmony_ci } else { 280e41f4b71Sopenharmony_ci console.info('Renderer release success.'); 281e41f4b71Sopenharmony_ci } 282e41f4b71Sopenharmony_ci }); 283e41f4b71Sopenharmony_ci } 284e41f4b71Sopenharmony_ci} 285e41f4b71Sopenharmony_ci``` 286e41f4b71Sopenharmony_ci 287e41f4b71Sopenharmony_ciWhen audio streams with the same or higher priority need to use the output device, the current audio playback will be interrupted. The application can respond to and handle the interruption event. For details, see [Processing Audio Interruption Events](audio-playback-concurrency.md). 288