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