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