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