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   > When the microphone audio source is set ([SourceType](../../reference/apis-audio-kit/js-apis-audio.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,
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 as fs } from '@kit.CoreFileKit';
60
61    class Options {
62      offset?: number;
63      length?: number;
64    }
65
66    let bufferSize: number = 0;
67    let path = getContext().cacheDir;
68    let filePath = path + '/StarWars10s-2C-48000-4SW.pcm';
69    let file: fs.File = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
70    let readDataCallback = (buffer: ArrayBuffer) => {
71      let options: Options = {
72        offset: bufferSize,
73        length: buffer.byteLength
74      }
75      fs.writeSync(file.fd, buffer, options);
76      bufferSize += buffer.byteLength;
77    };
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### Sample Code
125
126Refer to the sample code below to record audio using AudioCapturer.
127
128```ts
129import { audio } from '@kit.AudioKit';
130import { BusinessError } from '@kit.BasicServicesKit';
131import { fileIo as fs } from '@kit.CoreFileKit';
132
133const TAG = 'AudioCapturerDemo';
134
135class Options {
136  offset?: number;
137  length?: number;
138}
139
140let bufferSize: number = 0;
141let audioCapturer: audio.AudioCapturer | undefined = undefined;
142let audioStreamInfo: audio.AudioStreamInfo = {
143  samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // Sampling rate.
144  channels: audio.AudioChannel.CHANNEL_2, // Channel.
145  sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // Sampling format.
146  encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // Encoding format.
147};
148let audioCapturerInfo: audio.AudioCapturerInfo = {
149  source: audio.SourceType.SOURCE_TYPE_MIC, // Audio source type.
150  capturerFlags: 0 // Flag indicating an AudioCapturer.
151};
152let audioCapturerOptions: audio.AudioCapturerOptions = {
153  streamInfo: audioStreamInfo,
154  capturerInfo: audioCapturerInfo
155};
156let path = getContext().cacheDir;
157let filePath = path + '/StarWars10s-2C-48000-4SW.pcm';
158let file: fs.File = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
159let readDataCallback = (buffer: ArrayBuffer) => {
160   let options: Options = {
161      offset: bufferSize,
162      length: buffer.byteLength
163   }
164   fs.writeSync(file.fd, buffer, options);
165   bufferSize += buffer.byteLength;
166};
167
168// Create an AudioCapturer instance, and set the events to listen for.
169function init() {
170  audio.createAudioCapturer(audioCapturerOptions, (err, capturer) => { // Create an AudioCapturer instance.
171    if (err) {
172      console.error(`Invoke createAudioCapturer failed, code is ${err.code}, message is ${err.message}`);
173      return;
174    }
175    console.info(`${TAG}: create AudioCapturer success`);
176    audioCapturer = capturer;
177    if (audioCapturer !== undefined) {
178       (audioCapturer as audio.AudioCapturer).on('readData', readDataCallback);
179    }
180  });
181}
182
183// Start audio recording.
184function start() {
185  if (audioCapturer !== undefined) {
186    let stateGroup = [audio.AudioState.STATE_PREPARED, audio.AudioState.STATE_PAUSED, audio.AudioState.STATE_STOPPED];
187    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.
188      console.error(`${TAG}: start failed`);
189      return;
190    }
191
192    // Start recording.
193    (audioCapturer as audio.AudioCapturer).start((err: BusinessError) => {
194      if (err) {
195        console.error('Capturer start failed.');
196      } else {
197        console.info('Capturer start success.');
198      }
199    });
200  }
201}
202
203// Stop recording.
204function stop() {
205  if (audioCapturer !== undefined) {
206    // The AudioCapturer can be stopped only when it is in the STATE_RUNNING or STATE_PAUSED state.
207    if ((audioCapturer as audio.AudioCapturer).state.valueOf() !== audio.AudioState.STATE_RUNNING && (audioCapturer as audio.AudioCapturer).state.valueOf() !== audio.AudioState.STATE_PAUSED) {
208      console.info('Capturer is not running or paused');
209      return;
210    }
211
212    // Stop recording.
213    (audioCapturer as audio.AudioCapturer).stop((err: BusinessError) => {
214      if (err) {
215        console.error('Capturer stop failed.');
216      } else {
217        fs.close(file);
218        console.info('Capturer stop success.');
219      }
220    });
221  }
222}
223
224// Release the instance.
225function release() {
226  if (audioCapturer !== undefined) {
227    // The AudioCapturer can be released only when it is not in the STATE_RELEASED or STATE_NEW state.
228    if ((audioCapturer as audio.AudioCapturer).state.valueOf() === audio.AudioState.STATE_RELEASED || (audioCapturer as audio.AudioCapturer).state.valueOf() === audio.AudioState.STATE_NEW) {
229      console.info('Capturer already released');
230      return;
231    }
232
233    // Release the resources.
234    (audioCapturer as audio.AudioCapturer).release((err: BusinessError) => {
235      if (err) {
236        console.error('Capturer release failed.');
237      } else {
238        console.info('Capturer release success.');
239      }
240    });
241  }
242}
243```
244