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 "AudioRendererTest"
17 #endif
18
19 #include <chrono>
20 #include <cstdio>
21 #include <cstdlib>
22 #include <cinttypes>
23 #include <unistd.h>
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 ARGS_INDEX_THREE = 3;
34 constexpr int32_t ARGS_INDEX_TWO = 2;
35 constexpr int32_t ARGS_COUNT_TWO = 2;
36 constexpr int32_t ARGS_COUNT_THREE = 3;
37 constexpr int32_t ARGS_COUNT_FOUR = 4;
38 constexpr int32_t SUCCESS = 0;
39 #ifndef LATENCY_ACCURACY_TEST
40 constexpr int32_t STOP_BUFFER_POSITION = 700000;
41 constexpr int32_t PAUSE_BUFFER_POSITION = 1400000;
42 constexpr int32_t PAUSE_RENDER_TIME_SECONDS = 1;
43 constexpr int32_t STOP_RENDER_TIME_SECONDS = 1;
44 constexpr float TRACK_VOLUME = 0.2f;
45 #endif // LATENCY_ACCURACY_TEST
46
47 constexpr int32_t SAMPLE_FORMAT_U8 = 8;
48 constexpr int32_t SAMPLE_FORMAT_S16LE = 16;
49 constexpr int32_t SAMPLE_FORMAT_S24LE = 24;
50 constexpr int32_t SAMPLE_FORMAT_S32LE = 32;
51 }
52
53 class AudioRendererCallbackTestImpl : public AudioRendererCallback {
54 public:
OnInterrupt(const InterruptEvent & interruptEvent)55 void OnInterrupt(const InterruptEvent &interruptEvent) override {}
OnStateChange(const RendererState state,const StateChangeCmdType cmdType)56 void OnStateChange(const RendererState state, const StateChangeCmdType __attribute__((unused)) cmdType) override
57 {
58 AUDIO_DEBUG_LOG("AudioRendererCallbackTestImpl:: OnStateChange");
59
60 switch (state) {
61 case RENDERER_PREPARED:
62 AUDIO_DEBUG_LOG("AudioRendererCallbackTestImpl: OnStateChange RENDERER_PREPARED");
63 break;
64 case RENDERER_RUNNING:
65 AUDIO_DEBUG_LOG("AudioRendererCallbackTestImpl: OnStateChange RENDERER_RUNNING");
66 break;
67 case RENDERER_STOPPED:
68 AUDIO_DEBUG_LOG("AudioRendererCallbackTestImpl: OnStateChange RENDERER_STOPPED");
69 break;
70 case RENDERER_PAUSED:
71 AUDIO_DEBUG_LOG("AudioRendererCallbackTestImpl: OnStateChange RENDERER_PAUSED");
72 break;
73 case RENDERER_RELEASED:
74 AUDIO_DEBUG_LOG("AudioRendererCallbackTestImpl: OnStateChange RENDERER_RELEASED");
75 break;
76 default:
77 AUDIO_ERR_LOG("AudioRendererCallbackTestImpl: OnStateChange NOT A VALID state");
78 break;
79 }
80 }
81 };
82
83 class AudioRendererTest {
84 public:
CheckSupportedParams() const85 void CheckSupportedParams() const
86 {
87 vector<AudioSampleFormat> supportedFormatList = AudioRenderer::GetSupportedFormats();
88 AUDIO_INFO_LOG("AudioRendererTest: Supported formats:");
89 for (auto i = supportedFormatList.begin(); i != supportedFormatList.end(); ++i) {
90 AUDIO_INFO_LOG("AudioRendererTest: Format %{public}d", *i);
91 }
92
93 vector<AudioChannel> supportedChannelList = AudioRenderer::GetSupportedChannels();
94 AUDIO_INFO_LOG("AudioRendererTest: Supported channels:");
95 for (auto i = supportedChannelList.begin(); i != supportedChannelList.end(); ++i) {
96 AUDIO_INFO_LOG("AudioRendererTest: channel %{public}d", *i);
97 }
98
99 vector<AudioEncodingType> supportedEncodingTypes
100 = AudioRenderer::GetSupportedEncodingTypes();
101 AUDIO_INFO_LOG("AudioRendererTest: Supported encoding types:");
102 for (auto i = supportedEncodingTypes.begin(); i != supportedEncodingTypes.end(); ++i) {
103 AUDIO_INFO_LOG("AudioRendererTest: encoding type %{public}d", *i);
104 }
105
106 vector<AudioSamplingRate> supportedSamplingRates = AudioRenderer::GetSupportedSamplingRates();
107 AUDIO_INFO_LOG("AudioRendererTest: Supported sampling rates:");
108 for (auto i = supportedSamplingRates.begin(); i != supportedSamplingRates.end(); ++i) {
109 AUDIO_INFO_LOG("AudioRendererTest: sampling rate %{public}d", *i);
110 }
111 }
112
GetRendererStreamInfo(const unique_ptr<AudioRenderer> & audioRenderer) const113 void GetRendererStreamInfo(const unique_ptr<AudioRenderer> &audioRenderer) const
114 {
115 AUDIO_INFO_LOG("AudioRendererTest: GetRendererInfo:");
116 AudioRendererInfo rendererInfo;
117 if (audioRenderer->GetRendererInfo(rendererInfo) == SUCCESS) {
118 AUDIO_INFO_LOG("AudioRendererTest: Get ContentType: %{public}d", rendererInfo.contentType);
119 AUDIO_INFO_LOG("AudioRendererTest: Get StreamUsage: %{public}d", rendererInfo.streamUsage);
120 } else {
121 AUDIO_ERR_LOG("AudioRendererTest: GetStreamInfo failed");
122 }
123
124 AUDIO_INFO_LOG("AudioRendererTest: GetStreamInfo:");
125 AudioStreamInfo streamInfo;
126 if (audioRenderer->GetStreamInfo(streamInfo) == SUCCESS) {
127 AUDIO_INFO_LOG("AudioRendererTest: Get AudioSamplingRate: %{public}d", streamInfo.samplingRate);
128 AUDIO_INFO_LOG("AudioRendererTest: Get AudioEncodingType: %{public}d", streamInfo.encoding);
129 AUDIO_INFO_LOG("AudioRendererTest: Get AudioSampleFormat: %{public}d", streamInfo.format);
130 AUDIO_INFO_LOG("AudioRendererTest: Get AudioChannel: %{public}d", streamInfo.channels);
131 } else {
132 AUDIO_ERR_LOG("AudioRendererTest: GetStreamInfo failed");
133 }
134 }
135
InitRender(const unique_ptr<AudioRenderer> & audioRenderer) const136 bool InitRender(const unique_ptr<AudioRenderer> &audioRenderer) const
137 {
138 AUDIO_INFO_LOG("AudioRendererTest: Starting renderer");
139 if (!audioRenderer->Start()) {
140 AUDIO_ERR_LOG("AudioRendererTest: Start failed");
141 if (!audioRenderer->Release()) {
142 AUDIO_ERR_LOG("AudioRendererTest: Release failed");
143 }
144 return false;
145 }
146 AUDIO_INFO_LOG("AudioRendererTest: Playback started");
147 #ifndef LATENCY_ACCURACY_TEST
148 if (audioRenderer->SetVolume(TRACK_VOLUME) == SUCCESS) {
149 AUDIO_INFO_LOG("AudioRendererTest: volume set to: %{public}f", audioRenderer->GetVolume());
150 }
151 #endif // LATENCY_ACCURACY_TEST
152
153 return true;
154 }
155
156 #ifndef LATENCY_ACCURACY_TEST
TestPauseStop(const unique_ptr<AudioRenderer> & audioRenderer,bool & pauseTested,bool & stopTested,FILE & wavFile) const157 bool TestPauseStop(const unique_ptr<AudioRenderer> &audioRenderer, bool &pauseTested, bool &stopTested,
158 FILE &wavFile) const
159 {
160 int64_t currFilePos = ftell(&wavFile);
161 if (!stopTested && (currFilePos > STOP_BUFFER_POSITION) && audioRenderer->Stop()) {
162 stopTested = true;
163 sleep(STOP_RENDER_TIME_SECONDS);
164 AUDIO_INFO_LOG("Audio render resume");
165 if (!audioRenderer->Start()) {
166 AUDIO_ERR_LOG("resume stream failed");
167 return false;
168 }
169 } else if (!pauseTested && (currFilePos > PAUSE_BUFFER_POSITION)
170 && audioRenderer->Pause()) {
171 pauseTested = true;
172 sleep(PAUSE_RENDER_TIME_SECONDS);
173 AUDIO_INFO_LOG("Audio render resume");
174 if (audioRenderer->SetVolume(1.0) == SUCCESS) {
175 AUDIO_INFO_LOG("AudioRendererTest: after resume volume set to: %{public}f",
176 audioRenderer->GetVolume());
177 }
178 if (!audioRenderer->Flush()) {
179 AUDIO_ERR_LOG("AudioRendererTest: flush failed");
180 return false;
181 }
182 if (!audioRenderer->Start()) {
183 AUDIO_ERR_LOG("resume stream failed");
184 return false;
185 }
186 }
187
188 return true;
189 }
190 #endif // LATENCY_ACCURACY_TEST
191
GetBufferLen(const unique_ptr<AudioRenderer> & audioRenderer,size_t & bufferLen) const192 bool GetBufferLen(const unique_ptr<AudioRenderer> &audioRenderer, size_t &bufferLen) const
193 {
194 if (audioRenderer->GetBufferSize(bufferLen)) {
195 return false;
196 }
197 AUDIO_DEBUG_LOG("minimum buffer length: %{public}zu", bufferLen);
198
199 uint32_t frameCount;
200 if (audioRenderer->GetFrameCount(frameCount)) {
201 return false;
202 }
203 AUDIO_INFO_LOG("AudioRendererTest: Frame count: %{public}d", frameCount);
204 return true;
205 }
206
StartRender(const unique_ptr<AudioRenderer> & audioRenderer,FILE * wavFile) const207 bool StartRender(const unique_ptr<AudioRenderer> &audioRenderer, FILE* wavFile) const
208 {
209 size_t bufferLen = 0;
210 if (!GetBufferLen(audioRenderer, bufferLen)) {
211 return false;
212 }
213
214 int32_t n = 2;
215 auto buffer = std::make_unique<uint8_t[]>(n * bufferLen);
216 if (buffer == nullptr) {
217 AUDIO_ERR_LOG("AudioRendererTest: Failed to allocate buffer");
218 return false;
219 }
220
221 size_t bytesToWrite = 0;
222 size_t bytesWritten = 0;
223 size_t minBytes = 4;
224 uint64_t latency;
225 #ifndef LATENCY_ACCURACY_TEST
226 bool stopTested = false;
227 bool pauseTested = false;
228 #endif // LATENCY_ACCURACY_TEST
229 #ifdef LATENCY_ACCURACY_TEST
230 uint32_t writeCount {0};
231 #endif // LATENCY_ACCURACY_TEST
232
233 while (!feof(wavFile)) {
234 bytesToWrite = fread(buffer.get(), 1, bufferLen, wavFile);
235 bytesWritten = 0;
236 AUDIO_INFO_LOG("AudioRendererTest: Bytes to write: %{public}zu", bytesToWrite);
237
238 #ifndef LATENCY_ACCURACY_TEST
239 if (!TestPauseStop(audioRenderer, pauseTested, stopTested, *wavFile)) {
240 break;
241 }
242 #endif // LATENCY_ACCURACY_TEST
243 #ifdef LATENCY_ACCURACY_TEST
244 AUDIO_DEBUG_LOG("start: %{public}d", ++writeCount);
245 #endif // LATENCY_ACCURACY_TEST
246 while ((bytesWritten < bytesToWrite) && ((bytesToWrite - bytesWritten) > minBytes)) {
247 bytesWritten += audioRenderer->Write(buffer.get() + bytesWritten,
248 bytesToWrite - bytesWritten);
249 AUDIO_INFO_LOG("AudioRendererTest: Bytes written: %{public}zu", bytesWritten);
250 if (bytesWritten < 0) {
251 break;
252 }
253 }
254 #ifdef LATENCY_ACCURACY_TEST
255 AUDIO_DEBUG_LOG("complete: %{public}d", writeCount);
256 #endif // LATENCY_ACCURACY_TEST
257
258 if (audioRenderer->GetLatency(latency)) {
259 AUDIO_ERR_LOG("AudioRendererTest: GetLatency failed");
260 break;
261 #ifdef LATENCY_ACCURACY_TEST
262 } else {
263 AUDIO_DEBUG_LOG("GetLatency: %{public}" PRIu64, latency);
264 #endif // LATENCY_ACCURACY_TEST
265 }
266 }
267
268 if (!audioRenderer->Drain()) {
269 AUDIO_ERR_LOG("AudioRendererTest: Drain failed");
270 }
271
272 if (audioRenderer->GetLatency(latency)) {
273 AUDIO_ERR_LOG("AudioRendererTest: GetLatency failed after Drain");
274 #ifdef LATENCY_ACCURACY_TEST
275 } else {
276 AUDIO_DEBUG_LOG("GetLatency after Drain: %{public}" PRIu64, latency);
277 #endif // LATENCY_ACCURACY_TEST
278 }
279
280 return true;
281 }
282
GetSampleFormat(int32_t wavSampleFormat) const283 AudioSampleFormat GetSampleFormat(int32_t wavSampleFormat) const
284 {
285 switch (wavSampleFormat) {
286 case SAMPLE_FORMAT_U8:
287 return AudioSampleFormat::SAMPLE_U8;
288 case SAMPLE_FORMAT_S16LE:
289 return AudioSampleFormat::SAMPLE_S16LE;
290 case SAMPLE_FORMAT_S24LE:
291 return AudioSampleFormat::SAMPLE_S24LE;
292 case SAMPLE_FORMAT_S32LE:
293 return AudioSampleFormat::SAMPLE_S32LE;
294 default:
295 return AudioSampleFormat::INVALID_WIDTH;
296 }
297 }
298
TestPlayback(int argc,char * argv[]) const299 bool TestPlayback(int argc, char *argv[]) const
300 {
301 AUDIO_INFO_LOG("AudioRendererTest: TestPlayback start ");
302
303 int numBase = 10;
304 wav_hdr wavHeader;
305 size_t headerSize = sizeof(wav_hdr);
306 char *inputPath = argv[1];
307 char path[PATH_MAX + 1] = {0x00};
308 if ((strlen(inputPath) > PATH_MAX) || (realpath(inputPath, path) == nullptr)) {
309 AUDIO_ERR_LOG("Invalid path");
310 return false;
311 }
312 AUDIO_INFO_LOG("AudioRendererTest: path = %{public}s", path);
313 FILE* wavFile = fopen(path, "rb");
314 if (wavFile == nullptr) {
315 AUDIO_INFO_LOG("AudioRendererTest: Unable to open wave file");
316 return false;
317 }
318 size_t bytesRead = fread(&wavHeader, 1, headerSize, wavFile);
319 AUDIO_INFO_LOG("AudioRendererTest: Header Read in bytes %{public}zu", bytesRead);
320
321 ContentType contentType = ContentType::CONTENT_TYPE_MUSIC;
322 StreamUsage streamUsage = StreamUsage::STREAM_USAGE_MEDIA;
323
324 float speed = 1.0;
325 if (argc == ARGS_COUNT_THREE) {
326 speed = static_cast<float>(atof(argv[ARGS_COUNT_TWO]));
327 } else if (argc > ARGS_COUNT_THREE) {
328 contentType = static_cast<ContentType>(strtol(argv[ARGS_INDEX_TWO], NULL, numBase));
329 streamUsage = static_cast<StreamUsage>(strtol(argv[ARGS_INDEX_THREE], NULL, numBase));
330 }
331 int32_t bufferMsec = 0;
332 if (argc > ARGS_COUNT_FOUR) {
333 bufferMsec = strtol(argv[ARGS_COUNT_FOUR], nullptr, numBase);
334 }
335
336 AudioRendererOptions rendererOptions = {};
337 rendererOptions.streamInfo.encoding = AudioEncodingType::ENCODING_PCM;
338 rendererOptions.streamInfo.samplingRate = static_cast<AudioSamplingRate>(wavHeader.SamplesPerSec);
339 rendererOptions.streamInfo.format = GetSampleFormat(wavHeader.bitsPerSample);
340 rendererOptions.streamInfo.channels = static_cast<AudioChannel>(wavHeader.NumOfChan);
341 rendererOptions.rendererInfo.contentType = contentType;
342 rendererOptions.rendererInfo.streamUsage = streamUsage;
343 rendererOptions.rendererInfo.rendererFlags = 0;
344
345 unique_ptr<AudioRenderer> audioRenderer = AudioRenderer::Create(rendererOptions);
346
347 if (audioRenderer == nullptr) {
348 AUDIO_ERR_LOG("AudioRendererTest: Create failed");
349 fclose(wavFile);
350 return false;
351 }
352
353 int32_t ret = 0;
354 shared_ptr<AudioRendererCallback> cb1 = make_shared<AudioRendererCallbackTestImpl>();
355 ret = audioRenderer->SetRendererCallback(cb1);
356 if (ret) {
357 AUDIO_ERR_LOG("AudioRendererTest: SetRendererCallback failed %{public}d", ret);
358 fclose(wavFile);
359 return false;
360 }
361
362 GetRendererStreamInfo(audioRenderer);
363
364 CheckSupportedParams();
365 AUDIO_ERR_LOG("AudioRendererTest: buffermsec = %{public}d", bufferMsec);
366 int32_t status = audioRenderer->SetBufferDuration(bufferMsec);
367 if (status) {
368 AUDIO_ERR_LOG("Failed to set buffer duration");
369 }
370
371 if (!InitRender(audioRenderer)) {
372 AUDIO_ERR_LOG("AudioRendererTest: Init render failed");
373 fclose(wavFile);
374 return false;
375 }
376 audioRenderer->SetSpeed(speed);
377
378 if (!StartRender(audioRenderer, wavFile)) {
379 AUDIO_ERR_LOG("AudioRendererTest: Start render failed");
380 fclose(wavFile);
381 return false;
382 }
383
384 if (!audioRenderer->Stop()) {
385 AUDIO_ERR_LOG("AudioRendererTest: Stop failed");
386 }
387
388 if (!audioRenderer->Release()) {
389 AUDIO_ERR_LOG("AudioRendererTest: Release failed");
390 }
391
392 fclose(wavFile);
393 AUDIO_INFO_LOG("AudioRendererTest: TestPlayback end");
394
395 return true;
396 }
397 };
398
main(int argc,char * argv[])399 int main(int argc, char *argv[])
400 {
401 AUDIO_INFO_LOG("AudioRendererTest: Render test in");
402
403 if (argv == nullptr) {
404 AUDIO_ERR_LOG("AudioRendererTest: argv is null");
405 return 0;
406 }
407
408 if (argc < ARGS_COUNT_TWO) {
409 AUDIO_ERR_LOG("AudioRendererTest: incorrect argc. Enter either 2 or 3 or 4 args");
410 return 0;
411 }
412
413 AUDIO_INFO_LOG("AudioRendererTest: argc=%{public}d", argc);
414 AUDIO_INFO_LOG("file path argv[1]=%{public}s", argv[1]);
415
416 AudioRendererTest testObj;
417 bool ret = testObj.TestPlayback(argc, argv);
418
419 return ret;
420 }
421