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