1 /*
2 * Copyright (c) 2023 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 #include <cstdio>
16 #include <iostream>
17
18 #include "audio_capturer.h"
19 #include "audio_errors.h"
20 #include "audio_info.h"
21 #include "audio_log.h"
22 #include "audio_renderer.h"
23 #include "audio_utils.h"
24 #include "parameter.h"
25 #include "pcm2wav.h"
26
27 namespace OHOS {
28 namespace AudioStandard {
29 std::map<int32_t, std::string> g_OptStrMap = {
30 {INIT_LOCAL_SPK, "call local spk init process"},
31 {INIT_REMOTE_SPK, "call remote spk init process"},
32 {START_SPK, "call start spk process"},
33 {STOP_SPK, "call stop spk process"},
34 {RELEASE_SPK, "release spk process"},
35
36 {INIT_LOCAL_MIC, "call local mic init process"},
37 {INIT_REMOTE_MIC, "call remote mic init process"},
38 {START_MIC, "call start mic process"},
39 {STOP_MIC, "call stop mic process"},
40 {RELEASE_MIC, "release mic process"},
41
42 {EXIT_DEMO, "exit interactive run test"},
43 };
44
45 enum AudioOptCode : int32_t {
46 INIT_LOCAL_SPK = 0,
47 INIT_REMOTE_SPK = 1,
48 START_SPK = 2,
49 STOP_SPK = 3,
50 RELEASE_SPK = 4,
51 INIT_LOCAL_MIC = 5,
52 INIT_REMOTE_MIC = 6,
53 START_MIC = 7,
54 STOP_MIC = 8,
55 RELEASE_MIC = 9,
56 EXIT_DEMO = 10,
57 };
58
59 class PlaybackTest : public AudioRendererWriteCallback,
60 public AudioCapturerReadCallback,
61 public std::enable_shared_from_this<PlaybackTest> {
62 public:
63 int32_t InitRenderer();
64 int32_t StartPlay();
65 int32_t StopPlay();
66 int32_t InitCapturer();
67 int32_t StartCapture();
68 int32_t StopCapture();
69 void OnWriteData(size_t length) override;
70 void OnReadData(size_t length) override;
71 bool OpenSpkFile(const std::string &spkFilePath);
72 bool OpenMicFile(const std::string &micFilePath);
73 void CloseSpkFile();
74 void CloseMicFile();
75
76 private:
77 std::unique_ptr<AudioStandard::AudioRenderer> audioRenderer_ = nullptr;
78 std::unique_ptr<AudioStandard::AudioCapturer> audioCapturer_ = nullptr;
79 static constexpr long WAV_HEADER_SIZE = 44;
80 bool needSkipWavHeader_ = true;
81 FILE *spkWavFile_ = nullptr;
82 FILE *micWavFile_ = nullptr;
83 };
84
OnWriteData(size_t length)85 void PlaybackTest::OnWriteData(size_t length)
86 {
87 BufferDesc bufDesc;
88 if (audioRenderer_ == nullptr) {
89 AUDIO_ERR_LOG("audioRenderer is nullptr.");
90 return;
91 }
92 audioRenderer_->GetBufferDesc(bufDesc);
93
94 if (spkWavFile_ == nullptr) {
95 AUDIO_ERR_LOG("spkWavFile_ is nullptr.");
96 return;
97 }
98 if (needSkipWavHeader_) {
99 fseek(spkWavFile_, WAV_HEADER_SIZE, SEEK_SET);
100 needSkipWavHeader_ = false;
101 }
102 if (feof(spkWavFile_)) {
103 fseek(spkWavFile_, WAV_HEADER_SIZE, SEEK_SET); // infinite loop
104 }
105 if (renderFinish_) {
106 AUDIO_INFO_LOG("%{public}s render finish.", __func__);
107 return;
108 }
109 fread(bufDesc.buffer, 1, bufDesc.bufLength, spkWavFile_);
110 audioRenderer_->Enqueue(bufDesc);
111 }
112
OpenSpkFile(const std::string & spkFilePath)113 bool PlaybackTest::OpenSpkFile(const std::string &spkFilePath)
114 {
115 if (spkWavFile_ != nullptr) {
116 AUDIO_ERR_LOG("Spk file has been opened, spkFilePath %{public}s", spkFilePath.c_str());
117 return true;
118 }
119
120 char path[PATH_MAX] = { 0x00 };
121 if ((strlen(spkFilePath.c_str()) > PATH_MAX) || (realpath(spkFilePath.c_str(), path) == nullptr)) {
122 return false;
123 }
124 AUDIO_INFO_LOG("spk path = %{public}s", path);
125 spkWavFile_ = fopen(path, "rb");
126 if (spkWavFile_ == nullptr) {
127 AUDIO_ERR_LOG("Unable to open wave file");
128 return false;
129 }
130 return true;
131 }
132
CloseSpkFile()133 void PlaybackTest::CloseSpkFile()
134 {
135 if (spkWavFile_ != nullptr) {
136 fclose(spkWavFile_);
137 spkWavFile_ = nullptr;
138 }
139 }
140
InitRenderer()141 int32_t PlaybackTest::InitRenderer()
142 {
143 AudioStandard::AudioRendererOptions rendererOptions = {
144 {
145 AudioStandard::AudioSamplingRate::SAMPLE_RATE_48000,
146 AudioStandard::AudioEncodingType::ENCODING_PCM,
147 AudioStandard::AudioSampleFormat::SAMPLE_S16LE,
148 AudioStandard::AudioChannel::STEREO,
149 },
150 {
151 AudioStandard::ContentType::CONTENT_TYPE_MUSIC,
152 AudioStandard::StreamUsage::STREAM_USAGE_MEDIA,
153 AudioStandard::STREAM_FLAG_FAST, // fast audio stream
154 }
155 };
156 audioRenderer_ = AudioStandard::AudioRenderer::Create(rendererOptions);
157 if (audioRenderer_ == nullptr) {
158 AUDIO_ERR_LOG("Audio renderer create failed.");
159 return -1;
160 }
161 std::string path = "/data/test.wav";
162 OpenSpkFile(path);
163 int32_t ret = audioRenderer_->SetRendererWriteCallback(shared_from_this());
164 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "Client test save data callback fail, ret %{public}d.", ret);
165 AUDIO_INFO_LOG("Audio renderer create success.");
166 return 0;
167 }
168
StartPlay()169 int32_t PlaybackTest::StartPlay()
170 {
171 if (audioRenderer_ == nullptr) {
172 AUDIO_ERR_LOG("Audiorenderer init failed.");
173 return -1;
174 }
175 if (!audioRenderer_->Start()) {
176 AUDIO_ERR_LOG("Audio renderer start failed.");
177 return -1;
178 }
179 return 0;
180 }
181
StopPlay()182 int32_t PlaybackTest::StopPlay()
183 {
184 if (audioRenderer_ == nullptr) {
185 AUDIO_ERR_LOG("Audiorenderer init failed.");
186 return -1;
187 }
188 if (!audioRenderer_->Stop()) {
189 AUDIO_ERR_LOG("Audio renderer stop failed.");
190 return -1;
191 }
192 return 0;
193 }
194
OnReadData(size_t length)195 void PlaybackTest::OnReadData(size_t length)
196 {
197 BufferDesc bufDesc;
198 if (audioCapturer_ == nullptr) {
199 AUDIO_ERR_LOG("audioCapturer is nullptr.");
200 return;
201 }
202 int32_t ret = audioCapturer_->GetBufferDesc(bufDesc);
203 if (ret != 0 || bufDesc.buffer == nullptr || bufDesc.bufLength == 0) {
204 AUDIO_ERR_LOG("Get buffer desc failed. On read data.");
205 return;
206 }
207 if (micWavFile_ == nullptr) {
208 AUDIO_ERR_LOG("micWavFile_ is nullptr.");
209 return;
210 }
211 size_t cnt = fwrite(bufDesc.buffer, 1, bufDesc.bufLength, micWavFile_);
212 if (cnt != bufDesc.bufLength) {
213 AUDIO_ERR_LOG("fwrite fail, cnt %{public}zu, bufLength %{public}zu.", cnt, bufDesc.bufLength);
214 return;
215 }
216 audioCapturer_->Enqueue(bufDesc);
217 }
218
OpenMicFile(const std::string & micFilePath)219 bool PlaybackTest::OpenMicFile(const std::string &micFilePath)
220 {
221 if (micWavFile_ != nullptr) {
222 AUDIO_ERR_LOG("Mic file has been opened, micFilePath %{public}s.", micFilePath.c_str());
223 return true;
224 }
225
226 char path[PATH_MAX] = { 0x00 };
227 if ((strlen(micFilePath.c_str()) > PATH_MAX) || (realpath(micFilePath.c_str(), path) == nullptr)) {
228 AUDIO_ERR_LOG("micFilePath is not valid.");
229 return false;
230 }
231 AUDIO_INFO_LOG("mic path = %{public}s.", path);
232 micWavFile_ = fopen(path, "ab+");
233 if (micWavFile_ == nullptr) {
234 AUDIO_ERR_LOG("Unable to open wave file");
235 return false;
236 }
237 return true;
238 }
239
CloseMicFile()240 void PlaybackTest::CloseMicFile()
241 {
242 if (micWavFile_ != nullptr) {
243 fclose(micWavFile_);
244 micWavFile_ = nullptr;
245 }
246 }
247
InitCapturer()248 int32_t PlaybackTest::InitCapturer()
249 {
250 AudioStandard::AudioCapturerOptions capturerOptions = {
251 {
252 AudioStandard::AudioSamplingRate::SAMPLE_RATE_48000,
253 AudioStandard::AudioEncodingType::ENCODING_PCM,
254 AudioStandard::AudioSampleFormat::SAMPLE_S16LE,
255 AudioStandard::AudioChannel::STEREO,
256 },
257 {
258 AudioStandard::SourceType::SOURCE_TYPE_MIC,
259 AudioStandard::STREAM_FLAG_FAST,
260 }
261 };
262 audioCapturer_ = AudioStandard::AudioCapturer::Create(capturerOptions);
263 if (audioCapturer_ == nullptr) {
264 AUDIO_ERR_LOG("Audio capturer create failed.");
265 return -1;
266 }
267 std::string path = "/data/mic.pcm";
268 OpenMicFile(path);
269 int32_t ret = audioCapturer_->SetCapturerReadCallback(shared_from_this());
270 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "Client test save data callback fail, ret %{public}d.", ret);
271 AUDIO_INFO_LOG("Audio capturer create success.");
272 return 0;
273 }
274
StartCapture()275 int32_t PlaybackTest::StartCapture()
276 {
277 if (audioCapturer_ == nullptr) {
278 AUDIO_ERR_LOG("audioCapturer init failed.");
279 return -1;
280 }
281 if (!audioCapturer_->Start()) {
282 AUDIO_ERR_LOG("Audio capture start failed.");
283 return -1;
284 }
285 return 0;
286 }
287
StopCapture()288 int32_t PlaybackTest::StopCapture()
289 {
290 if (audioCapturer_ == nullptr) {
291 AUDIO_ERR_LOG("audioCapturer init failed.");
292 return -1;
293 }
294 if (!audioCapturer_->Stop()) {
295 AUDIO_ERR_LOG("Audio capture stop failed.");
296 return -1;
297 }
298 return 0;
299 }
300
SetSysPara(const std::string & key,int32_t & value)301 bool SetSysPara(const std::string &key, int32_t &value)
302 {
303 auto res = SetParameter(key.c_str(), std::to_string(value).c_str());
304 if (res < 0) {
305 AUDIO_WARNING_LOG("SetSysPara fail, key:%{public}s res:%{public}d", key.c_str(), res);
306 return false;
307 }
308 AUDIO_INFO_LOG("SetSysPara success.");
309 return true;
310 }
311
GetUserInput()312 int32_t GetUserInput()
313 {
314 int32_t res = -1; // result
315 size_t count = 3; // try three time
316 cout << ">>";
317 cin >> res;
318 while (cin.fail() && count-- > 0) {
319 cin.clear();
320 cin.ignore();
321 cout << "invalid input, not a number! Please retry with a number." << endl;
322 cout << ">>";
323 cin >> res;
324 }
325 return res;
326 }
327
PrintUsage()328 void PrintUsage()
329 {
330 cout << "[Fast Audio Stream Test App]" << endl << endl;
331 cout << "Supported Functionalities:" << endl;
332 cout << "================================Usage=======================================" << endl << endl;
333 cout << " 0: Init local spk." << endl;
334 cout << " 1: Init remote spk." << endl;
335 cout << " 2: Start play." << endl;
336 cout << " 3: Stop play." << endl;
337 cout << " 4: Release spk." << endl;
338 cout << " 5: Init local mic." << endl;
339 cout << " 6: Init remote mic." << endl;
340 cout << " 7: Start record." << endl;
341 cout << " 8: Stop record." << endl;
342 cout << " 9: Release mic." << endl;
343 cout << " 10: exit demo." << endl;
344 cout << " Please input your choice: " << endl;
345 }
346
347 int32_t InitPlayback(std:share_ptr<PlaybackTest> playTest, bool isRemote) {
348 if (playTest == nullptr) {
349 cout << "Play test is nullptr, init spk error." << endl;
350 return -1;
351 }
352 int32_t ret = playTest->InitRenderer();
353 if (ret != 0) {
354 cout << "Init renderer error!" << endl;
355 return -1;
356 }
357 return 0;
358 }
359
360 int32_t StartPlay(std:share_ptr<PlaybackTest> playTest) {
361 if (playTest == nullptr) {
362 cout << "Play test is nullptr, start play error." << endl;
363 return -1;
364 }
365 int32_t ret = playTest->StartPlay();
366 if (ret != 0) {
367 cout << "Start play error!" << endl;
368 return -1;
369 }
370 return 0;
371 }
372
373 int32_t StopPlay(std:share_ptr<PlaybackTest> playTest) {
374 if (playTest == nullptr) {
375 cout << "Play test is nullptr, stop play error." << endl;
376 return -1;
377 }
378 int32_t ret = playTest->StopPlay();
379 if (ret != 0) {
380 cout << "Stop play error!" << endl;
381 return -1;
382 }
383 return 0;
384 }
385
386 int32_t InitMic(std:share_ptr<PlaybackTest> playTest, bool isRemote) {
387 if (playTest == nullptr) {
388 cout << "Play test is nullptr, init mic error." << endl;
389 return -1;
390 }
391 int32_t ret = playTest->InitCapturer();
392 if (ret != 0) {
393 cout << "Init capturer error!" << endl;
394 return -1;
395 }
396 return 0;
397 }
398
399 int32_t StartCpature(std:share_ptr<PlaybackTest> playTest) {
400 if (playTest == nullptr) {
401 cout << "Play test is nullptr, start capture error." << endl;
402 return -1;
403 }
404 int32_t ret = playTest->StartCapture();
405 if (ret != 0) {
406 cout << "Start capture error!" << endl;
407 return -1;
408 }
409 return 0;
410 }
411
412 int32_t StopCapture(std:share_ptr<PlaybackTest> playTest) {
413 if (playTest == nullptr) {
414 cout << "Play test is nullptr, stop capture error." << endl;
415 return -1;
416 }
417 int32_t ret = playTest->StopCapture();
418 if (ret != 0) {
419 cout << "Stop capture error!" << endl;
420 return -1;
421 }
422 return 0;
423 }
424
Loop(std::shared_ptr<PlaybackTest> playTest)425 void Loop(std::shared_ptr<PlaybackTest> playTest)
426 {
427 bool isProcTestRun = true;
428 while (isProcTestRun) {
429 PrintUsage();
430 AudioOptCode optCode = -1;
431 int32_t res = GetUserInput();
432 if (g_optStrMap.count(res)) {
433 optCode = static_cast<AudioOptCode>(res);
434 }
435 switch (optCode) {
436 case INIT_LOCAL_SPK:
437 InitPlayback(playTest, false);
438 break;
439 case INIT_REMOTE_SPK:
440 InitPlayback(playTest, true);
441 break;
442 case START_SPK:
443 StartPlay(playTest);
444 break;
445 case STOP_SPK:
446 StopPlay(playTest);
447 break;
448 case RELEASE_SPK:
449 break;
450 case INIT_LOCAL_MIC:
451 InitMic(playTest, false);
452 break;
453 case INIT_REMOTE_MIC:
454 InitMic(playTest, true);
455 break;
456 case START_MIC:
457 StartCapture(playTest);
458 break;
459 case STOP_MIC:
460 StopCapture(playTest);
461 break;
462 case RELEASE_MIC:
463 break;
464 case EXIT_DEMO:
465 isProcTestRun = false;
466 break;
467 default:
468 cout << "invalid input: " << res << endl;
469 break;
470 }
471 }
472 }
473 }
474 }
475
476 using namespace OHOS::AudioStandard;
477 using namespace std;
main(int argc,char * argv[])478 int main(int argc, char* argv[])
479 {
480 cout << "oh fast audio stream test." << endl;
481 std::shared_ptr<PlaybackTest> playTest = std::make_shared<PlaybackTest>();
482 int32_t val = 1;
483 std::string key = "persist.multimedia.audio.mmap.enable";
484 SetSysPara(key, val);
485
486 Loop(playTest);
487 playTest->CloseSpkFile();
488 playTest->CloseMicFile();
489 return 0;
490 }