• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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