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