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