• 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 <chrono>
17 #include <thread>
18 #include <vector>
19 
20 #include "audio_renderer.h"
21 #include "media_log.h"
22 #include "pcm2wav.h"
23 
24 using namespace std;
25 using namespace OHOS;
26 using namespace OHOS::AudioStandard;
27 
28 class AudioRenderModeCallbackTest : public AudioRendererWriteCallback,
29     public enable_shared_from_this<AudioRenderModeCallbackTest> {
30 public:
OnWriteData(size_t length)31     void OnWriteData(size_t length) override
32     {
33         MEDIA_INFO_LOG("RenderCallbackTest: OnWriteData is called");
34         reqBufLen_ = length;
35         isEnqueue_ = true;
36     }
37 
InitRender()38     bool InitRender()
39     {
40         wav_hdr wavHeader;
41         size_t headerSize = sizeof(wav_hdr);
42         size_t bytesRead = fread(&wavHeader, 1, headerSize, wavFile_);
43         if (bytesRead != headerSize) {
44             MEDIA_ERR_LOG("RenderCallbackTest: File header reading error");
45             return false;
46         }
47 
48         AudioRendererOptions rendererOptions = {};
49         rendererOptions.streamInfo.encoding = AudioEncodingType::ENCODING_PCM;
50         rendererOptions.streamInfo.samplingRate = static_cast<AudioSamplingRate>(wavHeader.SamplesPerSec);
51         rendererOptions.streamInfo.format = static_cast<AudioSampleFormat>(wavHeader.bitsPerSample);
52         rendererOptions.streamInfo.channels = static_cast<AudioChannel>(wavHeader.NumOfChan);
53         rendererOptions.rendererInfo.contentType = ContentType::CONTENT_TYPE_MUSIC;
54         rendererOptions.rendererInfo.streamUsage = StreamUsage::STREAM_USAGE_MEDIA;
55         rendererOptions.rendererInfo.rendererFlags = 0;
56 
57         audioRenderer_ = AudioRenderer::Create(rendererOptions);
58         if (audioRenderer_== nullptr) {
59             MEDIA_ERR_LOG("RenderCallbackTest: Renderer create failed");
60             return false;
61         }
62 
63         MEDIA_INFO_LOG("RenderCallbackTest: Playback renderer created");
64         if (audioRenderer_->SetRenderMode(RENDER_MODE_CALLBACK)) {
65             MEDIA_ERR_LOG("RenderCallbackTest: SetRenderMode failed");
66             return false;
67         }
68 
69         if (audioRenderer_->SetRendererWriteCallback(shared_from_this())) {
70             MEDIA_ERR_LOG("RenderCallbackTest: SetRendererWriteCallback failed");
71             return false;
72         }
73 
74         audioRenderer_->GetBufferSize(reqBufLen_);
75 
76         return true;
77     }
78 
TestPlayback(int argc,char * argv[])79     int32_t TestPlayback(int argc, char *argv[])
80     {
81         MEDIA_INFO_LOG("RenderCallbackTest: TestPlayback start");
82         if (!InitRender()) {
83             return -1;
84         }
85 
86         if (!audioRenderer_->Start()) {
87             MEDIA_ERR_LOG("RenderCallbackTest: Start failed");
88             audioRenderer_->Release();
89             return -1;
90         }
91 
92         enqueueThread_ = make_unique<thread>(&AudioRenderModeCallbackTest::EnqueueBuffer, this);
93         enqueueThread_ ->join();
94 
95         audioRenderer_->Clear();
96         audioRenderer_->Stop();
97         audioRenderer_->Release();
98         MEDIA_INFO_LOG("RenderCallbackTest: TestPlayback end");
99 
100         return 0;
101     }
102 
~AudioRenderModeCallbackTest()103     ~AudioRenderModeCallbackTest()
104     {
105         MEDIA_INFO_LOG("RenderCallbackTest: Inside ~AudioRenderModeCallbackTest");
106         if (fclose(wavFile_)) {
107             MEDIA_INFO_LOG("RenderCallbackTest: wavFile_ failed");
108         } else {
109             MEDIA_INFO_LOG("RenderCallbackTest: fclose(wavFile_) success");
110         }
111         wavFile_ = nullptr;
112 
113         if (enqueueThread_ && enqueueThread_->joinable()) {
114             enqueueThread_->join();
115             enqueueThread_ = nullptr;
116         }
117     }
118 
119     FILE *wavFile_ = nullptr;
120 private:
EnqueueBuffer()121     void EnqueueBuffer()
122     {
123         MEDIA_INFO_LOG("RenderCallbackTest: EnqueueBuffer thread");
124         while (!feof(wavFile_)) {
125             if (isEnqueue_) {
126                 // Requested length received in callback
127                 size_t reqLen = reqBufLen_;
128                 bufDesc_.buffer = nullptr;
129                 audioRenderer_->GetBufferDesc(bufDesc_);
130                 if (bufDesc_.buffer == nullptr) {
131                     continue;
132                 }
133                 // requested len in callback will never be greater than allocated buf length
134                 // This is just a fail-safe
135                 if (reqLen > bufDesc_.bufLength) {
136                     bufDesc_.dataLength = bufDesc_.bufLength;
137                 } else {
138                     bufDesc_.dataLength = reqLen;
139                 }
140 
141                 fread(bufDesc_.buffer, 1, bufDesc_.dataLength, wavFile_);
142                 audioRenderer_->Enqueue(bufDesc_);
143                 isEnqueue_ = false;
144             }
145         }
146     }
147 
148     unique_ptr<AudioRenderer> audioRenderer_ = nullptr;
149     unique_ptr<thread> enqueueThread_ = nullptr;
150     bool isEnqueue_ = true;
151     BufferDesc bufDesc_ {};
152     size_t reqBufLen_;
153 };
154 
main(int argc,char * argv[])155 int main(int argc, char *argv[])
156 {
157     char *inputPath = argv[1];
158     char path[PATH_MAX + 1] = {0x00};
159     if ((strlen(inputPath) > PATH_MAX) || (realpath(inputPath, path) == nullptr)) {
160         MEDIA_ERR_LOG("RenderCallbackTest: Invalid input filepath");
161         return -1;
162     }
163     MEDIA_INFO_LOG("RenderCallbackTest: path = %{public}s", path);
164     auto testObj = std::make_shared<AudioRenderModeCallbackTest>();
165 
166     testObj->wavFile_ = fopen(path, "rb");
167     if (testObj->wavFile_ == nullptr) {
168         MEDIA_ERR_LOG("AudioRendererTest: Unable to open wave file");
169         return -1;
170     }
171 
172     return testObj->TestPlayback(argc, argv);
173 }
174