• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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![AudioLoopback status change](figures/audioloopback-status-change.png)
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