• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Audio Rendering Development
2
3## When to Use
4
5**AudioRenderer** provides APIs for rendering audio files and controlling playback. It also supports audio interruption. You can use the APIs provided by **AudioRenderer** to play audio files in output devices and manage playback tasks.
6
7### Audio Interruption
8
9When an audio stream with a higher priority needs to be played, the audio renderer interrupts the stream with a lower priority. For example, if a call comes in when the user is listening to music, the music playback, which is the lower priority stream, is paused. For details, see [How to Develop](#how-to-develop).
10
11### State Check
12
13During application development, you are advised to use **on('stateChange')** to subscribe to state changes of the **AudioRenderer** instance. This is because some operations can be performed only when the audio renderer is in a given state. If the application performs an operation when the audio renderer is not in the given state, the system may throw an exception or generate other undefined behavior.
14
15**Figure 1** Audio renderer state
16
17![](figures/audio-renderer-state.png)
18
19### Asynchronous Operations
20
21To ensure that the UI thread is not blocked, most **AudioRenderer** calls are asynchronous. Each API provides the callback and promise functions. The following examples use the promise functions. For more information, see [AudioRenderer in Audio Management](../reference/apis/js-apis-audio.md#audiorenderer8).
22
23
24
25## How to Develop
26
271. Use **createAudioRenderer()** to create an **AudioRenderer** instance.
28   Set parameters of the audio renderer in **audioCapturerOptions**. This instance is used to render audio, control and obtain the rendering status, and register a callback for notification.
29
30   ```js
31    var audioStreamInfo = {
32        samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_44100,
33        channels: audio.AudioChannel.CHANNEL_1,
34     sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,
35        encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW
36    }
37
38    var audioRendererInfo = {
39        content: audio.ContentType.CONTENT_TYPE_SPEECH,
40        usage: audio.StreamUsage.STREAM_USAGE_VOICE_COMMUNICATION,
41        rendererFlags: 1
42    }
43
44    var audioRendererOptions = {
45        streamInfo: audioStreamInfo,
46        rendererInfo: audioRendererInfo
47    }
48
49    let audioRenderer = await audio.createAudioRenderer(audioRendererOptions);
50   ```
51
522. Use **on('interrupt')** to subscribe to audio interruption events.
53
54   Stream-A is interrupted when Stream-B with a higher or equal priority requests to become active and use the output device.
55
56   In some cases, the audio renderer performs forcible operations such as pausing and ducking, and notifies the application through **InterruptEvent**. In other cases, the application can choose to act on the **InterruptEvent** or ignore it.
57
58   In the case of audio interruption, the application may encounter write failures. To avoid such failures, interruption unaware applications can use **audioRenderer.state** to check the renderer state before writing audio data. The applications can obtain more details by subscribing to the audio interruption events. For details, see [InterruptEvent](../reference/apis/js-apis-audio.md#interruptevent9).
59
60   ```js
61   audioRenderer.on('interrupt', (interruptEvent) => {
62           console.info('InterruptEvent Received');
63           console.info('InterruptType: ' + interruptEvent.eventType);
64           console.info('InterruptForceType: ' + interruptEvent.forceType);
65           console.info('AInterruptHint: ' + interruptEvent.hintType);
66
67           if (interruptEvent.forceType == audio.InterruptForceType.INTERRUPT_FORCE) {
68               switch (interruptEvent.hintType) {
69                   // Force Pause: Action was taken by framework.
70                   // Halt the write calls to avoid data loss.
71                   case audio.InterruptHint.INTERRUPT_HINT_PAUSE:
72                       isPlay = false;
73                       break;
74                   // Force Stop: Action was taken by framework.
75                   // Halt the write calls to avoid data loss.
76                   case audio.InterruptHint.INTERRUPT_HINT_STOP:
77                       isPlay = false;
78                       break;
79                   // Force Duck: Action was taken by framework,
80                   // just notifying the app that volume has been reduced.
81                   case audio.InterruptHint.INTERRUPT_HINT_DUCK:
82                       break;
83                   // Force Unduck: Action was taken by framework,
84                   // just notifying the app that volume has been restored.
85                   case audio.InterruptHint.INTERRUPT_HINT_UNDUCK:
86                       break;
87               }
88           } else if (interruptEvent.forceType == audio.InterruptForceType.INTERRUPT_SHARE) {
89               switch (interruptEvent.hintType) {
90                   // Share Resume: Action is to be taken by App.
91                   // Resume the force paused stream if required.
92                   case audio.InterruptHint.INTERRUPT_HINT_RESUME:
93                       startRenderer();
94                       break;
95                   // Share Pause: Stream has been interrupted,
96                   // It can choose to pause or play concurrently.
97                   case audio.InterruptHint.INTERRUPT_HINT_PAUSE:
98                       isPlay = false;
99                       pauseRenderer();
100                       break;
101               }
102           }
103       });
104   ```
105
1063. Use **start()** to start audio rendering.
107
108   The renderer state will be **STATE_RUNNING** once the audio renderer is started. The application can then begin reading buffers.
109
110   ```js
111    async function startRenderer() {
112        var state = audioRenderer.state;
113        // The state should be prepared, paused, or stopped.
114        if (state != audio.AudioState.STATE_PREPARED || state != audio.AudioState.STATE_PAUSED ||
115            state != audio.AudioState.STATE_STOPPED) {
116            console.info('Renderer is not in a correct state to start');
117            return;
118        }
119
120        await audioRenderer.start();
121
122        state = audioRenderer.state;
123        if (state == audio.AudioState.STATE_RUNNING) {
124            console.info('Renderer started');
125        } else {
126            console.error('Renderer start failed');
127        }
128    }
129   ```
130
1314. Call **write()** to write data to the buffer.
132
133   Read the audio data to be played to the buffer. Call **write()** repeatedly to write the data to the buffer.
134
135   ```js
136    async function writeBuffer(buf) {
137        var state = audioRenderer.state;
138        if (state != audio.AudioState.STATE_RUNNING) {
139            console.error('Renderer is not running, do not write');
140            isPlay = false;
141            return;
142        }
143        let writtenbytes = await audioRenderer.write(buf);
144
145        console.info('Actual written bytes: ' + writtenbytes);
146        if (writtenbytes < 0) {
147            console.error('Write buffer failed. check the state of renderer');
148        }
149    }
150
151    // Reasonable minimum buffer size for renderer. However, the renderer can accept other read sizes as well.
152    const bufferSize = await audioRenderer.getBufferSize();
153    const path = '/data/file_example_WAV_2MG.wav';
154    let ss = fileio.createStreamSync(path, 'r');
155    const totalSize = 2146166; // file_example_WAV_2MG.wav
156    let rlen = 0;
157    let discardHeader = new ArrayBuffer(44);
158    ss.readSync(discardHeader);
159    rlen += 44;
160
161    var id = setInterval(() =>  {
162        if (isPlay || isRelease) {
163            if (rlen >= totalSize || isRelease) {
164                ss.closeSync();
165                stopRenderer();
166                clearInterval(id);
167            }
168            let buf = new ArrayBuffer(bufferSize);
169            rlen += ss.readSync(buf);
170            console.info('Total bytes read from file: ' + rlen);
171            writeBuffer(buf);
172        } else {
173            console.info('check after next interval');
174        }
175    } , 30); // interval to be set based on audio file format
176   ```
177
1785. (Optional) Call **pause()** or **stop()** to pause or stop rendering.
179
180   ```js
181       async function pauseRenderer() {
182           var state = audioRenderer.state;
183           if (state != audio.AudioState.STATE_RUNNING) {
184               console.info('Renderer is not running');
185               return;
186           }
187
188           await audioRenderer.pause();
189
190           state = audioRenderer.state;
191           if (state == audio.AudioState.STATE_PAUSED) {
192               console.info('Renderer paused');
193           } else {
194               console.error('Renderer pause failed');
195           }
196       }
197
198       async function stopRenderer() {
199           var state = audioRenderer.state;
200           if (state != audio.AudioState.STATE_RUNNING || state != audio.AudioState.STATE_PAUSED) {
201               console.info('Renderer is not running or paused');
202               return;
203           }
204
205           await audioRenderer.stop();
206
207           state = audioRenderer.state;
208           if (state == audio.AudioState.STATE_STOPPED) {
209               console.info('Renderer stopped');
210           } else {
211               console.error('Renderer stop failed');
212           }
213   }
214   ```
215
2166. After the task is complete, call **release()** to release related resources.
217
218   **AudioRenderer** uses a large number of system resources. Therefore, ensure that the resources are released after the task is complete.
219
220   ```js
221       async function releaseRenderer() {
222           if (state_ == RELEASED || state_ == NEW) {
223               console.info('Resourced already released');
224               return;
225           }
226
227           await audioRenderer.release();
228
229           state = audioRenderer.state;
230           if (state == STATE_RELEASED) {
231               console.info('Renderer released');
232           } else {
233               console.info('Renderer release failed');
234           }
235
236       }
237   ```
238
239
240