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