• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 使用AudioCapturer开发音频录制功能
2
3AudioCapturer是音频采集器,用于录制PCM(Pulse Code Modulation)音频数据,适合有音频开发经验的开发者实现更灵活的录制功能。
4
5## 开发指导
6
7使用AudioCapturer录制音频涉及到AudioCapturer实例的创建、音频采集参数的配置、采集的开始与停止、资源的释放等。本开发指导将以一次录制音频数据的过程为例,向开发者讲解如何使用AudioCapturer进行音频录制,建议搭配[AudioCapturer的API说明](../../reference/apis-audio-kit/js-apis-audio.md#audiocapturer8)阅读。
8
9下图展示了AudioCapturer的状态变化,在创建实例后,调用对应的方法可以进入指定的状态实现对应的行为。需要注意的是在确定的状态执行不合适的方法可能导致AudioCapturer发生错误,建议开发者在调用状态转换的方法前进行状态检查,避免程序运行产生预期以外的结果。
10
11**图1** AudioCapturer状态变化示意图
12
13![AudioCapturer status change](figures/audiocapturer-status-change.png)
14
15使用on('stateChange')方法可以监听AudioCapturer的状态变化,每个状态对应值与说明见[AudioState](../../reference/apis-audio-kit/js-apis-audio.md#audiostate8)。
16
17### 开发步骤及注意事项
18
191. 配置音频采集参数并创建AudioCapturer实例,音频采集参数的详细信息可以查看[AudioCapturerOptions](../../reference/apis-audio-kit/js-apis-audio.md#audiocaptureroptions8)。
20
21   > **说明:**
22   > 当设置Mic音频源(即[SourceType](../../reference/apis-audio-kit/js-apis-audio.md#sourcetype8)为SOURCE_TYPE_MIC、SOURCE_TYPE_VOICE_RECOGNITION、SOURCE_TYPE_VOICE_COMMUNICATION、SOURCE_TYPE_VOICE_MESSAGE)时,需要申请麦克风权限ohos.permission.MICROPHONE,申请方式参考:[向用户申请授权](../../security/AccessToken/request-user-authorization.md)。
23
24   ```ts
25    import { audio } from '@kit.AudioKit';
26
27    let audioStreamInfo: audio.AudioStreamInfo = {
28      samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // 采样率。
29      channels: audio.AudioChannel.CHANNEL_2, // 通道。
30      sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // 采样格式。
31      encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // 编码格式。
32    };
33
34    let audioCapturerInfo: audio.AudioCapturerInfo = {
35      source: audio.SourceType.SOURCE_TYPE_MIC, // 音源类型:Mic音频源。根据业务场景配置,参考SourceType。
36      capturerFlags: 0 // 音频采集器标志。
37    };
38
39    let audioCapturerOptions: audio.AudioCapturerOptions = {
40      streamInfo: audioStreamInfo,
41      capturerInfo: audioCapturerInfo
42    };
43
44    audio.createAudioCapturer(audioCapturerOptions, (err, data) => {
45      if (err) {
46        console.error(`Invoke createAudioCapturer failed, code is ${err.code}, message is ${err.message}`);
47      } else {
48        console.info('Invoke createAudioCapturer succeeded.');
49        let audioCapturer = data;
50      }
51    });
52   ```
53
542. 调用on('readData')方法,订阅监听音频数据读入回调。
55
56   ```ts
57    import { BusinessError } from '@kit.BasicServicesKit';
58    import { fileIo as fs } from '@kit.CoreFileKit';
59    import { common } from '@kit.AbilityKit';
60
61    class Options {
62      offset?: number;
63      length?: number;
64    }
65
66    let bufferSize: number = 0;
67    // 请在组件内获取context,确保this.getUIContext().getHostContext()返回结果为UIAbilityContext。
68    let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
69    let path = context.cacheDir;
70    let filePath = path + '/StarWars10s-2C-48000-4SW.pcm';
71    let file: fs.File = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
72    let readDataCallback = (buffer: ArrayBuffer) => {
73      let options: Options = {
74        offset: bufferSize,
75        length: buffer.byteLength
76      }
77      fs.writeSync(file.fd, buffer, options);
78      bufferSize += buffer.byteLength;
79    };
80
81    audioCapturer.on('readData', readDataCallback);
82   ```
83
843. 调用start()方法进入running状态,开始录制音频。
85
86   ```ts
87    import { BusinessError } from '@kit.BasicServicesKit';
88
89    audioCapturer.start((err: BusinessError) => {
90      if (err) {
91        console.error(`Capturer start failed, code is ${err.code}, message is ${err.message}`);
92      } else {
93        console.info('Capturer start success.');
94      }
95    });
96   ```
97
984. 调用stop()方法停止录制。
99
100   ```ts
101    import { BusinessError } from '@kit.BasicServicesKit';
102
103    audioCapturer.stop((err: BusinessError) => {
104      if (err) {
105        console.error(`Capturer stop failed, code is ${err.code}, message is ${err.message}`);
106      } else {
107        console.info('Capturer stopped.');
108      }
109    });
110   ```
111
1125. 调用release()方法销毁实例,释放资源。
113
114   ```ts
115    import { BusinessError } from '@kit.BasicServicesKit';
116
117    audioCapturer.release((err: BusinessError) => {
118      if (err) {
119        console.error(`capturer release failed, code is ${err.code}, message is ${err.message}`);
120      } else {
121        console.info('capturer released.');
122      }
123    });
124   ```
125
126### 完整示例
127
128下面展示了使用AudioCapturer录制音频的完整示例代码。
129
130```ts
131import { audio } from '@kit.AudioKit';
132import { BusinessError } from '@kit.BasicServicesKit';
133import { fileIo as fs } from '@kit.CoreFileKit';
134import { common } from '@kit.AbilityKit';
135
136const TAG = 'AudioCapturerDemo';
137
138class Options {
139  offset?: number;
140  length?: number;
141}
142
143let bufferSize: number = 0;
144let audioCapturer: audio.AudioCapturer | undefined = undefined;
145let audioStreamInfo: audio.AudioStreamInfo = {
146  samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // 采样率。
147  channels: audio.AudioChannel.CHANNEL_2, // 通道。
148  sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // 采样格式。
149  encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // 编码格式。
150};
151let audioCapturerInfo: audio.AudioCapturerInfo = {
152  source: audio.SourceType.SOURCE_TYPE_MIC, // 音源类型:Mic音频源。根据业务场景配置,参考SourceType。
153  capturerFlags: 0 // 音频采集器标志。
154};
155let audioCapturerOptions: audio.AudioCapturerOptions = {
156  streamInfo: audioStreamInfo,
157  capturerInfo: audioCapturerInfo
158};
159// 请在组件内获取context,确保this.getUIContext().getHostContext()返回结果为UIAbilityContext。
160let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
161let path = context.cacheDir;
162let filePath = path + '/StarWars10s-2C-48000-4SW.pcm';
163let file: fs.File = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
164let readDataCallback = (buffer: ArrayBuffer) => {
165   let options: Options = {
166      offset: bufferSize,
167      length: buffer.byteLength
168   }
169   fs.writeSync(file.fd, buffer, options);
170   bufferSize += buffer.byteLength;
171};
172
173// 初始化,创建实例,设置监听事件。
174function init() {
175  audio.createAudioCapturer(audioCapturerOptions, (err, capturer) => { // 创建AudioCapturer实例。
176    if (err) {
177      console.error(`Invoke createAudioCapturer failed, code is ${err.code}, message is ${err.message}`);
178      return;
179    }
180    console.info(`${TAG}: create AudioCapturer success`);
181    audioCapturer = capturer;
182    if (audioCapturer !== undefined) {
183       (audioCapturer as audio.AudioCapturer).on('readData', readDataCallback);
184    }
185  });
186}
187
188// 开始一次音频采集。
189function start() {
190  if (audioCapturer !== undefined) {
191    let stateGroup = [audio.AudioState.STATE_PREPARED, audio.AudioState.STATE_PAUSED, audio.AudioState.STATE_STOPPED];
192    if (stateGroup.indexOf((audioCapturer as audio.AudioCapturer).state.valueOf()) === -1) { // 当且仅当状态为STATE_PREPARED、STATE_PAUSED和STATE_STOPPED之一时才能启动采集。
193      console.error(`${TAG}: start failed`);
194      return;
195    }
196
197    // 启动采集。
198    (audioCapturer as audio.AudioCapturer).start((err: BusinessError) => {
199      if (err) {
200        console.error('Capturer start failed.');
201      } else {
202        console.info('Capturer start success.');
203      }
204    });
205  }
206}
207
208// 停止采集。
209function stop() {
210  if (audioCapturer !== undefined) {
211    // 只有采集器状态为STATE_RUNNING或STATE_PAUSED的时候才可以停止。
212    if ((audioCapturer as audio.AudioCapturer).state.valueOf() !== audio.AudioState.STATE_RUNNING && (audioCapturer as audio.AudioCapturer).state.valueOf() !== audio.AudioState.STATE_PAUSED) {
213      console.info('Capturer is not running or paused');
214      return;
215    }
216
217    //停止采集。
218    (audioCapturer as audio.AudioCapturer).stop((err: BusinessError) => {
219      if (err) {
220        console.error('Capturer stop failed.');
221      } else {
222        fs.close(file);
223        console.info('Capturer stop success.');
224      }
225    });
226  }
227}
228
229// 销毁实例,释放资源。
230function release() {
231  if (audioCapturer !== undefined) {
232    // 采集器状态不是STATE_RELEASED或STATE_NEW状态,才能release。
233    if ((audioCapturer as audio.AudioCapturer).state.valueOf() === audio.AudioState.STATE_RELEASED || (audioCapturer as audio.AudioCapturer).state.valueOf() === audio.AudioState.STATE_NEW) {
234      console.info('Capturer already released');
235      return;
236    }
237
238    //释放资源。
239    (audioCapturer as audio.AudioCapturer).release((err: BusinessError) => {
240      if (err) {
241        console.error('Capturer release failed.');
242      } else {
243        console.info('Capturer release success.');
244      }
245    });
246  }
247}
248```
249