• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,uint16_t audioFormat) const283     AudioSampleFormat GetSampleFormat(int32_t wavSampleFormat, uint16_t audioFormat) 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                 if (audioFormat == 3) { // 3 - IEEE float
294                     return AudioSampleFormat::SAMPLE_F32LE;
295                 } else {
296                     return AudioSampleFormat::SAMPLE_S32LE;
297                 }
298             default:
299                 return AudioSampleFormat::INVALID_WIDTH;
300         }
301     }
302 
TestPlayback(int argc,char * argv[]) const303     bool TestPlayback(int argc, char *argv[]) const
304     {
305         AUDIO_INFO_LOG("AudioRendererTest: TestPlayback start ");
306 
307         int numBase = 10;
308         wav_hdr wavHeader;
309         size_t headerSize = sizeof(wav_hdr);
310         char *inputPath = argv[1];
311         char path[PATH_MAX + 1] = {0x00};
312         if ((strlen(inputPath) > PATH_MAX) || (realpath(inputPath, path) == nullptr)) {
313             AUDIO_ERR_LOG("Invalid path");
314             return false;
315         }
316         AUDIO_INFO_LOG("AudioRendererTest: path = %{public}s", path);
317         FILE* wavFile = fopen(path, "rb");
318         if (wavFile == nullptr) {
319             AUDIO_INFO_LOG("AudioRendererTest: Unable to open wave file");
320             return false;
321         }
322         size_t bytesRead = fread(&wavHeader, 1, headerSize, wavFile);
323         AUDIO_INFO_LOG("AudioRendererTest: Header Read in bytes %{public}zu", bytesRead);
324 
325         ContentType contentType = ContentType::CONTENT_TYPE_MUSIC;
326         StreamUsage streamUsage = StreamUsage::STREAM_USAGE_MEDIA;
327 
328         float speed = 1.0;
329         if (argc == ARGS_COUNT_THREE) {
330             speed = static_cast<float>(atof(argv[ARGS_COUNT_TWO]));
331         } else if (argc > ARGS_COUNT_THREE) {
332             contentType = static_cast<ContentType>(strtol(argv[ARGS_INDEX_TWO], NULL, numBase));
333             streamUsage = static_cast<StreamUsage>(strtol(argv[ARGS_INDEX_THREE], NULL, numBase));
334         }
335         int32_t bufferMsec = 0;
336         if (argc > ARGS_COUNT_FOUR) {
337             bufferMsec = strtol(argv[ARGS_COUNT_FOUR], nullptr, numBase);
338         }
339 
340         AudioRendererOptions rendererOptions = {};
341         rendererOptions.streamInfo.encoding = AudioEncodingType::ENCODING_PCM;
342         rendererOptions.streamInfo.samplingRate = static_cast<AudioSamplingRate>(wavHeader.SamplesPerSec);
343         rendererOptions.streamInfo.format = GetSampleFormat(wavHeader.bitsPerSample, wavHeader.AudioFormat);
344         rendererOptions.streamInfo.channels = static_cast<AudioChannel>(wavHeader.NumOfChan);
345         rendererOptions.rendererInfo.contentType = contentType;
346         rendererOptions.rendererInfo.streamUsage = streamUsage;
347         rendererOptions.rendererInfo.rendererFlags = 0;
348 
349         unique_ptr<AudioRenderer> audioRenderer = AudioRenderer::Create(rendererOptions);
350 
351         if (audioRenderer == nullptr) {
352             AUDIO_ERR_LOG("AudioRendererTest: Create failed");
353             fclose(wavFile);
354             return false;
355         }
356 
357         int32_t ret = 0;
358         shared_ptr<AudioRendererCallback> cb1 = make_shared<AudioRendererCallbackTestImpl>();
359         ret = audioRenderer->SetRendererCallback(cb1);
360         if (ret) {
361             AUDIO_ERR_LOG("AudioRendererTest: SetRendererCallback failed %{public}d", ret);
362             fclose(wavFile);
363             return false;
364         }
365 
366         GetRendererStreamInfo(audioRenderer);
367 
368         CheckSupportedParams();
369         AUDIO_ERR_LOG("AudioRendererTest: buffermsec = %{public}d", bufferMsec);
370         int32_t status = audioRenderer->SetBufferDuration(bufferMsec);
371         if (status) {
372             AUDIO_ERR_LOG("Failed to set buffer duration");
373         }
374 
375         if (!InitRender(audioRenderer)) {
376             AUDIO_ERR_LOG("AudioRendererTest: Init render failed");
377             fclose(wavFile);
378             return false;
379         }
380         audioRenderer->SetSpeed(speed);
381 
382         if (!StartRender(audioRenderer, wavFile)) {
383             AUDIO_ERR_LOG("AudioRendererTest: Start render failed");
384             fclose(wavFile);
385             return false;
386         }
387 
388         if (!audioRenderer->Stop()) {
389             AUDIO_ERR_LOG("AudioRendererTest: Stop failed");
390         }
391 
392         if (!audioRenderer->Release()) {
393             AUDIO_ERR_LOG("AudioRendererTest: Release failed");
394         }
395 
396         fclose(wavFile);
397         AUDIO_INFO_LOG("AudioRendererTest: TestPlayback end");
398 
399         return true;
400     }
401 };
402 
main(int argc,char * argv[])403 int main(int argc, char *argv[])
404 {
405     AUDIO_INFO_LOG("AudioRendererTest: Render test in");
406 
407     if (argv == nullptr) {
408         AUDIO_ERR_LOG("AudioRendererTest: argv is null");
409         return 0;
410     }
411 
412     if (argc < ARGS_COUNT_TWO) {
413         AUDIO_ERR_LOG("AudioRendererTest: incorrect argc. Enter either 2 or 3 or 4 args");
414         return 0;
415     }
416 
417     AUDIO_INFO_LOG("AudioRendererTest: argc=%{public}d", argc);
418     AUDIO_INFO_LOG("file path argv[1]=%{public}s", argv[1]);
419 
420     AudioRendererTest testObj;
421     bool ret = testObj.TestPlayback(argc, argv);
422 
423     return ret;
424 }
425