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