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 <cstdio>
17 #include <thread>
18 #include <climits>
19 #include <cstdlib>
20 #include "audio_capturer.h"
21 #include "audio_log.h"
22 #include "audio_renderer.h"
23 #include "pcm2wav.h"
24
25 using namespace std;
26 using namespace OHOS;
27 using namespace OHOS::AudioStandard;
28
29 namespace AudioTestConstants {
30 constexpr int32_t ARGS_INDEX_RENDERER_TEST_PATH = 1;
31 constexpr int32_t ARGS_INDEX_CAPTURER_TEST_PATH = 2;
32 constexpr int32_t ARGS_COUNT_THREE = 3;
33 constexpr int32_t SUCCESS = 0;
34
35 constexpr int32_t SAMPLE_FORMAT_U8 = 8;
36 constexpr int32_t SAMPLE_FORMAT_S16LE = 16;
37 constexpr int32_t SAMPLE_FORMAT_S24LE = 24;
38 constexpr int32_t SAMPLE_FORMAT_S32LE = 32;
39 }
40
41 class AudioVoIPTest {
42 public:
InitRender(const unique_ptr<AudioRenderer> & audioRenderer,const AudioRendererParams & rendererParams) const43 bool InitRender(const unique_ptr<AudioRenderer> &audioRenderer, const AudioRendererParams &rendererParams) const
44 {
45 if (audioRenderer->SetParams(rendererParams) != AudioTestConstants::SUCCESS) {
46 AUDIO_ERR_LOG("AudioVoIPTest: Set audio renderer parameters failed");
47 if (!audioRenderer->Release()) {
48 AUDIO_ERR_LOG("AudioVoIPTest: Release failed");
49 }
50 return false;
51 }
52 AUDIO_INFO_LOG("AudioVoIPTest: Playback renderer created");
53
54 AUDIO_INFO_LOG("AudioVoIPTest: Starting renderer");
55 if (!audioRenderer->Start()) {
56 AUDIO_ERR_LOG("AudioVoIPTest: Start failed");
57 if (!audioRenderer->Release()) {
58 AUDIO_ERR_LOG("AudioVoIPTest: Release failed");
59 }
60 return false;
61 }
62 AUDIO_INFO_LOG("AudioVoIPTest: Playback started");
63
64 return true;
65 }
66
StartRender(const unique_ptr<AudioRenderer> & audioRenderer,FILE * wavFile) const67 bool StartRender(const unique_ptr<AudioRenderer> &audioRenderer, FILE* wavFile) const
68 {
69 size_t bufferLen = 0;
70 if (audioRenderer->GetBufferSize(bufferLen)) {
71 return false;
72 }
73 AUDIO_DEBUG_LOG("minimum buffer length: %{public}zu", bufferLen);
74
75 int32_t n = 2;
76 auto buffer = std::make_unique<uint8_t[]>(n * bufferLen);
77 if (buffer == nullptr) {
78 AUDIO_ERR_LOG("AudioVoIPTest: Failed to allocate buffer");
79 return false;
80 }
81
82 size_t bytesToWrite = 0;
83 size_t bytesWritten = 0;
84 size_t minBytes = 4;
85
86 while (!feof(wavFile)) {
87 bytesToWrite = fread(buffer.get(), 1, bufferLen, wavFile);
88 bytesWritten = 0;
89 AUDIO_INFO_LOG("AudioVoIPTest: Bytes to write: %{public}zu", bytesToWrite);
90
91 while ((bytesWritten < bytesToWrite) && ((bytesToWrite - bytesWritten) > minBytes)) {
92 bytesWritten += audioRenderer->Write(buffer.get() + bytesWritten,
93 bytesToWrite - bytesWritten);
94 AUDIO_INFO_LOG("AudioVoIPTest: Bytes written: %{public}zu", bytesWritten);
95 if (bytesWritten < 0) {
96 break;
97 }
98 }
99 }
100
101 if (!audioRenderer->Drain()) {
102 AUDIO_ERR_LOG("AudioVoIPTest: Drain failed");
103 }
104
105 return true;
106 }
107
GetSampleFormat(int32_t wavSampleFormat) const108 AudioSampleFormat GetSampleFormat(int32_t wavSampleFormat) const
109 {
110 switch (wavSampleFormat) {
111 case AudioTestConstants::SAMPLE_FORMAT_U8:
112 return AudioSampleFormat::SAMPLE_U8;
113 case AudioTestConstants::SAMPLE_FORMAT_S16LE:
114 return AudioSampleFormat::SAMPLE_S16LE;
115 case AudioTestConstants::SAMPLE_FORMAT_S24LE:
116 return AudioSampleFormat::SAMPLE_S24LE;
117 case AudioTestConstants::SAMPLE_FORMAT_S32LE:
118 return AudioSampleFormat::SAMPLE_S32LE;
119 default:
120 return AudioSampleFormat::INVALID_WIDTH;
121 }
122 }
123
TestPlayback(char * inputPath) const124 bool TestPlayback(char *inputPath) const
125 {
126 AUDIO_INFO_LOG("AudioVoIPTest: TestPlayback start ");
127
128 wav_hdr wavHeader;
129 size_t headerSize = sizeof(wav_hdr);
130 char path[PATH_MAX + 1] = {0x00};
131 if ((strlen(inputPath) > PATH_MAX) || (realpath(inputPath, path) == nullptr)) {
132 AUDIO_ERR_LOG("Invalid path");
133 return false;
134 }
135 AUDIO_INFO_LOG("AudioVoIPTest: path = %{public}s", path);
136 FILE* wavFile = fopen(path, "rb");
137 if (wavFile == nullptr) {
138 AUDIO_INFO_LOG("AudioVoIPTest: Unable to open wave file");
139 return false;
140 }
141 size_t bytesRead = fread(&wavHeader, 1, headerSize, wavFile);
142 AUDIO_INFO_LOG("AudioVoIPTest: Header Read in bytes %{public}zu", bytesRead);
143
144 AudioStreamType streamType = AudioStreamType::STREAM_VOICE_CALL;
145 unique_ptr<AudioRenderer> audioRenderer = AudioRenderer::Create(streamType);
146
147 AudioRendererParams rendererParams;
148 rendererParams.sampleFormat = GetSampleFormat(wavHeader.bitsPerSample);
149 rendererParams.sampleRate = static_cast<AudioSamplingRate>(wavHeader.SamplesPerSec);
150 rendererParams.channelCount = static_cast<AudioChannel>(wavHeader.NumOfChan);
151 rendererParams.encodingType = static_cast<AudioEncodingType>(ENCODING_PCM);
152 if (!InitRender(audioRenderer, rendererParams)) {
153 AUDIO_ERR_LOG("AudioVoIPTest: Init render failed");
154 fclose(wavFile);
155 return false;
156 }
157
158 if (!StartRender(audioRenderer, wavFile)) {
159 AUDIO_ERR_LOG("AudioVoIPTest: Start render failed");
160 fclose(wavFile);
161 return false;
162 }
163
164 if (!audioRenderer->Stop()) {
165 AUDIO_ERR_LOG("AudioVoIPTest: Stop failed");
166 }
167
168 if (!audioRenderer->Release()) {
169 AUDIO_ERR_LOG("AudioVoIPTest: Release failed");
170 }
171
172 fclose(wavFile);
173 AUDIO_INFO_LOG("AudioVoIPTest: TestPlayback end");
174
175 return true;
176 }
177
InitCapture(const unique_ptr<AudioCapturer> & audioCapturer,const AudioCapturerParams & capturerParams) const178 bool InitCapture(const unique_ptr<AudioCapturer> &audioCapturer, const AudioCapturerParams &capturerParams) const
179 {
180 if (audioCapturer->SetParams(capturerParams) != AudioTestConstants::SUCCESS) {
181 AUDIO_ERR_LOG("Set audio stream parameters failed");
182 audioCapturer->Release();
183 return false;
184 }
185 AUDIO_INFO_LOG("Capture stream created");
186
187 AUDIO_INFO_LOG("Starting Stream");
188 if (!audioCapturer->Start()) {
189 AUDIO_ERR_LOG("Start stream failed");
190 audioCapturer->Release();
191 return false;
192 }
193 AUDIO_INFO_LOG("Capturing started");
194
195 return true;
196 }
197
StartCapture(const unique_ptr<AudioCapturer> & audioCapturer,bool isBlocking,FILE * pFile) const198 bool StartCapture(const unique_ptr<AudioCapturer> &audioCapturer, bool isBlocking, FILE *pFile) const
199 {
200 size_t bufferLen;
201 if (audioCapturer->GetBufferSize(bufferLen) < 0) {
202 AUDIO_ERR_LOG(" GetMinimumBufferSize failed");
203 return false;
204 }
205
206 auto buffer = std::make_unique<uint8_t[]>(bufferLen);
207 if (buffer == nullptr) {
208 AUDIO_ERR_LOG("AudioVoIPTest: Failed to allocate buffer");
209 return false;
210 }
211
212 size_t size = 1;
213 size_t numBuffersToCapture = 256;
214 while (numBuffersToCapture) {
215 size_t bytesRead = 0;
216 while (bytesRead < bufferLen) {
217 int32_t len = audioCapturer->Read(*(buffer.get() + bytesRead), bufferLen - bytesRead, isBlocking);
218 if (len >= 0) {
219 bytesRead += len;
220 } else {
221 bytesRead = len;
222 break;
223 }
224 }
225 if (bytesRead < 0) {
226 AUDIO_ERR_LOG("Bytes read failed. error code %{public}zu", bytesRead);
227 break;
228 } else if (bytesRead == 0) {
229 continue;
230 }
231
232 if (fwrite(buffer.get(), size, bytesRead, pFile) != bytesRead) {
233 AUDIO_ERR_LOG("error occurred in fwrite");
234 }
235 numBuffersToCapture--;
236 }
237
238 return true;
239 }
240
TestRecording(char * capturePath) const241 bool TestRecording(char *capturePath) const
242 {
243 AUDIO_INFO_LOG("TestCapture start ");
244
245 unique_ptr<AudioCapturer> audioCapturer = AudioCapturer::Create(AudioStreamType::STREAM_VOICE_CALL);
246
247 AudioCapturerParams capturerParams;
248 capturerParams.audioSampleFormat = SAMPLE_S16LE;
249 capturerParams.samplingRate = SAMPLE_RATE_44100;
250 capturerParams.audioChannel = AudioChannel::STEREO;
251 capturerParams.audioEncoding = ENCODING_PCM;
252 if (!InitCapture(audioCapturer, capturerParams)) {
253 AUDIO_ERR_LOG("Initialize capturer failed");
254 return false;
255 }
256
257 bool isBlocking = true;
258 FILE *pFile = fopen(capturePath, "wb");
259 if (pFile == nullptr) {
260 AUDIO_INFO_LOG("AudioVoIPTest: Unable to open file");
261 return false;
262 }
263
264 if (!StartCapture(audioCapturer, isBlocking, pFile)) {
265 AUDIO_ERR_LOG("Start capturer failed");
266 fclose(pFile);
267 return false;
268 }
269
270 fflush(pFile);
271 if (!audioCapturer->Flush()) {
272 AUDIO_ERR_LOG("AudioVoIPTest: flush failed");
273 }
274
275 if (!audioCapturer->Stop()) {
276 AUDIO_ERR_LOG("AudioVoIPTest: Stop failed");
277 }
278
279 if (!audioCapturer->Release()) {
280 AUDIO_ERR_LOG("AudioVoIPTest: Release failed");
281 }
282 fclose(pFile);
283 AUDIO_INFO_LOG("TestCapture end");
284
285 return true;
286 }
287 };
288
main(int argc,char * argv[])289 int main(int argc, char *argv[])
290 {
291 AUDIO_INFO_LOG("AudioVoIPTest: Render test in");
292
293 if ((argv == nullptr) || (argc < AudioTestConstants::ARGS_COUNT_THREE)) {
294 AUDIO_ERR_LOG("AudioVoIPTest: argv is null");
295 return 0;
296 }
297
298 AUDIO_INFO_LOG("AudioVoIPTest: argc=%d", argc);
299 AUDIO_INFO_LOG("AudioVoIPTest: renderer test path = %{public}s",
300 argv[AudioTestConstants::ARGS_INDEX_RENDERER_TEST_PATH]);
301 AUDIO_INFO_LOG("AudioVoIPTest: capturer test path = %{public}s",
302 argv[AudioTestConstants::ARGS_INDEX_CAPTURER_TEST_PATH]);
303
304 AudioVoIPTest *renderTestObj = new(std::nothrow) AudioVoIPTest();
305 if (!renderTestObj) {
306 AUDIO_ERR_LOG("AudioVoIPTest: create renderer object failed");
307 return 0;
308 }
309
310 AudioVoIPTest *captureTestObj = new(std::nothrow) AudioVoIPTest();
311 if (!captureTestObj) {
312 AUDIO_ERR_LOG("AudioVoIPTest: create capturer object failed");
313 delete renderTestObj;
314 renderTestObj = nullptr;
315 return 0;
316 }
317
318 std::thread renderThread(&AudioVoIPTest::TestPlayback, renderTestObj,
319 argv[AudioTestConstants::ARGS_INDEX_RENDERER_TEST_PATH]);
320
321 std::thread captureThread(&AudioVoIPTest::TestRecording, captureTestObj,
322 argv[AudioTestConstants::ARGS_INDEX_CAPTURER_TEST_PATH]);
323
324 renderThread.join();
325 captureThread.join();
326
327 delete renderTestObj;
328 renderTestObj = nullptr;
329 delete captureTestObj;
330 captureTestObj = nullptr;
331
332 return 0;
333 }
334