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