1 /*
2  * Copyright (c) 2021-2022 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 #ifndef LOG_TAG
16 #define LOG_TAG "AudioCapturerTest"
17 #endif
18 
19 #include <chrono>
20 #include <cstdint>
21 #include <cstdio>
22 #include <cstring>
23 #include <vector>
24 #include <cstdlib>
25 #include <memory>
26 #include "unistd.h"
27 #include "audio_capturer.h"
28 #include "audio_info.h"
29 #include "audio_capturer_log.h"
30 
31 using namespace std;
32 using namespace std::chrono;
33 using namespace OHOS;
34 using namespace OHOS::AudioStandard;
35 int32_t bufferMsec = 0;
36 namespace AudioTestConstants {
37     constexpr int32_t FIRST_ARG_IDX = 1;
38     constexpr int32_t SECOND_ARG_IDX = 2;
39     constexpr int32_t THIRD_ARG_IDX = 3;
40     constexpr int32_t FOURTH_ARG_IDX = 4;
41     constexpr int32_t NUM_BASE = 10;
42     constexpr int32_t PAUSE_BUFFER_POSITION = 128;
43     constexpr int32_t PAUSE_READ_TIME_SECONDS = 2;
44     constexpr int32_t SUCCESS = 0;
45 }
46 
47 class AudioCapturerCallbackTestImpl : public AudioCapturerCallback {
48 public:
OnInterrupt(const InterruptEvent & interruptEvent)49     void OnInterrupt(const InterruptEvent &interruptEvent) override
50     {
51         AUDIO_DEBUG_LOG("AudioCapturerCallbackTestImpl: OnInterrupt Hint : %{public}d eventType : %{public}d,\
52             forceType : %{public}d", interruptEvent.hintType, interruptEvent.eventType, interruptEvent.forceType);
53     }
54 
OnStateChange(const CapturerState state)55     void OnStateChange(const CapturerState state) override
56     {
57         AUDIO_DEBUG_LOG("AudioCapturerCallbackTestImpl:: OnStateChange");
58 
59         switch (state) {
60             case CAPTURER_PREPARED:
61                 AUDIO_DEBUG_LOG("AudioCapturerCallbackTestImpl: OnStateChange CAPTURER_PREPARED");
62                 break;
63             case CAPTURER_RUNNING:
64                 AUDIO_DEBUG_LOG("AudioCapturerCallbackTestImpl: OnStateChange CAPTURER_RUNNING");
65                 break;
66             case CAPTURER_STOPPED:
67                 AUDIO_DEBUG_LOG("AudioCapturerCallbackTestImpl: OnStateChange CAPTURER_STOPPED");
68                 break;
69             case CAPTURER_RELEASED:
70                 AUDIO_DEBUG_LOG("AudioCapturerCallbackTestImpl: OnStateChange CAPTURER_RELEASED");
71                 break;
72             default:
73                 AUDIO_ERR_LOG("AudioCapturerCallbackTestImpl: OnStateChange NOT A VALID state");
74                 break;
75         }
76     }
77 };
78 
79 class AudioCapturerTest {
80 public:
CheckSupportedParams() const81     void CheckSupportedParams() const
82     {
83         vector<AudioSampleFormat> supportedFormatList = AudioCapturer::GetSupportedFormats();
84         AUDIO_INFO_LOG("Supported formats:");
85         for (auto i = supportedFormatList.begin(); i != supportedFormatList.end(); ++i) {
86             AUDIO_INFO_LOG("Format %{public}d", *i);
87         }
88 
89         vector<AudioChannel> supportedChannelList = AudioCapturer::GetSupportedChannels();
90         AUDIO_INFO_LOG("Supported channels:");
91         for (auto i = supportedChannelList.begin(); i != supportedChannelList.end(); ++i) {
92             AUDIO_INFO_LOG("channel %{public}d", *i);
93         }
94 
95         vector<AudioEncodingType> supportedEncodingTypes
96                                     = AudioCapturer::GetSupportedEncodingTypes();
97         AUDIO_INFO_LOG("Supported encoding types:");
98         for (auto i = supportedEncodingTypes.begin(); i != supportedEncodingTypes.end(); ++i) {
99             AUDIO_INFO_LOG("encoding type %{public}d", *i);
100         }
101 
102         vector<AudioSamplingRate> supportedSamplingRates = AudioCapturer::GetSupportedSamplingRates();
103         AUDIO_INFO_LOG("Supported sampling rates:");
104         for (auto i = supportedSamplingRates.begin(); i != supportedSamplingRates.end(); ++i) {
105             AUDIO_INFO_LOG("sampling rate %{public}d", *i);
106         }
107     }
108 
InitCapture(const unique_ptr<AudioCapturer> & audioCapturer) const109     bool InitCapture(const unique_ptr<AudioCapturer> &audioCapturer) const
110     {
111         AUDIO_INFO_LOG("Starting Stream");
112         if (!audioCapturer->Start()) {
113             AUDIO_ERR_LOG("Start stream failed");
114             audioCapturer->Release();
115             return false;
116         }
117         AUDIO_INFO_LOG("Capturing started");
118 
119         AUDIO_INFO_LOG("Get Audio parameters:");
120         AudioCapturerParams getCapturerParams;
121         if (audioCapturer->GetParams(getCapturerParams) == AudioTestConstants::SUCCESS) {
122             AUDIO_INFO_LOG("Get Audio format: %{public}d", getCapturerParams.audioSampleFormat);
123             AUDIO_INFO_LOG("Get Audio sampling rate: %{public}d", getCapturerParams.samplingRate);
124             AUDIO_INFO_LOG("Get Audio channels: %{public}d", getCapturerParams.audioChannel);
125         }
126 
127         return true;
128     }
129 
StartCapture(const unique_ptr<AudioCapturer> & audioCapturer,bool isBlocking,FILE * pFile) const130     bool StartCapture(const unique_ptr<AudioCapturer> &audioCapturer, bool isBlocking, FILE *pFile) const
131     {
132         size_t bufferLen;
133         if (audioCapturer->GetBufferSize(bufferLen) < 0) {
134             AUDIO_ERR_LOG(" GetMinimumBufferSize failed");
135             return false;
136         }
137 
138         auto buffer = std::make_unique<uint8_t[]>(bufferLen);
139         if (buffer == nullptr) {
140             AUDIO_ERR_LOG("AudioCapturerTest: Failed to allocate buffer");
141             return false;
142         }
143         AUDIO_INFO_LOG("AudioPerf Capturer First Frame Read, BUFFER_LEN = %{public}zu", bufferLen);
144         size_t size = 1;
145         size_t numBuffersToCapture = 256;
146         while (numBuffersToCapture) {
147             size_t bytesRead = 0;
148             while (bytesRead < bufferLen) {
149                 auto start = high_resolution_clock::now();
150                 int32_t len = audioCapturer->Read(*(buffer.get() + bytesRead), bufferLen - bytesRead, isBlocking);
151                 auto stop = high_resolution_clock::now();
152                 auto duration = duration_cast<microseconds>(stop - start);
153                 AUDIO_INFO_LOG("AudioPerf Capturer Read in microseconds TimeTaken =%{public}lld",
154                     (long long)duration.count());
155                 if (len >= 0) {
156                     bytesRead += len;
157                 } else {
158                     bytesRead = len;
159                     break;
160                 }
161             }
162             if (bytesRead < 0) {
163                 AUDIO_ERR_LOG("Bytes read failed. error code %{public}zu", bytesRead);
164                 break;
165             } else if (bytesRead == 0) {
166                 continue;
167             }
168 
169             if (fwrite(buffer.get(), size, bytesRead, pFile) != bytesRead) {
170                 AUDIO_ERR_LOG("error occurred in fwrite");
171             }
172             numBuffersToCapture--;
173             if ((numBuffersToCapture == AudioTestConstants::PAUSE_BUFFER_POSITION)
174                 && (audioCapturer->Stop())) {
175                 AUDIO_INFO_LOG("Audio capture stopped for %{public}d seconds",
176                                AudioTestConstants::PAUSE_READ_TIME_SECONDS);
177                 sleep(AudioTestConstants::PAUSE_READ_TIME_SECONDS);
178                 if (!audioCapturer->Start()) {
179                     AUDIO_ERR_LOG("resume stream failed");
180                     audioCapturer->Release();
181                     break;
182                 }
183                 AUDIO_INFO_LOG("AudioPerf Capturer Read after stop and start");
184             }
185         }
186 
187         return true;
188     }
189 
TestRecording(int32_t samplingRate,bool isBlocking,string filePath) const190     bool TestRecording(int32_t samplingRate, bool isBlocking, string filePath) const
191     {
192         AUDIO_INFO_LOG("TestCapture start ");
193         AudioCapturerOptions capturerOptions;
194         capturerOptions.streamInfo.samplingRate = static_cast<AudioSamplingRate>(samplingRate);
195         capturerOptions.streamInfo.encoding = AudioEncodingType::ENCODING_PCM;
196         capturerOptions.streamInfo.format = AudioSampleFormat::SAMPLE_S16LE;
197         capturerOptions.streamInfo.channels = AudioChannel::STEREO;
198         capturerOptions.capturerInfo.sourceType = SourceType::SOURCE_TYPE_MIC;
199         capturerOptions.capturerInfo.capturerFlags = 0;
200 
201         unique_ptr<AudioCapturer> audioCapturer = AudioCapturer::Create(capturerOptions);
202 
203         int32_t ret = 0;
204         shared_ptr<AudioCapturerCallback> cb1 = make_shared<AudioCapturerCallbackTestImpl>();
205         ret = audioCapturer->SetCapturerCallback(cb1);
206         if (ret) {
207             AUDIO_ERR_LOG("AudioCapturerTest: SetCapturerCallback failed %{public}d", ret);
208             return false;
209         }
210 
211         CheckSupportedParams();
212         AUDIO_ERR_LOG("AudioCaptruerTest: buffermsec = %{public}d", bufferMsec);
213         int32_t status = audioCapturer->SetBufferDuration(bufferMsec);
214         if (status) {
215             AUDIO_ERR_LOG("Failed to set buffer duration");
216         }
217 
218         if (!InitCapture(audioCapturer)) {
219             AUDIO_ERR_LOG("Initialize capturer failed");
220             return false;
221         }
222 
223         AUDIO_INFO_LOG("Is blocking read: %{public}s", isBlocking ? "true" : "false");
224         FILE *pFile = fopen(filePath.c_str(), "wb");
225         if (pFile == nullptr) {
226             AUDIO_INFO_LOG("AudioCapturerTest: Unable to open file");
227             return false;
228         }
229 
230         if (!StartCapture(audioCapturer, isBlocking, pFile)) {
231             AUDIO_ERR_LOG("Start capturer failed");
232             fclose(pFile);
233             return false;
234         }
235 
236         fflush(pFile);
237         if (!audioCapturer->Flush()) {
238             AUDIO_ERR_LOG("AudioCapturerTest: flush failed");
239         }
240 
241         if (!audioCapturer->Stop()) {
242             AUDIO_ERR_LOG("AudioCapturerTest: Stop failed");
243         }
244 
245         if (!audioCapturer->Release()) {
246             AUDIO_ERR_LOG("AudioCapturerTest: Release failed");
247         }
248         fclose(pFile);
249         AUDIO_INFO_LOG("TestCapture end");
250 
251         return true;
252     }
253 };
254 
main(int argc,char * argv[])255 int main(int argc, char *argv[])
256 {
257     AUDIO_INFO_LOG("capture test in");
258 
259     if ((argv == nullptr) || (argc <= AudioTestConstants::THIRD_ARG_IDX)) {
260         AUDIO_ERR_LOG("argv is null");
261         return 0;
262     }
263 
264     AUDIO_INFO_LOG("argc=%d", argc);
265     AUDIO_INFO_LOG("argv[1]=%{public}s", argv[AudioTestConstants::FIRST_ARG_IDX]);
266     AUDIO_INFO_LOG("argv[2]=%{public}s", argv[AudioTestConstants::SECOND_ARG_IDX]);
267     AUDIO_INFO_LOG("argv[3]=%{public}s", argv[AudioTestConstants::THIRD_ARG_IDX]);
268 
269     int32_t samplingRate = atoi(argv[AudioTestConstants::SECOND_ARG_IDX]);
270     bool isBlocking = (atoi(argv[AudioTestConstants::THIRD_ARG_IDX]) == 1);
271     string filePath = argv[AudioTestConstants::FIRST_ARG_IDX];
272     if (argc > AudioTestConstants::FOURTH_ARG_IDX) {
273         bufferMsec = strtol(argv[AudioTestConstants::FOURTH_ARG_IDX], nullptr, AudioTestConstants::NUM_BASE);
274     }
275     AudioCapturerTest testObj;
276     bool ret = testObj.TestRecording(samplingRate, isBlocking, filePath);
277 
278     return ret;
279 }
280