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 25using namespace OHOS; 26using namespace OHOS::Audio; 27using namespace OHOS::Media; 28using namespace std; 29 30struct AudioSourceInput { 31 size_t framesize; 32 uint8_t *buffer; 33 AudioCapturer *audioCap; 34 AudioCodecFormat audioFormat; 35 std::thread processThread; 36 bool bThreadRun; 37}; 38 39enum AppState { 40 AV_ON, 41 AV_OFF 42}; 43 44static AudioSourceInput g_audioSourceProcessInput; 45 46static 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 95static 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 135struct CapturerInfo { 136 AudioCodecFormat audioFormat; 137 int32_t sampleRate; 138 int32_t bitRate; 139}; 140 141static 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 157static 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 176static 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 190static 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 200static 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 212static 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 228static 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 248static 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 277int 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