1# Using AudioCapturer for Audio Recording 2 3The AudioCapturer is used to record Pulse Code Modulation (PCM) audio data. It is suitable if you have extensive audio development experience and want to implement more flexible recording features. 4 5## Development Guidelines 6 7The full recording process involves creating an AudioCapturer instance, configuring audio recording parameters, starting and stopping recording, and releasing the instance. In this topic, you will learn how to use the AudioCapturer to record audio data. Before the development, you are advised to read [AudioCapturer](../../reference/apis-audio-kit/arkts-apis-audio-AudioCapturer.md) for the API reference. 8 9The figure below shows the state changes of the AudioCapturer. After an AudioCapturer instance is created, different APIs can be called to switch the AudioCapturer to different states and trigger the required behavior. If an API is called when the AudioCapturer is not in the given state, the system may throw an exception or generate other undefined behavior. Therefore, you are advised to check the AudioCapturer state before triggering state transition. 10 11**Figure 1** AudioCapturer state transition 12 13 14 15You can call **on('stateChange')** to listen for state changes of the AudioCapturer. For details about each state, see [AudioState](../../reference/apis-audio-kit/arkts-apis-audio-e.md#audiostate8). 16 17### How to Develop 18 191. Set audio recording parameters and create an AudioCapturer instance. For details about the parameters, see [AudioCapturerOptions](../../reference/apis-audio-kit/arkts-apis-audio-i.md#audiocaptureroptions8). 20 21 > **NOTE** 22 > 23 > When the microphone audio source is set ([SourceType](../../reference/apis-audio-kit/arkts-apis-audio-e.md#sourcetype8) is set to **SOURCE_TYPE_MIC**, **SOURCE_TYPE_VOICE_RECOGNITION**, **SOURCE_TYPE_VOICE_COMMUNICATION**, or **SOURCE_TYPE_VOICE_MESSAGE**), the permission ohos.permission.MICROPHONE is required. For details about how to apply for the permission, see [Requesting User Authorization](../../security/AccessToken/request-user-authorization.md). 24 25 ```ts 26 import { audio } from '@kit.AudioKit'; 27 28 let audioStreamInfo: audio.AudioStreamInfo = { 29 samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // Sampling rate. 30 channels: audio.AudioChannel.CHANNEL_2, // Channel. 31 sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // Sampling format. 32 encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // Encoding format. 33 }; 34 35 let audioCapturerInfo: audio.AudioCapturerInfo = { 36 source: audio.SourceType.SOURCE_TYPE_MIC, // Audio source type: microphone. Set this parameter based on the service scenario. 37 capturerFlags: 0 // Flag indicating an AudioCapturer. 38 }; 39 40 let audioCapturerOptions: audio.AudioCapturerOptions = { 41 streamInfo: audioStreamInfo, 42 capturerInfo: audioCapturerInfo 43 }; 44 45 audio.createAudioCapturer(audioCapturerOptions, (err, data) => { 46 if (err) { 47 console.error(`Invoke createAudioCapturer failed, code is ${err.code}, message is ${err.message}`); 48 } else { 49 console.info('Invoke createAudioCapturer succeeded.'); 50 let audioCapturer = data; 51 } 52 }); 53 ``` 54 552. Call **on('readData')** to subscribe to the audio data read callback. 56 > **NOTE** 57 > - **Thread management**: You are advised not to use multiple threads for data reading. If multithreading is necessary for data reading, ensure proper thread management. 58 > - **Thread performance**: Do not execute time-consuming tasks in the thread where the **readData** API resides. Failing to do so may delay the data processing thread's response to callbacks, potentially causing issues like missing audio data, lag, and noise. 59 60 ```ts 61 import { BusinessError } from '@kit.BasicServicesKit'; 62 import { fileIo as fs } from '@kit.CoreFileKit'; 63 import { common } from '@kit.AbilityKit'; 64 65 class Options { 66 offset?: number; 67 length?: number; 68 } 69 70 let bufferSize: number = 0; 71 // Obtain the context from the component and ensure that the return value of this.getUIContext().getHostContext() is UIAbilityContext. 72 let context = this.getUIContext().getHostContext() as common.UIAbilityContext; 73 let path = context.cacheDir; 74 let filePath = path + '/StarWars10s-2C-48000-4SW.pcm'; 75 let file: fs.File = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); 76 let readDataCallback = (buffer: ArrayBuffer) => { 77 let options: Options = { 78 offset: bufferSize, 79 length: buffer.byteLength 80 } 81 fs.writeSync(file.fd, buffer, options); 82 bufferSize += buffer.byteLength; 83 }; 84 85 audioCapturer.on('readData', readDataCallback); 86 ``` 87 883. Call **start()** to switch the AudioCapturer to the **running** state and start recording. 89 90 ```ts 91 import { BusinessError } from '@kit.BasicServicesKit'; 92 93 audioCapturer.start((err: BusinessError) => { 94 if (err) { 95 console.error(`Capturer start failed, code is ${err.code}, message is ${err.message}`); 96 } else { 97 console.info('Capturer start success.'); 98 } 99 }); 100 ``` 101 1024. Call **stop()** to stop recording. 103 104 ```ts 105 import { BusinessError } from '@kit.BasicServicesKit'; 106 107 audioCapturer.stop((err: BusinessError) => { 108 if (err) { 109 console.error(`Capturer stop failed, code is ${err.code}, message is ${err.message}`); 110 } else { 111 console.info('Capturer stopped.'); 112 } 113 }); 114 ``` 115 1165. Call **release()** to release the instance. 117 118 ```ts 119 import { BusinessError } from '@kit.BasicServicesKit'; 120 121 audioCapturer.release((err: BusinessError) => { 122 if (err) { 123 console.error(`capturer release failed, code is ${err.code}, message is ${err.message}`); 124 } else { 125 console.info('capturer released.'); 126 } 127 }); 128 ``` 129 130### Sample Code 131 132Refer to the sample code below to record audio using AudioCapturer. 133 134```ts 135import { audio } from '@kit.AudioKit'; 136import { BusinessError } from '@kit.BasicServicesKit'; 137import { fileIo as fs } from '@kit.CoreFileKit'; 138import { common } from '@kit.AbilityKit'; 139 140const TAG = 'AudioCapturerDemo'; 141 142class Options { 143 offset?: number; 144 length?: number; 145} 146 147let bufferSize: number = 0; 148let audioCapturer: audio.AudioCapturer | undefined = undefined; 149let audioStreamInfo: audio.AudioStreamInfo = { 150 samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // Sampling rate. 151 channels: audio.AudioChannel.CHANNEL_2, // Channel. 152 sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // Sampling format. 153 encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // Encoding format. 154}; 155let audioCapturerInfo: audio.AudioCapturerInfo = { 156 source: audio.SourceType.SOURCE_TYPE_MIC, // Audio source type: microphone. Set this parameter based on the service scenario. 157 capturerFlags: 0 // Flag indicating an AudioCapturer. 158}; 159let audioCapturerOptions: audio.AudioCapturerOptions = { 160 streamInfo: audioStreamInfo, 161 capturerInfo: audioCapturerInfo 162}; 163// Obtain the context from the component and ensure that the return value of this.getUIContext().getHostContext() is UIAbilityContext. 164let context = this.getUIContext().getHostContext() as common.UIAbilityContext; 165let path = context.cacheDir; 166let filePath = path + '/StarWars10s-2C-48000-4SW.pcm'; 167let file: fs.File = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); 168let readDataCallback = (buffer: ArrayBuffer) => { 169 let options: Options = { 170 offset: bufferSize, 171 length: buffer.byteLength 172 } 173 fs.writeSync(file.fd, buffer, options); 174 bufferSize += buffer.byteLength; 175}; 176 177// Create an AudioCapturer instance, and set the events to listen for. 178function init() { 179 audio.createAudioCapturer(audioCapturerOptions, (err, capturer) => { // Create an AudioCapturer instance. 180 if (err) { 181 console.error(`Invoke createAudioCapturer failed, code is ${err.code}, message is ${err.message}`); 182 return; 183 } 184 console.info(`${TAG}: create AudioCapturer success`); 185 audioCapturer = capturer; 186 if (audioCapturer !== undefined) { 187 (audioCapturer as audio.AudioCapturer).on('readData', readDataCallback); 188 } 189 }); 190} 191 192// Start audio recording. 193function start() { 194 if (audioCapturer !== undefined) { 195 let stateGroup = [audio.AudioState.STATE_PREPARED, audio.AudioState.STATE_PAUSED, audio.AudioState.STATE_STOPPED]; 196 if (stateGroup.indexOf((audioCapturer as audio.AudioCapturer).state.valueOf()) === -1) { // Recording can be started only when the AudioCapturer is in the STATE_PREPARED, STATE_PAUSED, or STATE_STOPPED state. 197 console.error(`${TAG}: start failed`); 198 return; 199 } 200 201 // Start recording. 202 (audioCapturer as audio.AudioCapturer).start((err: BusinessError) => { 203 if (err) { 204 console.error('Capturer start failed.'); 205 } else { 206 console.info('Capturer start success.'); 207 } 208 }); 209 } 210} 211 212// Stop recording. 213function stop() { 214 if (audioCapturer !== undefined) { 215 // The AudioCapturer can be stopped only when it is in the STATE_RUNNING or STATE_PAUSED state. 216 if ((audioCapturer as audio.AudioCapturer).state.valueOf() !== audio.AudioState.STATE_RUNNING && (audioCapturer as audio.AudioCapturer).state.valueOf() !== audio.AudioState.STATE_PAUSED) { 217 console.info('Capturer is not running or paused'); 218 return; 219 } 220 221 // Stop recording. 222 (audioCapturer as audio.AudioCapturer).stop((err: BusinessError) => { 223 if (err) { 224 console.error('Capturer stop failed.'); 225 } else { 226 fs.close(file); 227 console.info('Capturer stop success.'); 228 } 229 }); 230 } 231} 232 233// Release the instance. 234function release() { 235 if (audioCapturer !== undefined) { 236 // The AudioCapturer can be released only when it is not in the STATE_RELEASED or STATE_NEW state. 237 if ((audioCapturer as audio.AudioCapturer).state.valueOf() === audio.AudioState.STATE_RELEASED || (audioCapturer as audio.AudioCapturer).state.valueOf() === audio.AudioState.STATE_NEW) { 238 console.info('Capturer already released'); 239 return; 240 } 241 242 // Release the resources. 243 (audioCapturer as audio.AudioCapturer).release((err: BusinessError) => { 244 if (err) { 245 console.error('Capturer release failed.'); 246 } else { 247 console.info('Capturer release success.'); 248 } 249 }); 250 } 251} 252``` 253 254### Setting the Mute Interruption Mode 255 256To ensure that the recording is not interrupted by the system's focus concurrency rules, a feature is introduced to change the interruption strategy from stopping the recording to simply muting it. You can control this behavior by calling [setWillMuteWhenInterrupted](../../reference/apis-audio-kit/arkts-apis-audio-AudioCapturer.md#setwillmutewheninterrupted20) when creating an AudioCapturer instance. By default, this mode is disabled, and the audio focus strategy manages the order of concurrent audio streams. When enabled, if the recording is interrupted by another application, it will go into a muted state instead of stopping or pausing. In this state, the audio captured is silent. 257