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 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