1 /*
2 * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <ctime>
17 #include <iostream>
18 #include <string>
19 #include <thread>
20 #include <unistd.h>
21 #include "audio_capturer.h"
22 #include "media_errors.h"
23 #include "securec.h"
24
25 using namespace OHOS;
26 using namespace OHOS::Audio;
27 using namespace OHOS::Media;
28 using namespace std;
29
30 struct AudioSourceInput {
31 size_t framesize;
32 uint8_t *buffer;
33 AudioCapturer *audioCap;
34 AudioCodecFormat audioFormat;
35 std::thread processThread;
36 bool bThreadRun;
37 };
38
39 enum AppState {
40 AV_ON,
41 AV_OFF
42 };
43
44 static AudioSourceInput g_audioSourceProcessInput;
45
GernerateFileName(AudioCodecFormat format)46 static char *GernerateFileName(AudioCodecFormat format)
47 {
48 time_t stCurrent;
49 char aszDatetime[0x100];
50 (void)time(&stCurrent);
51 struct tm *pstCurrentTime = localtime(&(stCurrent));
52 if (pstCurrentTime == nullptr) {
53 return nullptr;
54 }
55 if (strftime(aszDatetime, 0x100, "%Y-%m-%d-%H-%M-%S", pstCurrentTime) > 0) {
56 std::cout << "Current Time: " << aszDatetime << std::endl;
57 }
58
59 string postfix;
60 switch (format) {
61 case PCM:
62 postfix = "pcm";
63 break;
64 case AAC_LC:
65 postfix = "aac";
66 break;
67 case G711A:
68 postfix = "g711a";
69 break;
70 case G711U:
71 postfix = "g711u";
72 break;
73 case G726:
74 postfix = "g726";
75 break;
76 default:
77 return nullptr;
78 }
79
80 const int32_t size = 0x180;
81 char *name = static_cast<char *>(malloc(size));
82 if (name == nullptr) {
83 return nullptr;
84 }
85 (void)memset_s(name, size, 0, size);
86 /* create file for save stream */
87 if (snprintf_s(name, size, size - 1, "/userdata/audio_%s.%s", aszDatetime, postfix.c_str()) < 0) {
88 std::cout << "snprintf_s failed " << std::endl;
89 free(name);
90 return nullptr;
91 }
92 return name;
93 }
94
AudioInputSourceProcess(AudioSourceInput * audioSourceInput)95 static void AudioInputSourceProcess(AudioSourceInput *audioSourceInput)
96 {
97 const int32_t waitTimeUs = 20000;
98 std::cout << "audioSourceInput: " << audioSourceInput << std::endl;
99 if (audioSourceInput == nullptr) {
100 return;
101 }
102
103 char *fileName = GernerateFileName(audioSourceInput->audioFormat);
104 if (fileName == nullptr) {
105 return;
106 }
107
108 FILE *pfd = fopen(fileName, "w+");
109 if (pfd == nullptr) {
110 std::cout << "open file failed " << fileName << std::endl;
111 free(fileName);
112 return;
113 }
114 std::cout << "Open SUCCESS " << fileName << std::endl;
115 int readCnt = 0;
116 while (audioSourceInput->bThreadRun) {
117 int ret = audioSourceInput->audioCap->Read(audioSourceInput->buffer,
118 audioSourceInput->framesize, false);
119 if (ret <= 0) {
120 std::cout << "audioCap Read failed ret:" << ret << std::endl;
121 usleep(waitTimeUs);
122 continue;
123 }
124 if (fwrite(audioSourceInput->buffer, 1, ret, pfd) != ret) {
125 std::cout << "fwrite failed errno:"<< errno << std::endl;
126 break;
127 }
128 readCnt++;
129 std::cout << "audioCap Read readCnt: "<< readCnt << " size: " << ret << std::endl;
130 }
131 (void)fclose(pfd);
132 free(fileName);
133 }
134
135 struct CapturerInfo {
136 AudioCodecFormat audioFormat;
137 int32_t sampleRate;
138 int32_t bitRate;
139 };
140
GetAudioFormat(void)141 static AudioCodecFormat GetAudioFormat(void)
142 {
143 std::cout << "*******************************************" << endl;
144 std::cout << "SetCapturerInfo (PCM:1, AAC_LC:2, G711A:7, G711U:8, G726:9)" << endl;
145 std::cout << "*******************************************" << endl;
146 int32_t audioFormat;
147 std::cin >> audioFormat;
148 cout << "input audioFormat:" << audioFormat << endl;
149 if (audioFormat != 1 && audioFormat != 0x2 && audioFormat != 0x7 &&
150 audioFormat != 0x8 && audioFormat != 0x9) {
151 std::cout << "Can't support input format:" << static_cast<int32_t> (audioFormat) << std::endl;
152 return FORMAT_BUTT;
153 }
154 return static_cast<AudioCodecFormat> (audioFormat);
155 }
156
GetDefaultSampleRateAndRateBaseFormat(AudioCodecFormat format,int32_t & sr,int32_t & rate)157 static void GetDefaultSampleRateAndRateBaseFormat(AudioCodecFormat format, int32_t &sr, int32_t &rate)
158 {
159 const CapturerInfo audioCapturerInfo[] = {
160 {PCM, 16000, 128000},
161 {AAC_LC, 48000, 128000},
162 {G711A, 8000, 64000},
163 {G711U, 8000, 64000},
164 {G726, 8000, 24000}
165 };
166
167 int validCapInfoNum = sizeof(audioCapturerInfo) / sizeof(audioCapturerInfo[0]);
168 for (int i = 0; i < validCapInfoNum; i++) {
169 if (format == audioCapturerInfo[i].audioFormat) {
170 sr = audioCapturerInfo[i].sampleRate;
171 rate = audioCapturerInfo[i].bitRate;
172 }
173 }
174 }
175
GetChannelCount(void)176 static int32_t GetChannelCount(void)
177 {
178 std::cout << "*******************************************" << endl;
179 std::cout << "SetCapturerInfo (channelCount:1, channelCount:2)" << endl;
180 std::cout << "*******************************************" << endl;
181 int32_t channelCount;
182 std::cin >> channelCount;
183 if (channelCount != 1 && channelCount != 0x2) {
184 std::cout << "Can't support input channelCount:" << channelCount << std::endl;
185 return -1;
186 }
187 return channelCount;
188 }
189
ShowCmdInfo(void)190 static void ShowCmdInfo(void)
191 {
192 cout << "*******************************************" << endl;
193 cout << "Select the behavior of audio capturer." << endl;
194 cout << "s or S-----start audio capturer" << endl;
195 cout << "p or P-----stop audio capturer" << endl;
196 cout << "q or Q-----quit audio capturer" << endl;
197 cout << "*******************************************" << endl;
198 }
199
TaskQuit(AudioCapturer & audioCap,AppState & state)200 static void TaskQuit(AudioCapturer &audioCap, AppState &state)
201 {
202 if (state == AV_ON) {
203 g_audioSourceProcessInput.bThreadRun = false;
204 g_audioSourceProcessInput.processThread.join();
205 if (!audioCap.Stop()) {
206 std::cout << "Stop audioCap failed, quit record\n" << endl;
207 }
208 state = AV_OFF;
209 }
210 }
211
TaskStop(AudioCapturer & audioCap,AppState & state)212 static int32_t TaskStop(AudioCapturer &audioCap, AppState &state)
213 {
214 if (state == AV_ON) {
215 g_audioSourceProcessInput.bThreadRun = false;
216 g_audioSourceProcessInput.processThread.join();
217 if (!audioCap.Stop()) {
218 std::cout << "Stop audioCap fialed, stop record " << endl;
219 return -1;
220 }
221 state = AV_OFF;
222 } else {
223 std::cout << "Start recorder first." << endl;
224 }
225 return 0;
226 }
227
TaskStart(AudioCapturer & audioCap,AppState & state)228 static int32_t TaskStart(AudioCapturer &audioCap, AppState &state)
229 {
230 if (state == AV_ON) {
231 return 0;
232 }
233
234 if (!audioCap.Start()) {
235 std::cout << "Can't Start..." << endl;
236 delete g_audioSourceProcessInput.buffer;
237 return -1;
238 }
239 g_audioSourceProcessInput.audioCap = &audioCap;
240 g_audioSourceProcessInput.bThreadRun = true;
241 g_audioSourceProcessInput.processThread = std::thread(AudioInputSourceProcess,
242 &g_audioSourceProcessInput);
243 state = AV_ON;
244 std::cout << "Recording..." << endl;
245 return 0;
246 }
247
RumCmd(AudioCapturer & audioCap)248 static void RumCmd(AudioCapturer &audioCap)
249 {
250 ShowCmdInfo();
251 char input;
252 AppState state = AV_OFF;
253 while (std::cin >> input) {
254 switch (input) {
255 case 's':
256 case 'S':
257 if (TaskStart(audioCap, state) != 0) {
258 return;
259 }
260 break;
261 case 'p':
262 case 'P':
263 if (TaskStop(audioCap, state) != 0) {
264 return;
265 }
266 break;
267 case 'q':
268 case 'Q':
269 TaskQuit(audioCap, state);
270 return;
271 default:
272 break;
273 }
274 }
275 }
276
main(int argc,char * argv[])277 int main(int argc, char *argv[])
278 {
279 std::cout << "audio_capture_sample " << std::endl;
280 int ret = 0;
281 size_t frameCount;
282 AudioCapturer audioCap;
283
284 AudioCapturerInfo info;
285 info.inputSource = AUDIO_MIC;
286 info.bitWidth = BIT_WIDTH_16;
287 AudioCodecFormat audioFormat = GetAudioFormat();
288 if (audioFormat == FORMAT_BUTT) {
289 return -1;
290 }
291 info.audioFormat = audioFormat;
292 g_audioSourceProcessInput.audioFormat = audioFormat;
293 GetDefaultSampleRateAndRateBaseFormat(audioFormat, info.sampleRate, info.bitRate);
294
295 info.channelCount = GetChannelCount();
296 if (info.channelCount == -1) {
297 return -1;
298 }
299
300 std::cout << " SetCapturerInfo" << std::endl;
301 if ((ret = audioCap.SetCapturerInfo(info)) != 0) {
302 std::cout << "Can't SetCapturerInfo " << std::endl;
303 delete g_audioSourceProcessInput.buffer;
304 return -1;
305 }
306 frameCount = audioCap.GetFrameCount();
307 std::cout << "GetFrameCount " << frameCount << std::endl;
308 g_audioSourceProcessInput.framesize = frameCount * 0x400;
309 g_audioSourceProcessInput.buffer = new uint8_t[g_audioSourceProcessInput.framesize];
310
311 RumCmd(audioCap);
312
313 audioCap.Release();
314 delete g_audioSourceProcessInput.buffer;
315 g_audioSourceProcessInput.buffer = nullptr;
316 return 0;
317 }
318