• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 音频采集开发指导
2
3## 简介
4
5AudioCapturer提供了用于获取原始音频文件的方法。开发者可以通过本指导了解应用如何通过AudioCapturer接口的调用实现音频数据的采集。
6
7- **状态检查**:在进行应用开发的过程中,建议开发者通过on('stateChange')方法订阅AudioCapturer的状态变更。因为针对AudioCapturer的某些操作,仅在音频采集器在固定状态时才能执行。如果应用在音频采集器处于错误状态时执行操作,系统可能会抛出异常或生成其他未定义的行为。
8
9## 运作机制
10
11该模块提供了音频采集模块的状态变化示意图。
12
13**图1** 音频采集状态变化示意图
14
15![audio-capturer-state](figures/audio-capturer-state.png)
16
17**PREPARED状态:** 通过调用create()方法进入到该状态。<br>
18**RUNNING状态:** 正在进行音频数据播放,可以在prepared状态通过调用start()方法进入此状态,也可以在stopped状态通过调用start()方法进入此状态。<br>
19**STOPPED状态:** 在running状态可以通过stop()方法停止音频数据的播放。<br>
20**RELEASED状态:** 在prepared和stop状态,用户均可通过release()方法释放掉所有占用的硬件和软件资源,并且不会再进入到其他的任何一种状态了。<br>
21
22## 约束与限制
23
24开发者在进行音频数据采集功能开发前,需要先对所开发的应用配置麦克风权限(ohos.permission.MICROPHONE),配置方式请参见[访问控制授权申请](../security/accesstoken-guidelines.md#配置文件权限声明)。
25
26## 开发指导
27
28详细API含义可参考:[音频管理API文档AudioCapturer](../reference/apis/js-apis-audio.md#audiocapturer8)
29
301. 使用createAudioCapturer()创建一个全局的AudioCapturer实例。
31
32   在audioCapturerOptions中设置音频采集器的相关参数。该实例可用于音频采集、控制和获取采集状态,以及注册通知回调。
33
34   ```js
35  import audio from '@ohos.multimedia.audio';
36  import fs from '@ohos.file.fs';  //便于步骤3 read函数调用
37
38  //音频渲染相关接口自测试
39  @Entry
40  @Component
41  struct AudioRenderer {
42    @State message: string = 'Hello World'
43    private audioCapturer : audio.AudioCapturer;  //供全局调用
44
45    async initAudioCapturer(){
46      let audioStreamInfo = {
47        samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_44100,
48        channels: audio.AudioChannel.CHANNEL_1,
49        sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,
50        encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW
51      }
52
53      let audioCapturerInfo = {
54        source: audio.SourceType.SOURCE_TYPE_MIC,
55        capturerFlags: 0 // 0是音频采集器的扩展标志位,默认为0
56      }
57
58      let audioCapturerOptions = {
59        streamInfo: audioStreamInfo,
60        capturerInfo: audioCapturerInfo
61      }
62
63      this.audioCapturer = await audio.createAudioCapturer(audioCapturerOptions);
64      console.log('AudioRecLog: Create audio capturer success.');
65    }
66   ```
67
682. 调用start()方法来启动/恢复采集任务。
69
70   启动完成后,采集器状态将变更为STATE_RUNNING,然后应用可以开始读取缓冲区。
71
72   ```js
73   async  startCapturer() {
74     let state = this.audioCapturer.state;
75     // Capturer start时的状态应该是STATE_PREPARED、STATE_PAUSED和STATE_STOPPED之一.
76     if (state == audio.AudioState.STATE_PREPARED || state == audio.AudioState.STATE_PAUSED ||
77     state == audio.AudioState.STATE_STOPPED) {
78       await this.audioCapturer.start();
79       state = this.audioCapturer.state;
80       if (state == audio.AudioState.STATE_RUNNING) {
81         console.info('AudioRecLog: Capturer started');
82       } else {
83         console.error('AudioRecLog: Capturer start failed');
84       }
85     }
86   }
87   ```
88
893. 读取采集器的音频数据并将其转换为字节流。重复调用read()方法读取数据,直到应用准备停止采集。
90
91   参考以下示例,将采集到的数据写入文件。
92
93   ```js
94   async readData(){
95     let state = this.audioCapturer.state;
96     // 只有状态为STATE_RUNNING的时候才可以read.
97     if (state != audio.AudioState.STATE_RUNNING) {
98       console.info('Capturer is not in a correct state to read');
99       return;
100     }
101     const path = '/data/data/.pulse_dir/capture_js.wav'; // 采集到的音频文件存储路径
102     let file = fs.openSync(path, 0o2);
103     let fd = file.fd;
104     if (file !== null) {
105       console.info('AudioRecLog: file created');
106     } else {
107       console.info('AudioRecLog: file create : FAILED');
108       return;
109     }
110     if (fd !== null) {
111       console.info('AudioRecLog: file fd opened in append mode');
112     }
113     let numBuffersToCapture = 150; // 循环写入150次
114     let count = 0;
115     while (numBuffersToCapture) {
116       this.bufferSize = await this.audioCapturer.getBufferSize();
117       let buffer = await this.audioCapturer.read(this.bufferSize, true);
118       let options = {
119         offset: count * this.bufferSize,
120         length: this.bufferSize
121       }
122       if (typeof(buffer) == undefined) {
123         console.info('AudioRecLog: read buffer failed');
124       } else {
125         let number = fs.writeSync(fd, buffer, options);
126         console.info(`AudioRecLog: data written: ${number}`);
127       }
128       numBuffersToCapture--;
129       count++;
130     }
131   }
132   ```
133
1344. 采集完成后,调用stop方法,停止录制。
135
136   ```js
137   async  StopCapturer() {
138     let state = this.audioCapturer.state;
139     // 只有采集器状态为STATE_RUNNING或STATE_PAUSED的时候才可以停止
140     if (state != audio.AudioState.STATE_RUNNING && state != audio.AudioState.STATE_PAUSED) {
141       console.info('AudioRecLog: Capturer is not running or paused');
142       return;
143     }
144
145     await this.audioCapturer.stop();
146
147     state = this.audioCapturer.state;
148     if (state == audio.AudioState.STATE_STOPPED) {
149       console.info('AudioRecLog: Capturer stopped');
150     } else {
151       console.error('AudioRecLog: Capturer stop failed');
152     }
153   }
154   ```
155
1565. 任务结束,调用release()方法释放相关资源。
157
158   ```js
159   async releaseCapturer() {
160     let state = this.audioCapturer.state;
161     // 采集器状态不是STATE_RELEASED或STATE_NEW状态,才能release
162     if (state == audio.AudioState.STATE_RELEASED || state == audio.AudioState.STATE_NEW) {
163       console.info('AudioRecLog: Capturer already released');
164       return;
165     }
166
167     await this.audioCapturer.release();
168
169     state = this.audioCapturer.state;
170     if (state == audio.AudioState.STATE_RELEASED) {
171       console.info('AudioRecLog: Capturer released');
172     } else {
173       console.info('AudioRecLog: Capturer release failed');
174     }
175   }
176   ```
177
1786. (可选)获取采集器相关信息
179
180   通过以下代码,可以获取采集器的相关信息。
181
182   ```js
183   async getAudioCapturerInfo(){
184     // 获取当前采集器状态
185     let state = this.audioCapturer.state;
186     // 获取采集器信息
187     let audioCapturerInfo : audio.AudioCapturerInfo = await this.audioCapturer.getCapturerInfo();
188     // 获取音频流信息
189     let audioStreamInfo : audio.AudioStreamInfo = await this.audioCapturer.getStreamInfo();
190     // 获取音频流ID
191     let audioStreamId : number = await this.audioCapturer.getAudioStreamId();
192     // 获取纳秒形式的Unix时间戳
193     let audioTime : number = await this.audioCapturer.getAudioTime();
194     // 获取合理的最小缓冲区大小
195     let bufferSize : number = await this.audioCapturer.getBufferSize();
196   }
197   ```
198
1997. (可选)使用on('markReach')方法订阅采集器标记到达事件,使用off('markReach')取消订阅事件。
200
201    注册markReach监听后,当采集器采集的帧数到达设定值时,会触发回调并返回设定的值。
202
203    ```js
204    async markReach(){
205      this.audioCapturer.on('markReach', 10, (reachNumber) => {
206        console.info('Mark reach event Received');
207        console.info(`The Capturer reached frame: ${reachNumber}`);
208      });
209      this.audioCapturer.off('markReach'); // 取消markReach事件的订阅,后续将无法监听到“标记到达”事件
210    }
211    ```
212
2138. (可选)使用on('periodReach')方法订阅采集器区间标记到达事件,使用off('periodReach')取消订阅事件。
214
215    注册periodReach监听后,**每当**采集器采集的帧数到达设定值时,会触发回调并返回设定的值。
216
217    ```js
218    async periodReach(){
219      this.audioCapturer.on('periodReach', 10, (reachNumber) => {
220        console.info('Period reach event Received');
221        console.info(`In this period, the Capturer reached frame: ${reachNumber}`);
222      });
223      this.audioCapturer.off('periodReach'); // 取消periodReach事件的订阅,后续将无法监听到“区间标记到达”事件
224    }
225    ```
226
2279. 如果应用需要在采集器状态更新时进行一些操作,可以订阅该事件,当采集器状态更新时,会受到一个包含有事件类型的回调。
228
229    ```js
230    async stateChange(){
231      this.audioCapturer.on('stateChange', (state) => {
232        console.info(`AudioCapturerLog: Changed State to : ${state}`)
233        switch (state) {
234          case audio.AudioState.STATE_PREPARED:
235            console.info('--------CHANGE IN AUDIO STATE----------PREPARED--------------');
236            console.info('Audio State is : Prepared');
237            break;
238          case audio.AudioState.STATE_RUNNING:
239            console.info('--------CHANGE IN AUDIO STATE----------RUNNING--------------');
240            console.info('Audio State is : Running');
241            break;
242          case audio.AudioState.STATE_STOPPED:
243            console.info('--------CHANGE IN AUDIO STATE----------STOPPED--------------');
244            console.info('Audio State is : stopped');
245            break;
246          case audio.AudioState.STATE_RELEASED:
247            console.info('--------CHANGE IN AUDIO STATE----------RELEASED--------------');
248            console.info('Audio State is : released');
249            break;
250          default:
251            console.info('--------CHANGE IN AUDIO STATE----------INVALID--------------');
252            console.info('Audio State is : invalid');
253            break;
254        }
255      });
256    }
257    ```