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