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, 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 60 class Options { 61 offset?: number; 62 length?: number; 63 } 64 65 let bufferSize: number = 0; 66 let path = getContext().cacheDir; 67 let filePath = path + '/StarWars10s-2C-48000-4SW.pcm'; 68 let file: fs.File = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); 69 let readDataCallback = (buffer: ArrayBuffer) => { 70 let options: Options = { 71 offset: bufferSize, 72 length: buffer.byteLength 73 } 74 fs.writeSync(file.fd, buffer, options); 75 bufferSize += buffer.byteLength; 76 }; 77 78 audioCapturer.on('readData', readDataCallback); 79 ``` 80 813. 调用start()方法进入running状态,开始录制音频。 82 83 ```ts 84 import { BusinessError } from '@kit.BasicServicesKit'; 85 86 audioCapturer.start((err: BusinessError) => { 87 if (err) { 88 console.error(`Capturer start failed, code is ${err.code}, message is ${err.message}`); 89 } else { 90 console.info('Capturer start success.'); 91 } 92 }); 93 ``` 94 954. 调用stop()方法停止录制。 96 97 ```ts 98 import { BusinessError } from '@kit.BasicServicesKit'; 99 100 audioCapturer.stop((err: BusinessError) => { 101 if (err) { 102 console.error(`Capturer stop failed, code is ${err.code}, message is ${err.message}`); 103 } else { 104 console.info('Capturer stopped.'); 105 } 106 }); 107 ``` 108 1095. 调用release()方法销毁实例,释放资源。 110 111 ```ts 112 import { BusinessError } from '@kit.BasicServicesKit'; 113 114 audioCapturer.release((err: BusinessError) => { 115 if (err) { 116 console.error(`capturer release failed, code is ${err.code}, message is ${err.message}`); 117 } else { 118 console.info('capturer released.'); 119 } 120 }); 121 ``` 122 123### 完整示例 124 125下面展示了使用AudioCapturer录制音频的完整示例代码。 126 127```ts 128import { audio } from '@kit.AudioKit'; 129import { BusinessError } from '@kit.BasicServicesKit'; 130import { fileIo as fs } from '@kit.CoreFileKit'; 131 132const TAG = 'AudioCapturerDemo'; 133 134class Options { 135 offset?: number; 136 length?: number; 137} 138 139let bufferSize: number = 0; 140let audioCapturer: audio.AudioCapturer | undefined = undefined; 141let audioStreamInfo: audio.AudioStreamInfo = { 142 samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // 采样率 143 channels: audio.AudioChannel.CHANNEL_2, // 通道 144 sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // 采样格式 145 encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // 编码格式 146}; 147let audioCapturerInfo: audio.AudioCapturerInfo = { 148 source: audio.SourceType.SOURCE_TYPE_MIC, // 音源类型 149 capturerFlags: 0 // 音频采集器标志 150}; 151let audioCapturerOptions: audio.AudioCapturerOptions = { 152 streamInfo: audioStreamInfo, 153 capturerInfo: audioCapturerInfo 154}; 155let path = getContext().cacheDir; 156let filePath = path + '/StarWars10s-2C-48000-4SW.pcm'; 157let file: fs.File = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); 158let readDataCallback = (buffer: ArrayBuffer) => { 159 let options: Options = { 160 offset: bufferSize, 161 length: buffer.byteLength 162 } 163 fs.writeSync(file.fd, buffer, options); 164 bufferSize += buffer.byteLength; 165}; 166 167// 初始化,创建实例,设置监听事件 168function init() { 169 audio.createAudioCapturer(audioCapturerOptions, (err, capturer) => { // 创建AudioCapturer实例 170 if (err) { 171 console.error(`Invoke createAudioCapturer failed, code is ${err.code}, message is ${err.message}`); 172 return; 173 } 174 console.info(`${TAG}: create AudioCapturer success`); 175 audioCapturer = capturer; 176 if (audioCapturer !== undefined) { 177 (audioCapturer as audio.AudioCapturer).on('readData', readDataCallback); 178 } 179 }); 180} 181 182// 开始一次音频采集 183function start() { 184 if (audioCapturer !== undefined) { 185 let stateGroup = [audio.AudioState.STATE_PREPARED, audio.AudioState.STATE_PAUSED, audio.AudioState.STATE_STOPPED]; 186 if (stateGroup.indexOf((audioCapturer as audio.AudioCapturer).state.valueOf()) === -1) { // 当且仅当状态为STATE_PREPARED、STATE_PAUSED和STATE_STOPPED之一时才能启动采集 187 console.error(`${TAG}: start failed`); 188 return; 189 } 190 191 // 启动采集 192 (audioCapturer as audio.AudioCapturer).start((err: BusinessError) => { 193 if (err) { 194 console.error('Capturer start failed.'); 195 } else { 196 console.info('Capturer start success.'); 197 } 198 }); 199 } 200} 201 202// 停止采集 203function stop() { 204 if (audioCapturer !== undefined) { 205 // 只有采集器状态为STATE_RUNNING或STATE_PAUSED的时候才可以停止 206 if ((audioCapturer as audio.AudioCapturer).state.valueOf() !== audio.AudioState.STATE_RUNNING && (audioCapturer as audio.AudioCapturer).state.valueOf() !== audio.AudioState.STATE_PAUSED) { 207 console.info('Capturer is not running or paused'); 208 return; 209 } 210 211 //停止采集 212 (audioCapturer as audio.AudioCapturer).stop((err: BusinessError) => { 213 if (err) { 214 console.error('Capturer stop failed.'); 215 } else { 216 fs.close(file); 217 console.info('Capturer stop success.'); 218 } 219 }); 220 } 221} 222 223// 销毁实例,释放资源 224function release() { 225 if (audioCapturer !== undefined) { 226 // 采集器状态不是STATE_RELEASED或STATE_NEW状态,才能release 227 if ((audioCapturer as audio.AudioCapturer).state.valueOf() === audio.AudioState.STATE_RELEASED || (audioCapturer as audio.AudioCapturer).state.valueOf() === audio.AudioState.STATE_NEW) { 228 console.info('Capturer already released'); 229 return; 230 } 231 232 //释放资源 233 (audioCapturer as audio.AudioCapturer).release((err: BusinessError) => { 234 if (err) { 235 console.error('Capturer release failed.'); 236 } else { 237 console.info('Capturer release success.'); 238 } 239 }); 240 } 241} 242``` 243