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 "AudioInterruptTest"
17 #endif
18 
19 #include <cstddef>
20 #include <climits>
21 #include <cstdlib>
22 #include <cstring>
23 #include <unistd.h>
24 #include "audio_interrupt_test.h"
25 #include "audio_renderer_log.h"
26 #include "pcm2wav.h"
27 
28 using namespace std;
29 
30 namespace OHOS {
31 namespace AudioStandard {
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 }
OnStateChange(const RendererState state,const StateChangeCmdType cmdType)38 void AudioInterruptTest::OnStateChange(const RendererState state,
39     const StateChangeCmdType __attribute__((unused)) cmdType)
40 {
41     AUDIO_DEBUG_LOG("AudioInterruptTest:: OnStateChange");
42 
43     switch (state) {
44         case RENDERER_PREPARED:
45             AUDIO_DEBUG_LOG("AudioInterruptTest: OnStateChange RENDERER_PREPARED");
46             break;
47         case RENDERER_RUNNING:
48             AUDIO_DEBUG_LOG("AudioInterruptTest: OnStateChange RENDERER_RUNNING");
49             break;
50         case RENDERER_STOPPED:
51             AUDIO_DEBUG_LOG("AudioInterruptTest: OnStateChange RENDERER_STOPPED");
52             break;
53         case RENDERER_PAUSED:
54             AUDIO_DEBUG_LOG("AudioInterruptTest: OnStateChange RENDERER_PAUSED");
55             break;
56         case RENDERER_RELEASED:
57             AUDIO_DEBUG_LOG("AudioInterruptTest: OnStateChange RENDERER_RELEASED");
58             break;
59         default:
60             AUDIO_ERR_LOG("AudioInterruptTest: OnStateChange NOT A VALID state");
61             break;
62     }
63 }
64 
OnInterrupt(const InterruptEvent & interruptEvent)65 void AudioInterruptTest::OnInterrupt(const InterruptEvent &interruptEvent)
66 {
67     AUDIO_DEBUG_LOG("AudioInterruptTest:  OnInterrupt");
68     AUDIO_DEBUG_LOG("AudioInterruptTest: interrupt hintType: %{public}d", interruptEvent.hintType);
69 
70     if (interruptEvent.forceType == INTERRUPT_FORCE) {
71         switch (interruptEvent.hintType) {
72             case INTERRUPT_HINT_PAUSE:
73                 AUDIO_DEBUG_LOG("AudioInterruptTest: ForcePaused Pause Writing");
74                 isRenderPaused_ = true;
75                 break;
76             case INTERRUPT_HINT_STOP:
77                 AUDIO_DEBUG_LOG("AudioInterruptTest: ForceStopped Stop Writing");
78                 isRenderStopped_ = true;
79                 break;
80             case INTERRUPT_HINT_DUCK:
81                 AUDIO_INFO_LOG("AudioInterruptTest: force INTERRUPT_HINT_DUCK received");
82                 break;
83             case INTERRUPT_HINT_UNDUCK:
84                 AUDIO_INFO_LOG("AudioInterruptTest: force INTERRUPT_HINT_UNDUCK received");
85                 break;
86             default:
87                 AUDIO_ERR_LOG("AudioInterruptTest: OnInterrupt NOT A VALID force HINT");
88                 break;
89         }
90     } else if  (interruptEvent.forceType == INTERRUPT_SHARE) {
91         switch (interruptEvent.hintType) {
92             case INTERRUPT_HINT_PAUSE:
93                 AUDIO_DEBUG_LOG("AudioInterruptTest: SharePause Hint received, Do pause if required");
94                 break;
95             case INTERRUPT_HINT_RESUME:
96                 AUDIO_DEBUG_LOG("AudioInterruptTest: Do ShareResume");
97                 if (audioRenderer_ == nullptr) {
98                     AUDIO_DEBUG_LOG("AudioInterruptTest: OnInterrupt audioRenderer_ nullptr return");
99                     return;
100                 }
101                 if (audioRenderer_->Start()) {
102                     AUDIO_DEBUG_LOG("AudioInterruptTest: Resume Success");
103                     isRenderPaused_ = false;
104                 } else {
105                     AUDIO_DEBUG_LOG("AudioInterruptTest: Resume Failed");
106                 }
107                 break;
108             default:
109                 AUDIO_ERR_LOG("AudioInterruptTest: OnInterrupt default share hint case");
110                 break;
111         }
112     }
113 }
114 
GetBufferLen(size_t & bufferLen) const115 bool AudioInterruptTest::GetBufferLen(size_t &bufferLen) const
116 {
117     if (audioRenderer_->GetBufferSize(bufferLen)) {
118         return false;
119     }
120     AUDIO_DEBUG_LOG("minimum buffer length: %{public}zu", bufferLen);
121 
122     return true;
123 }
124 
WriteBuffer()125 void AudioInterruptTest::WriteBuffer()
126 {
127     size_t bufferLen = 0;
128     if (!GetBufferLen(bufferLen)) {
129         isRenderingCompleted_ = true;
130         return;
131     }
132 
133     int32_t n = 2;
134     auto buffer = std::make_unique<uint8_t[]>(n * bufferLen);
135     if (buffer == nullptr) {
136         AUDIO_ERR_LOG("AudioInterruptTest: Failed to allocate buffer");
137         isRenderingCompleted_ = true;
138         return;
139     }
140 
141     size_t bytesToWrite = 0;
142     size_t bytesWritten = 0;
143     size_t minBytes = 4;
144     while (true) {
145         while (!feof(wavFile_) &&
146                !isRenderPaused_ && !isRenderStopped_ && !isStopInProgress_) {
147             bytesToWrite = fread(buffer.get(), 1, bufferLen, wavFile_);
148             bytesWritten = 0;
149             AUDIO_INFO_LOG("AudioInterruptTest: Bytes to write: %{public}zu", bytesToWrite);
150 
151             while ((bytesWritten < bytesToWrite) && ((bytesToWrite - bytesWritten) > minBytes)) {
152                 int32_t retBytes = audioRenderer_->Write(buffer.get() + bytesWritten,
153                                                          bytesToWrite - bytesWritten);
154                 AUDIO_INFO_LOG("AudioInterruptTest: Bytes written: %{public}zu", bytesWritten);
155                 if (retBytes < 0) {
156                     if (audioRenderer_->GetStatus() == RENDERER_PAUSED) {
157                         isRenderPaused_ = true;
158                         int32_t seekPos = bytesWritten - bytesToWrite;
159                         if (fseek(wavFile_, seekPos, SEEK_CUR)) {
160                             AUDIO_INFO_LOG("AudioInterruptTest: fseek failed");
161                         }
162                         AUDIO_INFO_LOG("AudioInterruptTest: fseek success");
163                     }
164                     break;
165                 }
166                 bytesWritten += retBytes;
167             }
168         }
169 
170         if (feof(wavFile_)) {
171             AUDIO_INFO_LOG("AudioInterruptTest: EOF set isRenderingCompleted_ true ");
172             isRenderingCompleted_ = true;
173             break;
174         }
175 
176         if (isRenderStopped_) {
177             AUDIO_INFO_LOG("AudioInterruptTest: Renderer stopping, complete writing ");
178             break;
179         }
180     }
181 }
182 
StartRender()183 bool AudioInterruptTest::StartRender()
184 {
185     AUDIO_INFO_LOG("AudioInterruptTest: Starting renderer");
186     if (!audioRenderer_->Start()) {
187         AUDIO_ERR_LOG("AudioInterruptTest: Start failed");
188         if (!audioRenderer_->Release()) {
189             AUDIO_ERR_LOG("AudioInterruptTest: Release failed");
190         }
191         isRenderingCompleted_ = true;
192         return false;
193     }
194     AUDIO_INFO_LOG("AudioInterruptTest: Playback started");
195     return true;
196 }
197 
GetSampleFormat(int32_t wavSampleFormat)198 AudioSampleFormat AudioInterruptTest::GetSampleFormat(int32_t wavSampleFormat)
199 {
200     switch (wavSampleFormat) {
201         case SAMPLE_FORMAT_U8:
202             return AudioSampleFormat::SAMPLE_U8;
203         case SAMPLE_FORMAT_S16LE:
204             return AudioSampleFormat::SAMPLE_S16LE;
205         case SAMPLE_FORMAT_S24LE:
206             return AudioSampleFormat::SAMPLE_S24LE;
207         case SAMPLE_FORMAT_S32LE:
208             return AudioSampleFormat::SAMPLE_S32LE;
209         default:
210             return AudioSampleFormat::INVALID_WIDTH;
211     }
212 }
213 
InitRender()214 bool AudioInterruptTest::InitRender()
215 {
216     wav_hdr wavHeader;
217     size_t headerSize = sizeof(wav_hdr);
218     size_t bytesRead = fread(&wavHeader, 1, headerSize, wavFile_);
219     if (bytesRead != headerSize) {
220         AUDIO_ERR_LOG("AudioInterruptTest: File header reading error");
221         return false;
222     }
223 
224     AudioRendererOptions rendererOptions = {};
225     rendererOptions.streamInfo.encoding = AudioEncodingType::ENCODING_PCM;
226     rendererOptions.streamInfo.samplingRate = static_cast<AudioSamplingRate>(wavHeader.SamplesPerSec);
227     rendererOptions.streamInfo.format = GetSampleFormat(wavHeader.bitsPerSample);
228     rendererOptions.streamInfo.channels = static_cast<AudioChannel>(wavHeader.NumOfChan);
229     rendererOptions.rendererInfo.contentType = contentType_;
230     rendererOptions.rendererInfo.streamUsage = streamUsage_;
231     rendererOptions.rendererInfo.rendererFlags = 0;
232 
233     audioRenderer_ = AudioRenderer::Create(rendererOptions);
234     if (audioRenderer_ == nullptr) {
235         AUDIO_INFO_LOG("AudioInterruptTest: Renderer create failed");
236         return false;
237     }
238     AUDIO_INFO_LOG("AudioInterruptTest: Playback renderer created");
239 
240     return true;
241 }
242 
TestPlayback()243 int32_t AudioInterruptTest::TestPlayback()
244 {
245     AUDIO_INFO_LOG("AudioInterruptTest: TestPlayback start ");
246     if (!InitRender()) {
247         fclose(wavFile_);
248         return -1;
249     }
250 
251     std::shared_ptr<AudioRendererCallback> audioRendererCB = GetPtr();
252     int32_t ret = audioRenderer_->SetRendererCallback(audioRendererCB);
253     AUDIO_DEBUG_LOG("AudioInterruptTest: SetRendererCallback result : %{public}d", ret);
254     if (ret) {
255         AUDIO_ERR_LOG("AudioInterruptTest: SetRendererCallback failed : %{public}d", ret);
256         fclose(wavFile_);
257         return -1;
258     }
259 
260     if (!StartRender()) {
261         fclose(wavFile_);
262         return -1;
263     }
264 
265     writeThread_ = std::make_unique<std::thread>(&AudioInterruptTest::WriteBuffer, this);
266     writeThread_->join();
267 
268     if (audioRenderer_->GetStatus() == RENDERER_RUNNING) {
269         AUDIO_DEBUG_LOG("AudioInterruptTest: StopRender");
270         if (audioRenderer_->Stop()) {
271             AUDIO_ERR_LOG("AudioInterruptTest: Stop Success");
272         } else {
273             AUDIO_DEBUG_LOG("AudioInterruptTest: Stop Failed");
274         }
275     }
276 
277     if (!audioRenderer_->Release()) {
278         AUDIO_ERR_LOG("AudioInterruptTest: Release failed");
279     }
280 
281     fclose(wavFile_);
282     wavFile_ = nullptr;
283 
284     AUDIO_INFO_LOG("AudioInterruptTest: TestPlayback end");
285 
286     return 0;
287 }
288 
SaveStreamInfo(ContentType contentType,StreamUsage streamUsage)289 void AudioInterruptTest::SaveStreamInfo(ContentType contentType, StreamUsage streamUsage)
290 {
291     contentType_ = contentType;
292     streamUsage_ = streamUsage;
293 }
294 } // namespace AudioStandard
295 } // namespace OHOS
296 
297 using namespace OHOS;
298 using namespace OHOS::AudioStandard;
299 
main(int argc,char * argv[])300 int main(int argc, char *argv[])
301 {
302     AUDIO_INFO_LOG("AudioInterruptTest: Render test in");
303     constexpr int32_t minNumOfArgs = 2;
304     constexpr int32_t argIndexTwo = 2;
305     constexpr int32_t argIndexThree = 3;
306 
307     if (argv == nullptr) {
308         AUDIO_ERR_LOG("AudioInterruptTest: argv is null");
309         return 0;
310     }
311 
312     if (argc < minNumOfArgs || argc == minNumOfArgs + 1) {
313         AUDIO_ERR_LOG("AudioInterruptTest: incorrect argc. Enter either 2 or 4 args");
314         return 0;
315     }
316 
317     AUDIO_INFO_LOG("AudioInterruptTest: argc=%d", argc);
318     AUDIO_INFO_LOG("AudioInterruptTest: argv[1]=%{public}s", argv[1]);
319 
320     int numBase = 10;
321     char *inputPath = argv[1];
322     char path[PATH_MAX + 1] = {0x00};
323     if ((strlen(inputPath) > PATH_MAX) || (realpath(inputPath, path) == nullptr)) {
324         AUDIO_ERR_LOG("AudioInterruptTest: Invalid input filepath");
325         return -1;
326     }
327     AUDIO_INFO_LOG("AudioInterruptTest: path = %{public}s", path);
328 
329     auto audioInterruptTest = std::make_shared<AudioInterruptTest>();
330 
331     audioInterruptTest->wavFile_ = fopen(path, "rb");
332     if (audioInterruptTest->wavFile_ == nullptr) {
333         AUDIO_INFO_LOG("AudioInterruptTest: Unable to open wave file");
334         return -1;
335     }
336 
337     if (argc > minNumOfArgs + 1) { // argc = 4
338         ContentType contentType = static_cast<ContentType>(strtol(argv[argIndexTwo], NULL, numBase));
339         StreamUsage streamUsage = static_cast<StreamUsage>(strtol(argv[argIndexThree], NULL, numBase));
340         audioInterruptTest->SaveStreamInfo(contentType, streamUsage);
341     }
342 
343     int32_t ret = audioInterruptTest->TestPlayback();
344 
345     return ret;
346 }
347