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