1# Low-Latency Audio Monitoring 2 3AudioLoopback is an audio monitoring tool that delivers audio to headphones with reduced latency in real time, enabling users to hear their own voice or other relevant sounds immediately. 4 5It is commonly used in karaoke applications, where the recorded vocals and background music are sent to the headphones in real time. This allows users to adjust their performance based on the feedback, enhancing their experience. 6 7When audio loopback is enabled, the system creates a low-latency renderer and capturer to implement low-latency in-ear monitoring. The audio captured is routed back to the renderer through an internal path. The renderer follows the audio focus strategy for [STREAM_USAGE_MUSIC](../../reference/apis-audio-kit/arkts-apis-audio-e.md#streamusage), whereas the capturer follows the strategy for [SOURCE_TYPE_MIC](../../reference/apis-audio-kit/arkts-apis-audio-e.md#sourcetype8). 8 9The system automatically chooses the input and output devices. If these devices do not support low latency, audio loopback does not work. If another audio stream takes over the audio focus or if the input or output device changes to the one that does not support low latency, the system disables audio loopback automatically. 10 11## Prerequisites 12 13- Currently, low-latency audio monitoring is only supported through wired headphones, where audio is captured and played back via the wired headphones. 14 15- Low-power renderers and low-latency renderers cannot be used concurrently in API version 20. To enable a renderer, you are advised to use [STREAM_USAGE_UNKNOWN](../../reference/apis-audio-kit/arkts-apis-audio-e.md#streamusage). If [STREAM_USAGE_MUSIC](../../reference/apis-audio-kit/arkts-apis-audio-e.md#streamusage) is used, the system creates a normal renderer. 16 17## Development Guidelines 18 19Using AudioLoopback for audio monitoring involves querying the monitoring capability with [isAudioLoopbackSupported](../../reference/apis-audio-kit/arkts-apis-audio-AudioStreamManager.md#isaudioloopbacksupported20), creating an AudioLoopback instance, setting the volume, listening for status changes, and enabling/disabling audio loopback. This guide walks you through the process of enabling audio monitoring using AudioLoopback, with a focus on how to use AudioLoopback for audio monitoring. You are advised to read this in conjunction with the [AudioLoopback](../../reference/apis-audio-kit/arkts-apis-audio-AudioLoopback.md) API documentation. 20 21The figure below shows the status changes of the AudioLoopback. After an AudioLoopback instance is created, different APIs can be called to switch the AudioLoopback to different states and trigger the required behavior. 22 23If an API is called when the AudioLoopback is not in the given state, the system may throw an exception or generate other undefined behavior. Therefore, you are advised to check the AudioLoopback state before triggering state transition. 24 25**AudioLoopback status changes** 26 27 28 29The [on('statusChange')](../../reference/apis-audio-kit/arkts-apis-audio-AudioLoopback.md#onstatuschange20) API can be used to listen for AudioLoopback status changes. For details about the value and description of each status, see [AudioLoopbackStatus](../../reference/apis-audio-kit/arkts-apis-audio-e.md#audioloopbackstatus20). 30 31### How to Develop 32 331. Query the audio monitoring capability and create an AudioLoopback instance. For details about the AudioLoopback mode, see [AudioLoopbackMode](../../reference/apis-audio-kit/arkts-apis-audio-e.md#audioloopbackmode20). 34 35 > **NOTE** 36 > 37 > You must request the ohos.permission.MICROPHONE permission for audio monitoring. For details, see [Requesting User Authorization](../../security/AccessToken/request-user-authorization.md). 38 39 ```ts 40 import { audio } from '@kit.AudioKit'; 41 import { BusinessError } from '@kit.BasicServicesKit'; 42 43 let mode: audio.AudioLoopbackMode.HARDWARE; 44 let audioLoopback: audio.AudioLoopback; 45 let isSupported = audio.getAudioManager().getStreamManager().isAudioLoopbackSupported(mode); 46 if (isSupported) { 47 audio.createAudioLoopback(mode).then((loopback) => { 48 audioLoopback = loopback; 49 console.info('Invoke createAudioLoopback succeeded.'); 50 }).catch((err: BusinessError) => { 51 console.error(`Invoke createAudioLoopback failed, code is ${err.code}, message is ${err.message}.`); 52 }); 53 } 54 ``` 55 562. Call [getStatus](../../reference/apis-audio-kit/arkts-apis-audio-AudioLoopback.md#getstatus20) to obtain the current audio loopback status. 57 58 > **NOTE** 59 > 60 > The audio loopback status is affected by factors such as audio focus, low-latency control, and capturer and renderer devices. 61 62 ```ts 63 import { BusinessError } from '@kit.BasicServicesKit'; 64 65 audioLoopback.getStatus().then((status: audio.AudioLoopbackStatus) => { 66 console.info(`getStatus success, status is ${status}.`); 67 }).catch((err: BusinessError) => { 68 console.error(`getStatus failed, code is ${err.code}, message is ${err.message}.`); 69 }) 70 ``` 71 723. Call [setVolume](../../reference/apis-audio-kit/arkts-apis-audio-AudioLoopback.md#setvolume20) to set the audio loopback volume. 73 74 > **NOTE** 75 > - Setting the volume before enabling audio loopback will take effect after successful activation of audio loopback. 76 > - Setting the volume after enabling audio loopback will take effect immediately. 77 > - If the volume is not set before enabling audio loopback, the default volume of 0.5 is used upon activation of audio loopback. 78 79 ```ts 80 import { BusinessError } from '@kit.BasicServicesKit'; 81 82 audioLoopback.setVolume(0.5).then(() => { 83 console.info('setVolume success.'); 84 }).catch((err: BusinessError) => { 85 console.error(`setVolume failed, code is ${err.code}, message is ${err.message}.`); 86 }); 87 ``` 88 894. Call [enable](../../reference/apis-audio-kit/arkts-apis-audio-AudioLoopback.md#enable20) to enable or disable audio loopback. 90 91 ```ts 92 import { BusinessError } from '@kit.BasicServicesKit'; 93 94 audioLoopback.enable(true).then((isSuccess) => { 95 if (isSuccess) { 96 console.info('enable success.'); 97 } else { 98 console.info('enable failed.'); 99 } 100 }).catch((err: BusinessError) => { 101 console.error(`enable failed, code is ${err.code}, message is ${err.message}.`); 102 }); 103 104 audioLoopback.enable(false).then((isSuccess) => { 105 if (isSuccess) { 106 console.info('disable success.'); 107 } else { 108 console.info('disable failed.'); 109 } 110 }).catch((err: BusinessError) => { 111 console.error(`disable failed, code is ${err.code}, message is ${err.message}.`); 112 }); 113 ``` 114 115### Sample Code 116 117The following example demonstrates how to use AudioLoopback to enable low-latency audio monitoring: 118 119```ts 120import { audio } from '@kit.AudioKit'; 121import { BusinessError } from '@kit.BasicServicesKit'; 122import { common } from '@kit.AbilityKit'; 123 124const TAG = 'AudioLoopbackDemo'; 125 126let mode: audio.AudioLoopbackMode.HARDWARE; 127let audioLoopback: audio.AudioLoopback | undefined = undefined; 128 129let statusChangeCallback = (status: audio.AudioLoopbackStatus) => { 130 if (status == audio.AudioLoopbackStatus.UNAVAILABLE_DEVICE) { 131 console.info('Audio loopback status is: UNAVAILABLE_DEVICE'); 132 } else if (status == audio.AudioLoopbackStatus.UNAVAILABLE_SCENE) { 133 console.info('Audio loopback status is: UNAVAILABLE_SCENE'); 134 } else if (status == audio.AudioLoopbackStatus.AVAILABLE_IDLE) { 135 console.info('Audio loopback status is: AVAILABLE_IDLE'); 136 } else if (status == audio.AudioLoopbackStatus.AVAILABLE_RUNNING) { 137 console.info('Audio loopback status is: AVAILABLE_RUNNING'); 138 } 139}; 140 141// Query the capability and create an instance. 142function init() { 143 let isSupported = audio.getAudioManager().getStreamManager().isAudioLoopbackSupported(mode); 144 if (isSupported) { 145 audio.createAudioLoopback(mode).then((loopback) => { 146 console.info('Invoke createAudioLoopback succeeded.'); 147 audioLoopback = loopback; 148 }).catch((err: BusinessError) => { 149 console.error(`Invoke createAudioLoopback failed, code is ${err.code}, message is ${err.message}.`); 150 }); 151 } else { 152 console.error('Audio loopback is unsupported.'); 153 } 154} 155 156// Set the volume for audio loopback. 157async function setVolume(volume: number) { 158 if (audioLoopback !== undefined) { 159 try { 160 await audioLoopback.setVolume(volume); 161 console.info(`Invoke setVolume ${volume} succeeded.`); 162 } catch (err) { 163 console.error(`Invoke setVolume failed, code is ${err.code}, message is ${err.message}.`); 164 } 165 } else { 166 console.error('Audio loopback not created.'); 167 } 168} 169 170// Set a listener and enable audio loopback. 171async function enable() { 172 if (audioLoopback !== undefined) { 173 try { 174 let status = await audioLoopback.getStatus(); 175 if (status == audio.AudioLoopbackStatus.AVAILABLE_IDLE) { 176 // Register a listener. 177 audioLoopback.on('statusChange', statusChangeCallback); 178 // Enable audio loopback. 179 let success = await audioLoopback.enable(true); 180 if (success) { 181 console.info('Invoke enable succeeded'); 182 } else { 183 status = await audioLoopback.getStatus(); 184 statusChangeCallback(status); 185 } 186 } else { 187 statusChangeCallback(status); 188 } 189 } catch (err) { 190 console.error(`Invoke enable failed, code is ${err.code}, message is ${err.message}.`); 191 } 192 } else { 193 console.error('Audio loopback not created.'); 194 } 195} 196 197// Disable audio loopback and unregister the listener. 198async function disable() { 199 if (audioLoopback !== undefined) { 200 try { 201 let status = await audioLoopback.getStatus(); 202 if (status == audio.AudioLoopbackStatus.AVAILABLE_RUNNING) { 203 // Disable audio loopback. 204 let success = await audioLoopback.enable(false); 205 if (success) { 206 console.info('Invoke disable succeeded'); 207 // Unregister the listener. 208 audioLoopback.off('statusChange', statusChangeCallback); 209 } else { 210 status = await audioLoopback.getStatus(); 211 statusChangeCallback(status); 212 } 213 } else { 214 statusChangeCallback(status); 215 } 216 } catch (err) { 217 console.error(`Invoke disable failed, code is ${err.code}, message is ${err.message}.`); 218 } 219 } else { 220 console.error('Audio loopback not created.'); 221 } 222} 223``` 224