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![AudioRenderer state transition](figures/audiorenderer-status-change.png)
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