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