• 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 
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