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