• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Using AudioCapturer for Audio Recording (ArkTS)
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. 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   ```ts
22    import audio from '@ohos.multimedia.audio';
23
24    let audioStreamInfo: audio.AudioStreamInfo = {
25      samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_44100,
26      channels: audio.AudioChannel.CHANNEL_2,
27      sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,
28      encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW
29    };
30
31    let audioCapturerInfo: audio.AudioCapturerInfo = {
32      source: audio.SourceType.SOURCE_TYPE_MIC,
33      capturerFlags: 0
34    };
35
36    let audioCapturerOptions: audio.AudioCapturerOptions = {
37      streamInfo: audioStreamInfo,
38      capturerInfo: audioCapturerInfo
39    };
40
41    audio.createAudioCapturer(audioCapturerOptions, (err, data) => {
42      if (err) {
43        console.error(`Invoke createAudioCapturer failed, code is ${err.code}, message is ${err.message}`);
44      } else {
45        console.info('Invoke createAudioCapturer succeeded.');
46        let audioCapturer = data;
47      }
48    });
49   ```
50
512. Call **start()** to switch the AudioCapturer to the **running** state and start recording.
52
53   ```ts
54    import { BusinessError } from '@ohos.base';
55
56    audioCapturer.start((err: BusinessError) => {
57      if (err) {
58        console.error(`Capturer start failed, code is ${err.code}, message is ${err.message}`);
59      } else {
60        console.info('Capturer start success.');
61      }
62    });
63   ```
64
653. Specify the recording file path and call **read()** to read the data in the buffer.
66
67   ```ts
68    import fs from '@ohos.file.fs';
69
70    let context = getContext(this);
71    async function read() {
72      let path = context.filesDir;
73      const filePath = path + '/voice_call_data.wav';
74      let file: fs.File = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
75      let bufferSize: number = await audioCapturer.getBufferSize();
76      let buffer: ArrayBuffer = await audioCapturer.read(bufferSize, true);
77      fs.writeSync(file.fd, buffer);
78    }
79   ```
80
814. Call **stop()** to stop recording.
82
83   ```ts
84    import { BusinessError } from '@ohos.base';
85
86    audioCapturer.stop((err: BusinessError) => {
87      if (err) {
88        console.error(`Capturer stop failed, code is ${err.code}, message is ${err.message}`);
89      } else {
90        console.info('Capturer stopped.');
91      }
92    });
93   ```
94
955. Call **release()** to release the instance.
96
97   ```ts
98    import { BusinessError } from '@ohos.base';
99
100    audioCapturer.release((err: BusinessError) => {
101      if (err) {
102        console.error(`capturer release failed, code is ${err.code}, message is ${err.message}`);
103      } else {
104        console.info('capturer released.');
105      }
106    });
107   ```
108
109
110### Sample Code
111
112Refer to the sample code below to record audio using AudioCapturer.
113
114```ts
115import audio from '@ohos.multimedia.audio';
116import fs from '@ohos.file.fs';
117
118const TAG = 'AudioCapturerDemo';
119let context = getContext(this);
120
121let audioCapturer: audio.AudioCapturer | undefined = undefined;
122let audioStreamInfo: audio.AudioStreamInfo = {
123  samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_44100,
124  channels: audio.AudioChannel.CHANNEL_1,
125  sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,
126  encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW
127}
128let audioCapturerInfo: audio.AudioCapturerInfo = {
129  source: audio.SourceType.SOURCE_TYPE_MIC, // Audio source type.
130  capturerFlags: 0 // Flag indicating an AudioCapturer.
131}
132let audioCapturerOptions: audio.AudioCapturerOptions = {
133  streamInfo: audioStreamInfo,
134  capturerInfo: audioCapturerInfo
135}
136
137// Create an AudioCapturer instance, and set the events to listen for.
138async function init() {
139  audio.createAudioCapturer(audioCapturerOptions, (err, capturer) => { // Create an AudioCapturer instance.
140    if (err) {
141      console.error(`Invoke createAudioCapturer failed, code is ${err.code}, message is ${err.message}`);
142      return;
143    }
144    console.info(`${TAG}: create AudioCapturer success`);
145    audioCapturer = capturer;
146    if (audioCapturer !== undefined) {
147      (audioCapturer as audio.AudioCapturer).on('markReach', 1000, (position: number) => { // Subscribe to the markReach event. A callback is triggered when the number of captured frames reaches 1000.
148        if (position === 1000) {
149          console.info('ON Triggered successfully');
150        }
151      });
152      (audioCapturer as audio.AudioCapturer).on('periodReach', 2000, (position: number) => { // Subscribe to the periodReach event. A callback is triggered when the number of captured frames reaches 2000.
153        if (position === 2000) {
154          console.info('ON Triggered successfully');
155        }
156      });
157    }
158  });
159}
160
161// Start audio recording.
162async function start() {
163  if (audioCapturer !== undefined) {
164    let stateGroup = [audio.AudioState.STATE_PREPARED, audio.AudioState.STATE_PAUSED, audio.AudioState.STATE_STOPPED];
165    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.
166      console.error(`${TAG}: start failed`);
167      return;
168    }
169    await (audioCapturer as audio.AudioCapturer).start(); // Start recording.
170    const filePath = context.filesDir + '/test.wav'; // Path for storing the recorded audio file.
171    let file: fs.File = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); // Create the file if it does not exist.
172    let fd = file.fd;
173    let numBuffersToCapture = 150; // Write data for 150 times.
174    let count = 0;
175    class Options {
176      offset: number = 0;
177      length: number = 0
178    }
179    while (numBuffersToCapture) {
180      let bufferSize = await (audioCapturer as audio.AudioCapturer).getBufferSize();
181      let buffer = await (audioCapturer as audio.AudioCapturer).read(bufferSize, true);
182      let options: Options = {
183        offset: count * bufferSize,
184        length: bufferSize
185      };
186      if (buffer === undefined) {
187        console.error(`${TAG}: read buffer failed`);
188      } else {
189        let number = fs.writeSync(fd, buffer, options);
190        console.info(`${TAG}: write date: ${number}`);
191      }
192      numBuffersToCapture--;
193      count++;
194    }
195  }
196}
197
198// Stop recording.
199async function stop() {
200  if (audioCapturer !== undefined) {
201    // The AudioCapturer can be stopped only when it is in the STATE_RUNNING or STATE_PAUSED state.
202    if ((audioCapturer as audio.AudioCapturer).state.valueOf() !== audio.AudioState.STATE_RUNNING && (audioCapturer as audio.AudioCapturer).state.valueOf() !== audio.AudioState.STATE_PAUSED) {
203      console.info('Capturer is not running or paused');
204      return;
205    }
206    await (audioCapturer as audio.AudioCapturer).stop(); // Stop recording.
207    if ((audioCapturer as audio.AudioCapturer).state.valueOf() === audio.AudioState.STATE_STOPPED) {
208       console.info('Capturer stopped');
209    } else {
210       console.error('Capturer stop failed');
211    }
212  }
213}
214
215// Release the instance.
216async function release() {
217  if (audioCapturer !== undefined) {
218    // The AudioCapturer can be released only when it is not in the STATE_RELEASED or STATE_NEW state.
219    if ((audioCapturer as audio.AudioCapturer).state.valueOf() === audio.AudioState.STATE_RELEASED || (audioCapturer as audio.AudioCapturer).state.valueOf() === audio.AudioState.STATE_NEW) {
220      console.info('Capturer already released');
221      return;
222    }
223    await (audioCapturer as audio.AudioCapturer).release(); // Release resources.
224    if ((audioCapturer as audio.AudioCapturer).state.valueOf() === audio.AudioState.STATE_RELEASED) {
225      console.info('Capturer released');
226    } else {
227      console.error('Capturer release failed');
228    }
229  }
230}
231```
232