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