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 recording audio data. Before the development, you are advised to read [AudioCapturer](../../reference/apis-audio-kit/js-apis-audio.md#audiocapturer8) 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![AudioCapturer state change](figures/audiocapturer-status-change.png)
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/js-apis-audio.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/js-apis-audio.md#audiocaptureroptions8).
20   
21   > **NOTE**
22   >
23   > In the case of the microphone audio source (when **SourceType** is set to **SOURCE_TYPE_MIC**), you must request the **ohos.permission.MICROPHONE** permission. For details, 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,
37      capturerFlags: 0
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     
57   ```ts
58    import { BusinessError } from '@kit.BasicServicesKit';
59    import { fileIo } from '@kit.CoreFileKit';
60
61    let bufferSize: number = 0;
62    class Options {
63      offset?: number;
64      length?: number;
65    }
66   
67    let path = getContext().cacheDir;
68    let filePath = path + '/StarWars10s-2C-48000-4SW.wav';
69    let file: fileIo.File = fileIo.openSync(filePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
70   
71    let readDataCallback = (buffer: ArrayBuffer) => {
72      let options: Options = {
73        offset: bufferSize,
74        length: buffer.byteLength
75      }
76      fileIo.writeSync(file.fd, buffer, options);
77      bufferSize += buffer.byteLength;
78    }
79    audioCapturer.on('readData', readDataCallback);
80   ```
81
823. Call **start()** to switch the AudioCapturer to the **running** state and start recording.
83     
84   ```ts
85    import { BusinessError } from '@kit.BasicServicesKit';
86   
87    audioCapturer.start((err: BusinessError) => {
88      if (err) {
89        console.error(`Capturer start failed, code is ${err.code}, message is ${err.message}`);
90      } else {
91        console.info('Capturer start success.');
92      }
93    });
94   ```
95
964. Call **stop()** to stop recording.
97     
98   ```ts
99    import { BusinessError } from '@kit.BasicServicesKit';
100   
101    audioCapturer.stop((err: BusinessError) => {
102      if (err) {
103        console.error(`Capturer stop failed, code is ${err.code}, message is ${err.message}`);
104      } else {
105        console.info('Capturer stopped.');
106      }
107    });
108   ```
109
1105. Call **release()** to release the instance.
111     
112   ```ts
113    import { BusinessError } from '@kit.BasicServicesKit';
114   
115    audioCapturer.release((err: BusinessError) => {
116      if (err) {
117        console.error(`capturer release failed, code is ${err.code}, message is ${err.message}`);
118      } else {
119        console.info('capturer released.');
120      }
121    });
122   ```
123
124
125### Sample Code
126
127Refer to the sample code below to record audio using AudioCapturer.
128  
129```ts
130import { audio } from '@kit.AudioKit';
131import { BusinessError } from '@kit.BasicServicesKit';
132import { fileIo } from '@kit.CoreFileKit';
133
134const TAG = 'AudioCapturerDemo';
135
136class Options {
137  offset?: number;
138  length?: number;
139}
140
141let context = getContext(this);
142let bufferSize: number = 0;
143let audioCapturer: audio.AudioCapturer | undefined = undefined;
144let audioStreamInfo: audio.AudioStreamInfo = {
145  samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // Sampling rate.
146  channels: audio.AudioChannel.CHANNEL_2, // Channel.
147  sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // Sampling format.
148  encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // Encoding format.
149}
150let audioCapturerInfo: audio.AudioCapturerInfo = {
151  source: audio.SourceType.SOURCE_TYPE_MIC, // Audio source type.
152  capturerFlags: 0 // Flag indicating an AudioCapturer.
153}
154let audioCapturerOptions: audio.AudioCapturerOptions = {
155  streamInfo: audioStreamInfo,
156  capturerInfo: audioCapturerInfo
157}
158
159let path = getContext().cacheDir;
160let filePath = path + '/StarWars10s-2C-48000-4SW.wav';
161let file: fileIo.File = fileIo.openSync(filePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
162
163let readDataCallback = (buffer: ArrayBuffer) => {
164   let options: Options = {
165      offset: bufferSize,
166      length: buffer.byteLength
167   }
168   fileIo.writeSync(file.fd, buffer, options);
169   bufferSize += buffer.byteLength;
170}
171
172// Create an AudioCapturer instance, and set the events to listen for.
173function init() {
174  audio.createAudioCapturer(audioCapturerOptions, (err, capturer) => { // Create an AudioCapturer instance.
175    if (err) {
176      console.error(`Invoke createAudioCapturer failed, code is ${err.code}, message is ${err.message}`);
177      return;
178    }
179    console.info(`${TAG}: create AudioCapturer success`);
180    audioCapturer = capturer;
181    if (audioCapturer !== undefined) {
182       (audioCapturer as audio.AudioCapturer).on('readData', readDataCallback);
183    }
184  });
185}
186
187// Start audio recording.
188function start() {
189  if (audioCapturer !== undefined) {
190    let stateGroup = [audio.AudioState.STATE_PREPARED, audio.AudioState.STATE_PAUSED, audio.AudioState.STATE_STOPPED];
191    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.
192      console.error(`${TAG}: start failed`);
193      return;
194    }
195
196    // Start recording.
197    (audioCapturer as audio.AudioCapturer).start((err: BusinessError) => {
198      if (err) {
199        console.error('Capturer start failed.');
200      } else {
201        console.info('Capturer start success.');
202      }
203    });
204  }
205}
206
207// Stop recording.
208function stop() {
209  if (audioCapturer !== undefined) {
210    // The AudioCapturer can be stopped only when it is in the STATE_RUNNING or STATE_PAUSED state.
211    if ((audioCapturer as audio.AudioCapturer).state.valueOf() !== audio.AudioState.STATE_RUNNING && (audioCapturer as audio.AudioCapturer).state.valueOf() !== audio.AudioState.STATE_PAUSED) {
212      console.info('Capturer is not running or paused');
213      return;
214    }
215
216    // Stop recording.
217    (audioCapturer as audio.AudioCapturer).stop((err: BusinessError) => {
218      if (err) {
219        console.error('Capturer stop failed.');
220      } else {
221        fileIo.close(file);
222        console.info('Capturer stop success.');
223      }
224    });
225  }
226}
227
228// Release the instance.
229function release() {
230  if (audioCapturer !== undefined) {
231    // The AudioCapturer can be released only when it is not in the STATE_RELEASED or STATE_NEW state.
232    if ((audioCapturer as audio.AudioCapturer).state.valueOf() === audio.AudioState.STATE_RELEASED || (audioCapturer as audio.AudioCapturer).state.valueOf() === audio.AudioState.STATE_NEW) {
233      console.info('Capturer already released');
234      return;
235    }
236
237    // Release the resources.
238    (audioCapturer as audio.AudioCapturer).release((err: BusinessError) => {
239      if (err) {
240        console.error('Capturer release failed.');
241      } else {
242        console.info('Capturer release success.');
243      }
244    });
245  }
246}
247```
248