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