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 "InterruptMultiRendererTest"
17 #endif
18
19 #include <chrono>
20 #include <thread>
21 #include <climits>
22 #include <cstdlib>
23 #include <unistd.h>
24 #include "audio_renderer_log.h"
25 #include "interrupt_multi_renderer_test.h"
26 #include "pcm2wav.h"
27
28 using namespace std;
29
30 namespace OHOS {
31 namespace AudioStandard {
32 namespace {
33 constexpr int32_t FIVE_SEC = 5;
34 constexpr int32_t MIN_NO_OF_ARGS = 3;
35 constexpr int32_t ARG_INDEX_1 = 1;
36 constexpr int32_t ARG_INDEX_2 = 2;
37 constexpr int32_t ARG_INDEX_3 = 3;
38 constexpr int32_t ARG_INDEX_4 = 4;
39 constexpr int32_t NUM_BASE = 10;
40
41 constexpr int32_t SAMPLE_FORMAT_U8 = 8;
42 constexpr int32_t SAMPLE_FORMAT_S16LE = 16;
43 constexpr int32_t SAMPLE_FORMAT_S24LE = 24;
44 constexpr int32_t SAMPLE_FORMAT_S32LE = 32;
45 }
46
OnStateChange(const RendererState state,const StateChangeCmdType cmdType)47 void AudioRendererCallbackTestImpl::OnStateChange(const RendererState state,
48 const StateChangeCmdType __attribute__((unused)) cmdType)
49 {
50 AUDIO_DEBUG_LOG("AudioRendererCallbackTestImpl:: OnStateChange");
51
52 switch (state) {
53 case RENDERER_PREPARED:
54 AUDIO_DEBUG_LOG("AudioRendererCallbackTestImpl: OnStateChange RENDERER_PREPARED");
55 break;
56 case RENDERER_RUNNING:
57 AUDIO_DEBUG_LOG("AudioRendererCallbackTestImpl: OnStateChange RENDERER_RUNNING");
58 break;
59 case RENDERER_STOPPED:
60 AUDIO_DEBUG_LOG("AudioRendererCallbackTestImpl: OnStateChange RENDERER_STOPPED");
61 break;
62 case RENDERER_PAUSED:
63 AUDIO_DEBUG_LOG("AudioRendererCallbackTestImpl: OnStateChange RENDERER_PAUSED");
64 break;
65 case RENDERER_RELEASED:
66 AUDIO_DEBUG_LOG("AudioRendererCallbackTestImpl: OnStateChange RENDERER_RELEASED");
67 break;
68 default:
69 AUDIO_ERR_LOG("AudioRendererCallbackTestImpl: OnStateChange NOT A VALID state");
70 break;
71 }
72 }
73
OnInterrupt(const InterruptEvent & interruptEvent)74 void AudioRendererCallbackTestImpl::OnInterrupt(const InterruptEvent &interruptEvent)
75 {
76 AUDIO_DEBUG_LOG("InterruptMultiRendererTest: OnInterrupt");
77 AUDIO_DEBUG_LOG("InterruptMultiRendererTest: interrupt hintType: %{public}d", interruptEvent.hintType);
78
79 if (interruptEvent.forceType == INTERRUPT_FORCE) {
80 switch (interruptEvent.hintType) {
81 case INTERRUPT_HINT_PAUSE:
82 AUDIO_DEBUG_LOG("InterruptMultiRendererTest: ForcePaused Pause Writing");
83 isRendererPaused_ = true;
84 break;
85 case INTERRUPT_HINT_STOP:
86 AUDIO_DEBUG_LOG("InterruptMultiRendererTest: ForceStopped Stop Writing");
87 isRendererStopped_ = true;
88 break;
89 case INTERRUPT_HINT_DUCK:
90 AUDIO_INFO_LOG("InterruptMultiRendererTest: force INTERRUPT_HINT_DUCK received");
91 break;
92 case INTERRUPT_HINT_UNDUCK:
93 AUDIO_INFO_LOG("InterruptMultiRendererTest: force INTERRUPT_HINT_UNDUCK received");
94 break;
95 default:
96 AUDIO_ERR_LOG("InterruptMultiRendererTest: OnInterrupt NOT A VALID force HINT");
97 break;
98 }
99 } else if (interruptEvent.forceType == INTERRUPT_SHARE) {
100 switch (interruptEvent.hintType) {
101 case INTERRUPT_HINT_PAUSE:
102 AUDIO_DEBUG_LOG("InterruptMultiRendererTest: SharePause Hint received, Do pause if required");
103 break;
104 case INTERRUPT_HINT_RESUME:
105 AUDIO_DEBUG_LOG("InterruptMultiRendererTest: Do ShareResume");
106 isRendererResumed_ = true;
107 break;
108 default:
109 AUDIO_ERR_LOG("InterruptMultiRendererTest: OnInterrupt default share hint case");
110 break;
111 }
112 }
113 }
114
WriteBuffer(AudioRenderer * audioRenderer,FILE * wavFile,const shared_ptr<AudioRendererCallbackTestImpl> & cb) const115 void InterruptMultiRendererTest::WriteBuffer(AudioRenderer* audioRenderer, FILE* wavFile,
116 const shared_ptr<AudioRendererCallbackTestImpl> &cb) const
117 {
118 size_t bufferLen = 4096;
119 audioRenderer->GetBufferSize(bufferLen);
120
121 int32_t n = 2;
122 auto buffer = make_unique<uint8_t[]>(n * bufferLen);
123
124 size_t bytesToWrite = 0;
125 size_t bytesWritten = 0;
126 size_t minBytes = 4;
127 while (true) {
128 if (cb->isRendererResumed_) {
129 if (audioRenderer->Start()) {
130 cb->isRendererPaused_ = false;
131 }
132 }
133
134 while (!feof(wavFile) &&
135 !cb->isRendererPaused_ && !cb->isRendererStopped_ && !cb->isStopInProgress_) {
136 bytesToWrite = fread(buffer.get(), 1, bufferLen, wavFile);
137 bytesWritten = 0;
138
139 while ((bytesWritten < bytesToWrite) && ((bytesToWrite - bytesWritten) > minBytes)) {
140 int32_t retBytes = audioRenderer->Write(buffer.get() + bytesWritten,
141 bytesToWrite - bytesWritten);
142 if (retBytes < 0) {
143 AUDIO_ERR_LOG("InterruptMultiRendererTest: Error occurred in writing buffer: %{public}d", retBytes);
144 if (audioRenderer->GetStatus() == RENDERER_PAUSED) {
145 cb->isRendererPaused_ = true;
146 int32_t seekPos = bytesWritten - bytesToWrite;
147 if (fseek(wavFile, seekPos, SEEK_CUR)) {
148 AUDIO_INFO_LOG("InterruptMultiRendererTest: fseek failed");
149 }
150 AUDIO_INFO_LOG("InterruptMultiRendererTest: fseek success");
151 } else if (audioRenderer->GetStatus() == RENDERER_STOPPED) {
152 AUDIO_INFO_LOG("InterruptMultiRendererTest: Renderer Stopped");
153 cb->isRendererStopped_ = true;
154 }
155 break;
156 }
157 bytesWritten += retBytes;
158 }
159 }
160
161 if (feof(wavFile) || cb->isRendererStopped_) {
162 if (feof(wavFile)) {
163 AUDIO_INFO_LOG("InterruptMultiRendererTest: EOF reached. Complete rendering ");
164 }
165 if (audioRenderer->GetStatus() == RENDERER_RUNNING) {
166 audioRenderer->Stop();
167 }
168 audioRenderer->Release();
169 break;
170 }
171 }
172 }
173
StartRender(const unique_ptr<AudioRenderer> & audioRenderer) const174 bool InterruptMultiRendererTest::StartRender(const unique_ptr<AudioRenderer> &audioRenderer) const
175 {
176 AUDIO_INFO_LOG("InterruptMultiRendererTest: Starting renderer");
177 if (!audioRenderer->Start()) {
178 AUDIO_ERR_LOG("InterruptMultiRendererTest: Start rejected or failed");
179 if (!audioRenderer->Release()) {
180 AUDIO_ERR_LOG("InterruptMultiRendererTest: Release failed");
181 }
182 return false;
183 }
184 AUDIO_INFO_LOG("InterruptMultiRendererTest: Playback started");
185 return true;
186 }
187
GetSampleFormat(int32_t wavSampleFormat) const188 AudioSampleFormat InterruptMultiRendererTest::GetSampleFormat(int32_t wavSampleFormat) const
189 {
190 switch (wavSampleFormat) {
191 case SAMPLE_FORMAT_U8:
192 return AudioSampleFormat::SAMPLE_U8;
193 case SAMPLE_FORMAT_S16LE:
194 return AudioSampleFormat::SAMPLE_S16LE;
195 case SAMPLE_FORMAT_S24LE:
196 return AudioSampleFormat::SAMPLE_S24LE;
197 case SAMPLE_FORMAT_S32LE:
198 return AudioSampleFormat::SAMPLE_S32LE;
199 default:
200 return AudioSampleFormat::INVALID_WIDTH;
201 }
202 }
203
InitRender(const unique_ptr<AudioRenderer> & audioRenderer,FILE * & wavFile) const204 bool InterruptMultiRendererTest::InitRender(const unique_ptr<AudioRenderer> &audioRenderer, FILE* &wavFile) const
205 {
206 wav_hdr wavHeader;
207 size_t headerSize = sizeof(wav_hdr);
208 size_t bytesRead = fread(&wavHeader, 1, headerSize, wavFile);
209 if (bytesRead != headerSize) {
210 AUDIO_ERR_LOG("InterruptMultiRendererTest: File header reading error");
211 return false;
212 }
213
214 AudioRendererParams rendererParams;
215 rendererParams.sampleFormat = GetSampleFormat(wavHeader.bitsPerSample);
216 rendererParams.sampleRate = static_cast<AudioSamplingRate>(wavHeader.SamplesPerSec);
217 rendererParams.channelCount = static_cast<AudioChannel>(wavHeader.NumOfChan);
218 rendererParams.encodingType = static_cast<AudioEncodingType>(ENCODING_PCM);
219
220 if (audioRenderer->SetParams(rendererParams)) {
221 AUDIO_ERR_LOG("InterruptMultiRendererTest: Set audio renderer parameters failed");
222 if (!audioRenderer->Release()) {
223 AUDIO_ERR_LOG("InterruptMultiRendererTest: Release failed");
224 }
225 return false;
226 }
227 AUDIO_INFO_LOG("InterruptMultiRendererTest: Playback renderer created");
228
229 return true;
230 }
231
ValidateFile(char * filePath,char path[]) const232 int32_t InterruptMultiRendererTest::ValidateFile(char *filePath, char path[]) const
233 {
234 if ((strlen(filePath) > PATH_MAX) || (realpath(filePath, path) == nullptr)) {
235 AUDIO_ERR_LOG("InterruptMultiRendererTest: Invalid input filepath");
236 return -1;
237 }
238
239 return 0;
240 }
241
TestPlayback(int argc,char * argv[]) const242 int32_t InterruptMultiRendererTest::TestPlayback(int argc, char *argv[]) const
243 {
244 char *file1Path = argv[ARG_INDEX_1];
245 char path1[PATH_MAX + 1] = {0x00};
246 char *file2Path = argv[ARG_INDEX_2];
247 char path2[PATH_MAX + 1] = {0x00};
248 FILE *wavFile1 = nullptr;
249 FILE *wavFile2 = nullptr;
250
251 if (!ValidateFile(file1Path, path1)) {
252 wavFile1 = fopen(path1, "rb");
253 if (wavFile1 == nullptr) {
254 return -1;
255 }
256 }
257
258 if (!ValidateFile(file2Path, path2)) {
259 wavFile2 = fopen(path2, "rb");
260 if (wavFile2 == nullptr) {
261 fclose(wavFile1);
262 return -1;
263 }
264 }
265
266 AudioStreamType streamType1 = STREAM_MUSIC;
267 AudioStreamType streamType2 = STREAM_VOICE_CALL;
268 if (argc > MIN_NO_OF_ARGS) {
269 streamType1 = static_cast<AudioStreamType>(strtol(argv[ARG_INDEX_3], NULL, NUM_BASE));
270 }
271 if (argc > MIN_NO_OF_ARGS + 1) {
272 streamType2 = static_cast<AudioStreamType>(strtol(argv[ARG_INDEX_4], NULL, NUM_BASE));
273 }
274
275 unique_ptr<AudioRenderer> audioRenderer1 = AudioRenderer::Create(streamType1);
276 unique_ptr<AudioRenderer> audioRenderer2 = AudioRenderer::Create(streamType2);
277
278 shared_ptr<AudioRendererCallback> cb1 = make_shared<AudioRendererCallbackTestImpl>();
279 if (InitRender(audioRenderer1, wavFile1)) {
280 audioRenderer1->SetRendererCallback(cb1);
281 }
282
283 shared_ptr<AudioRendererCallback> cb2 = make_shared<AudioRendererCallbackTestImpl>();
284 if (InitRender(audioRenderer2, wavFile2)) {
285 audioRenderer2->SetRendererCallback(cb2);
286 }
287
288 std::shared_ptr<AudioRendererCallbackTestImpl> cb1Impl =
289 std::static_pointer_cast<AudioRendererCallbackTestImpl>(cb1);
290 unique_ptr<thread> writeThread1 = nullptr;
291 if (audioRenderer1->GetStatus() == RENDERER_PREPARED && StartRender(audioRenderer1)) {
292 writeThread1 = make_unique<thread>(&InterruptMultiRendererTest::WriteBuffer, this,
293 audioRenderer1.get(), wavFile1, cb1Impl);
294 this_thread::sleep_for(chrono::seconds(FIVE_SEC));
295 }
296
297 std::shared_ptr<AudioRendererCallbackTestImpl> cb2Impl =
298 std::static_pointer_cast<AudioRendererCallbackTestImpl>(cb2);
299 unique_ptr<thread> writeThread2 = nullptr;
300 if (audioRenderer2->GetStatus() == RENDERER_PREPARED && StartRender(audioRenderer2)) {
301 writeThread2 = make_unique<thread>(&InterruptMultiRendererTest::WriteBuffer, this,
302 audioRenderer2.get(), wavFile2, cb2Impl);
303 }
304
305 if (writeThread1 && writeThread1->joinable()) {
306 writeThread1->join();
307 }
308 if (writeThread2 && writeThread2->joinable()) {
309 writeThread2->join();
310 }
311 fclose(wavFile1);
312 fclose(wavFile2);
313
314 return 0;
315 }
316 } // namespace AudioStandard
317 } // namespace OHOS
318
319 using namespace OHOS;
320 using namespace OHOS::AudioStandard;
321
main(int argc,char * argv[])322 int main(int argc, char *argv[])
323 {
324 AUDIO_INFO_LOG("InterruptMultiRendererTest: Render test in");
325
326 if ((argv == nullptr) || (argc < MIN_NO_OF_ARGS)) {
327 AUDIO_ERR_LOG("InterruptMultiRendererTest: argv / argc incorrect");
328 return 0;
329 }
330
331 AUDIO_INFO_LOG("InterruptMultiRendererTest: argc=%d", argc);
332 AUDIO_INFO_LOG("InterruptMultiRendererTest: argv[1]=%{public}s", argv[ARG_INDEX_1]);
333 AUDIO_INFO_LOG("InterruptMultiRendererTest: argv[2]=%{public}s", argv[ARG_INDEX_2]);
334
335 auto interruptMultiRendererTest = make_unique<InterruptMultiRendererTest>();
336 AUDIO_INFO_LOG("InterruptMultiRendererTest: TestPlayback start ");
337 int32_t ret = interruptMultiRendererTest->TestPlayback(argc, argv);
338 AUDIO_INFO_LOG("InterruptMultiRendererTest: TestPlayback end");
339
340 return ret;
341 }
342