1 /*
2  * Copyright (c) 2022-2023 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 "AudioOpenslesPlayerTest"
17 #endif
18 
19 #include <OpenSLES.h>
20 #include <OpenSLES_OpenHarmony.h>
21 
22 #include <cstdio>
23 #include <climits>
24 #include <cstdlib>
25 #include <cstring>
26 #include <unistd.h>
27 
28 #include "audio_log.h"
29 #include "pcm2wav.h"
30 
31 using namespace std;
32 
33 static void BufferQueueCallback(SLOHBufferQueueItf bufferQueueItf, void *pContext, SLuint32 size);
34 
35 static void PlayerStart(SLPlayItf playItf, SLOHBufferQueueItf bufferQueueItf, FILE *wavFile);
36 
37 static void PlayerStop(SLPlayItf playItf, SLOHBufferQueueItf bufferQueueItf);
38 
39 static void OpenSlTest();
40 
41 static void OpenSlTestConcurrent();
42 
43 const SLuint32 number = 3;
44 FILE *wavFile_ = nullptr;
45 FILE *wavFile1_ = nullptr;
46 FILE *wavFile2_ = nullptr;
47 wav_hdr wavHeader_;
48 wav_hdr wavHeader1_;
49 wav_hdr wavHeader2_;
50 SLObjectItf engineObject = nullptr;
51 SLObjectItf outputMixObject = nullptr;
52 SLPlayItf playItf;
53 SLPlayItf playItf1;
54 SLPlayItf playItf2;
55 SLVolumeItf volumeItf1;
56 SLVolumeItf volumeItf2;
57 SLOHBufferQueueItf bufferQueueItf;
58 SLOHBufferQueueItf bufferQueueItf1;
59 SLOHBufferQueueItf bufferQueueItf2;
60 SLObjectItf pcmPlayerObject = nullptr;
61 SLObjectItf pcmPlayerObject1 = nullptr;
62 SLObjectItf pcmPlayerObject2 = nullptr;
63 
main(int argc,char * argv[])64 int main(int argc, char *argv[])
65 {
66     if (argc == 4) {
67         size_t headerSize = sizeof(wav_hdr);
68         char *inputPath = argv[1];
69         char path[PATH_MAX + 1] = {0x00};
70         if ((strlen(inputPath) > PATH_MAX) || (realpath(inputPath, path) == nullptr)) {
71             AUDIO_ERR_LOG("Invalid path");
72             return -1;
73         }
74         wavFile1_ = fopen(path, "rb");
75         if (wavFile1_ == nullptr) {
76             AUDIO_INFO_LOG("AudioRendererTest: Unable to open wave file");
77             return -1;
78         }
79         fread(&wavHeader1_, 1, headerSize, wavFile1_);
80 
81         headerSize = sizeof(wav_hdr);
82         inputPath = argv[2];
83         if ((strlen(inputPath) > PATH_MAX) || (realpath(inputPath, path) == nullptr)) {
84             AUDIO_ERR_LOG("Invalid path");
85             return -1;
86         }
87         wavFile2_ = fopen(path, "rb");
88         if (wavFile2_ == nullptr) {
89             AUDIO_INFO_LOG("AudioRendererTest: Unable to open wave file");
90             return -1;
91         }
92         fread(&wavHeader2_, 1, headerSize, wavFile2_);
93 
94         OpenSlTestConcurrent();
95 
96         while (!feof(wavFile1_) || !feof(wavFile2_)) {
97             sleep(1);
98         }
99 
100         PlayerStop(playItf1, bufferQueueItf1);
101         PlayerStop(playItf2, bufferQueueItf2);
102         (*pcmPlayerObject1)->Destroy(pcmPlayerObject1);
103         (*pcmPlayerObject2)->Destroy(pcmPlayerObject2);
104         (*engineObject)->Destroy(engineObject);
105         (*outputMixObject)->Destroy(outputMixObject);
106         return 0;
107     } else {
108         if (argc < 2) {
109             return -1;
110         }
111         size_t headerSize = sizeof(wav_hdr);
112         char *inputPath = argv[1];
113         char path[PATH_MAX + 1] = {0x00};
114         if ((strlen(inputPath) > PATH_MAX) || (realpath(inputPath, path) == nullptr)) {
115             AUDIO_ERR_LOG("Invalid path");
116             return -1;
117         }
118         wavFile_ = fopen(path, "rb");
119         if (wavFile_ == nullptr) {
120             AUDIO_INFO_LOG("AudioRendererTest: Unable to open wave file");
121             return -1;
122         }
123         fread(&wavHeader_, 1, headerSize, wavFile_);
124 
125         OpenSlTest();
126 
127         while (!feof(wavFile_)) {
128             sleep(1);
129         }
130         PlayerStop(playItf, bufferQueueItf);
131         (*pcmPlayerObject)->Destroy(pcmPlayerObject);
132 
133         if (argc < 3) {
134             return 0;
135         }
136         char *inputPath2 = argv[2];
137         char path2[PATH_MAX + 1] = {0x00};
138         if ((strlen(inputPath2) > PATH_MAX) || (realpath(inputPath2, path2) == nullptr)) {
139             AUDIO_ERR_LOG("Invalid path");
140             return -1;
141         }
142         wavFile_ = fopen(path2, "rb");
143         if (wavFile_ == nullptr) {
144             AUDIO_INFO_LOG("AudioRendererTest: Unable to open wave file");
145             return -1;
146         }
147         fread(&wavHeader_, 1, headerSize, wavFile_);
148 
149         OpenSlTest();
150 
151         while (!feof(wavFile_)) {
152             sleep(1);
153         }
154         PlayerStop(playItf, bufferQueueItf);
155         (*pcmPlayerObject)->Destroy(pcmPlayerObject);
156         return 0;
157     }
158 }
159 
OpenSlTest()160 static void OpenSlTest()
161 {
162     AUDIO_INFO_LOG("OpenSlTest");
163     engineObject = nullptr;
164     SLEngineItf engineEngine = nullptr;
165     slCreateEngine(&engineObject, 0, nullptr, 0, nullptr, nullptr);
166     (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
167     (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
168 
169     outputMixObject = nullptr;
170     (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, nullptr, nullptr);
171     (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
172 
173     SLDataLocator_OutputMix slOutputMix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
174     SLDataSink slSink = {&slOutputMix, nullptr};
175     SLDataLocator_BufferQueue slBufferQueue = {
176         SL_DATALOCATOR_BUFFERQUEUE,
177         0
178     };
179     SLDataFormat_PCM pcmFormat = {
180         SL_DATAFORMAT_PCM,
181         wavHeader_.NumOfChan,
182         wavHeader_.SamplesPerSec * 1000,
183         wavHeader_.bitsPerSample,
184         0,
185         0,
186         0
187     };
188     SLDataSource slSource = {&slBufferQueue, &pcmFormat};
189     (*engineEngine)->CreateAudioPlayer(engineEngine, &pcmPlayerObject, &slSource, &slSink, number, nullptr, nullptr);
190     (*pcmPlayerObject)->Realize(pcmPlayerObject, SL_BOOLEAN_FALSE);
191 
192     (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_PLAY, &playItf);
193     SLVolumeItf volumeItf;
194     (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_VOLUME, &volumeItf);
195     SLmillibel pLevel = 0;
196     (*volumeItf)->GetVolumeLevel(volumeItf, &pLevel);
197     (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_OH_BUFFERQUEUE, &bufferQueueItf);
198     (*bufferQueueItf)->RegisterCallback(bufferQueueItf, BufferQueueCallback, wavFile_);
199 
200     PlayerStart(playItf, bufferQueueItf, wavFile_);
201 }
202 
OpenSlTestConcurrent()203 static void OpenSlTestConcurrent()
204 {
205     AUDIO_INFO_LOG("OpenSlTestConcurrent");
206     engineObject = nullptr;
207     SLEngineItf engineEngine = nullptr;
208 
209     slCreateEngine(&engineObject, 0, nullptr, 0, nullptr, nullptr);
210     (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
211     (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
212 
213     outputMixObject = nullptr;
214     (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, nullptr, nullptr);
215     (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
216 
217     SLDataLocator_OutputMix slOutputMix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
218     SLDataSink slSink = {&slOutputMix, nullptr};
219     SLDataLocator_BufferQueue slBufferQueue = {
220         SL_DATALOCATOR_BUFFERQUEUE,
221         0
222     };
223     SLDataFormat_PCM pcmFormat1 = {
224         SL_DATAFORMAT_PCM,
225         wavHeader1_.NumOfChan,
226         wavHeader1_.SamplesPerSec * 1000,
227         wavHeader1_.bitsPerSample,
228         0,
229         0,
230         0
231     };
232     SLDataFormat_PCM pcmFormat2 = {
233         SL_DATAFORMAT_PCM,
234         wavHeader2_.NumOfChan,
235         wavHeader2_.SamplesPerSec * 1000,
236         wavHeader2_.bitsPerSample,
237         0,
238         0,
239         0
240     };
241     SLDataSource slSource1 = {&slBufferQueue, &pcmFormat1};
242     SLDataSource slSource2 = {&slBufferQueue, &pcmFormat2};
243 
244     (*engineEngine)->CreateAudioPlayer(engineEngine, &pcmPlayerObject1, &slSource1, &slSink, number, nullptr, nullptr);
245     (*pcmPlayerObject1)->Realize(pcmPlayerObject1, SL_BOOLEAN_FALSE);
246 
247     (*engineEngine)->CreateAudioPlayer(engineEngine, &pcmPlayerObject2, &slSource2, &slSink, number, nullptr, nullptr);
248     (*pcmPlayerObject2)->Realize(pcmPlayerObject2, SL_BOOLEAN_FALSE);
249 
250     (*pcmPlayerObject1)->GetInterface(pcmPlayerObject1, SL_IID_PLAY, &playItf1);
251     (*pcmPlayerObject2)->GetInterface(pcmPlayerObject2, SL_IID_PLAY, &playItf2);
252     (*pcmPlayerObject1)->GetInterface(pcmPlayerObject1, SL_IID_VOLUME, &volumeItf1);
253 
254     SLmillibel level1 = 0;
255     (*volumeItf1)->GetMaxVolumeLevel(volumeItf1, &level1);
256     SLmillibel temp = 2;
257     level1 = (SLmillibel) (level1 / temp);
258     (*volumeItf1)->SetVolumeLevel(volumeItf1, level1);
259     (*pcmPlayerObject2)->GetInterface(pcmPlayerObject2, SL_IID_VOLUME, &volumeItf2);
260     SLmillibel level2 = 0;
261     (*volumeItf2)->GetMaxVolumeLevel(volumeItf2, &level2);
262     temp = 15; // MaxVolumeLevel
263     level2 = (SLmillibel) (level2 / temp);
264     (*volumeItf2)->SetVolumeLevel(volumeItf2, level2);
265 
266     (*pcmPlayerObject1)->GetInterface(pcmPlayerObject1, SL_IID_OH_BUFFERQUEUE, &bufferQueueItf1);
267     (*pcmPlayerObject2)->GetInterface(pcmPlayerObject2, SL_IID_OH_BUFFERQUEUE, &bufferQueueItf2);
268     (*bufferQueueItf1)->RegisterCallback(bufferQueueItf1, BufferQueueCallback, wavFile1_);
269     (*bufferQueueItf2)->RegisterCallback(bufferQueueItf2, BufferQueueCallback, wavFile2_);
270     PlayerStart(playItf1, bufferQueueItf1, wavFile1_);
271     PlayerStart(playItf2, bufferQueueItf2, wavFile2_);
272 }
273 
BufferQueueCallback(SLOHBufferQueueItf bufferQueueItf,void * pContext,SLuint32 size)274 static void BufferQueueCallback(SLOHBufferQueueItf bufferQueueItf, void *pContext, SLuint32 size)
275 {
276     FILE *wavFile = (FILE *)pContext;
277     if (!feof(wavFile)) {
278         SLuint8 *buffer = nullptr;
279         SLuint32 bufferSize = 0;
280         (*bufferQueueItf)->GetBuffer(bufferQueueItf, &buffer, &bufferSize);
281         if (buffer != nullptr) {
282             fread(buffer, 1, size, wavFile);
283             (*bufferQueueItf)->Enqueue(bufferQueueItf, buffer, size);
284         }
285     }
286     return;
287 }
288 
PlayerStart(SLPlayItf playItf,SLOHBufferQueueItf bufferQueueItf,FILE * wavFile)289 static void PlayerStart(SLPlayItf playItf, SLOHBufferQueueItf bufferQueueItf, FILE *wavFile)
290 {
291     AUDIO_INFO_LOG("PlayerStart");
292     (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING);
293     return;
294 }
295 
PlayerStop(SLPlayItf playItf,SLOHBufferQueueItf bufferQueueItf)296 static void PlayerStop(SLPlayItf playItf, SLOHBufferQueueItf bufferQueueItf)
297 {
298     AUDIO_INFO_LOG("PlayerStop");
299     (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
300     return;
301 }
302