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