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_renderer_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 fclose(wavFile1_);
86 wavFile1_ = nullptr;
87 return -1;
88 }
89 wavFile2_ = fopen(path, "rb");
90 if (wavFile2_ == nullptr) {
91 fclose(wavFile1_);
92 wavFile1_ = nullptr;
93 AUDIO_INFO_LOG("AudioRendererTest: Unable to open wave file");
94 return -1;
95 }
96 fread(&wavHeader2_, 1, headerSize, wavFile2_);
97
98 OpenSlTestConcurrent();
99
100 while (!feof(wavFile1_) || !feof(wavFile2_)) {
101 sleep(1);
102 }
103
104 PlayerStop(playItf1, bufferQueueItf1);
105 PlayerStop(playItf2, bufferQueueItf2);
106 (*pcmPlayerObject1)->Destroy(pcmPlayerObject1);
107 (*pcmPlayerObject2)->Destroy(pcmPlayerObject2);
108 (*engineObject)->Destroy(engineObject);
109 (*outputMixObject)->Destroy(outputMixObject);
110 fclose(wavFile1_);
111 wavFile1_ = nullptr;
112 fclose(wavFile2_);
113 wavFile2_ = nullptr;
114 return 0;
115 } else {
116 if (argc < 2) {
117 return -1;
118 }
119 size_t headerSize = sizeof(wav_hdr);
120 char *inputPath = argv[1];
121 char path[PATH_MAX + 1] = {0x00};
122 if ((strlen(inputPath) > PATH_MAX) || (realpath(inputPath, path) == nullptr)) {
123 AUDIO_ERR_LOG("Invalid path");
124 return -1;
125 }
126 wavFile_ = fopen(path, "rb");
127 if (wavFile_ == nullptr) {
128 AUDIO_INFO_LOG("AudioRendererTest: Unable to open wave file");
129 return -1;
130 }
131 fread(&wavHeader_, 1, headerSize, wavFile_);
132
133 OpenSlTest();
134
135 while (!feof(wavFile_)) {
136 sleep(1);
137 }
138 PlayerStop(playItf, bufferQueueItf);
139 (*pcmPlayerObject)->Destroy(pcmPlayerObject);
140 fclose(wavFile_);
141 wavFile_ = nullptr;
142
143 if (argc < 3) {
144 return 0;
145 }
146 char *inputPath2 = argv[2];
147 char path2[PATH_MAX + 1] = {0x00};
148 if ((strlen(inputPath2) > PATH_MAX) || (realpath(inputPath2, path2) == nullptr)) {
149 AUDIO_ERR_LOG("Invalid path");
150 return -1;
151 }
152 wavFile_ = fopen(path2, "rb");
153 if (wavFile_ == nullptr) {
154 AUDIO_INFO_LOG("AudioRendererTest: Unable to open wave file");
155 return -1;
156 }
157 fread(&wavHeader_, 1, headerSize, wavFile_);
158
159 OpenSlTest();
160
161 while (!feof(wavFile_)) {
162 sleep(1);
163 }
164 PlayerStop(playItf, bufferQueueItf);
165 (*pcmPlayerObject)->Destroy(pcmPlayerObject);
166 fclose(wavFile_);
167 wavFile_ = nullptr;
168 return 0;
169 }
170 }
171
OpenSlTest()172 static void OpenSlTest()
173 {
174 AUDIO_INFO_LOG("OpenSlTest");
175 engineObject = nullptr;
176 SLEngineItf engineEngine = nullptr;
177 slCreateEngine(&engineObject, 0, nullptr, 0, nullptr, nullptr);
178 (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
179 (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
180
181 outputMixObject = nullptr;
182 (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, nullptr, nullptr);
183 (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
184
185 SLDataLocator_OutputMix slOutputMix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
186 SLDataSink slSink = {&slOutputMix, nullptr};
187 SLDataLocator_BufferQueue slBufferQueue = {
188 SL_DATALOCATOR_BUFFERQUEUE,
189 0
190 };
191 SLDataFormat_PCM pcmFormat = {
192 SL_DATAFORMAT_PCM,
193 wavHeader_.NumOfChan,
194 wavHeader_.SamplesPerSec * 1000,
195 wavHeader_.bitsPerSample,
196 0,
197 0,
198 0
199 };
200 SLDataSource slSource = {&slBufferQueue, &pcmFormat};
201 (*engineEngine)->CreateAudioPlayer(engineEngine, &pcmPlayerObject, &slSource, &slSink, number, nullptr, nullptr);
202 (*pcmPlayerObject)->Realize(pcmPlayerObject, SL_BOOLEAN_FALSE);
203
204 (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_PLAY, &playItf);
205 SLVolumeItf volumeItf;
206 (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_VOLUME, &volumeItf);
207 SLmillibel pLevel = 0;
208 (*volumeItf)->GetVolumeLevel(volumeItf, &pLevel);
209 (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_OH_BUFFERQUEUE, &bufferQueueItf);
210 (*bufferQueueItf)->RegisterCallback(bufferQueueItf, BufferQueueCallback, wavFile_);
211
212 PlayerStart(playItf, bufferQueueItf, wavFile_);
213 }
214
OpenSlTestConcurrent()215 static void OpenSlTestConcurrent()
216 {
217 AUDIO_INFO_LOG("OpenSlTestConcurrent");
218 engineObject = nullptr;
219 SLEngineItf engineEngine = nullptr;
220
221 slCreateEngine(&engineObject, 0, nullptr, 0, nullptr, nullptr);
222 (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
223 (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
224
225 outputMixObject = nullptr;
226 (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, nullptr, nullptr);
227 (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
228
229 SLDataLocator_OutputMix slOutputMix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
230 SLDataSink slSink = {&slOutputMix, nullptr};
231 SLDataLocator_BufferQueue slBufferQueue = {
232 SL_DATALOCATOR_BUFFERQUEUE,
233 0
234 };
235 SLDataFormat_PCM pcmFormat1 = {
236 SL_DATAFORMAT_PCM,
237 wavHeader1_.NumOfChan,
238 wavHeader1_.SamplesPerSec * 1000,
239 wavHeader1_.bitsPerSample,
240 0,
241 0,
242 0
243 };
244 SLDataFormat_PCM pcmFormat2 = {
245 SL_DATAFORMAT_PCM,
246 wavHeader2_.NumOfChan,
247 wavHeader2_.SamplesPerSec * 1000,
248 wavHeader2_.bitsPerSample,
249 0,
250 0,
251 0
252 };
253 SLDataSource slSource1 = {&slBufferQueue, &pcmFormat1};
254 SLDataSource slSource2 = {&slBufferQueue, &pcmFormat2};
255
256 (*engineEngine)->CreateAudioPlayer(engineEngine, &pcmPlayerObject1, &slSource1, &slSink, number, nullptr, nullptr);
257 (*pcmPlayerObject1)->Realize(pcmPlayerObject1, SL_BOOLEAN_FALSE);
258
259 (*engineEngine)->CreateAudioPlayer(engineEngine, &pcmPlayerObject2, &slSource2, &slSink, number, nullptr, nullptr);
260 (*pcmPlayerObject2)->Realize(pcmPlayerObject2, SL_BOOLEAN_FALSE);
261
262 (*pcmPlayerObject1)->GetInterface(pcmPlayerObject1, SL_IID_PLAY, &playItf1);
263 (*pcmPlayerObject2)->GetInterface(pcmPlayerObject2, SL_IID_PLAY, &playItf2);
264 (*pcmPlayerObject1)->GetInterface(pcmPlayerObject1, SL_IID_VOLUME, &volumeItf1);
265
266 SLmillibel level1 = 0;
267 (*volumeItf1)->GetMaxVolumeLevel(volumeItf1, &level1);
268 SLmillibel temp = 2;
269 level1 = (SLmillibel) (level1 / temp);
270 (*volumeItf1)->SetVolumeLevel(volumeItf1, level1);
271 (*pcmPlayerObject2)->GetInterface(pcmPlayerObject2, SL_IID_VOLUME, &volumeItf2);
272 SLmillibel level2 = 0;
273 (*volumeItf2)->GetMaxVolumeLevel(volumeItf2, &level2);
274 temp = 15; // MaxVolumeLevel
275 level2 = (SLmillibel) (level2 / temp);
276 (*volumeItf2)->SetVolumeLevel(volumeItf2, level2);
277
278 (*pcmPlayerObject1)->GetInterface(pcmPlayerObject1, SL_IID_OH_BUFFERQUEUE, &bufferQueueItf1);
279 (*pcmPlayerObject2)->GetInterface(pcmPlayerObject2, SL_IID_OH_BUFFERQUEUE, &bufferQueueItf2);
280 (*bufferQueueItf1)->RegisterCallback(bufferQueueItf1, BufferQueueCallback, wavFile1_);
281 (*bufferQueueItf2)->RegisterCallback(bufferQueueItf2, BufferQueueCallback, wavFile2_);
282 PlayerStart(playItf1, bufferQueueItf1, wavFile1_);
283 PlayerStart(playItf2, bufferQueueItf2, wavFile2_);
284 }
285
BufferQueueCallback(SLOHBufferQueueItf bufferQueueItf,void * pContext,SLuint32 size)286 static void BufferQueueCallback(SLOHBufferQueueItf bufferQueueItf, void *pContext, SLuint32 size)
287 {
288 FILE *wavFile = (FILE *)pContext;
289 if (!feof(wavFile)) {
290 SLuint8 *buffer = nullptr;
291 SLuint32 bufferSize = 0;
292 (*bufferQueueItf)->GetBuffer(bufferQueueItf, &buffer, &bufferSize);
293 if (buffer != nullptr) {
294 fread(buffer, 1, size, wavFile);
295 (*bufferQueueItf)->Enqueue(bufferQueueItf, buffer, size);
296 }
297 }
298 return;
299 }
300
PlayerStart(SLPlayItf playItf,SLOHBufferQueueItf bufferQueueItf,FILE * wavFile)301 static void PlayerStart(SLPlayItf playItf, SLOHBufferQueueItf bufferQueueItf, FILE *wavFile)
302 {
303 AUDIO_INFO_LOG("PlayerStart");
304 (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING);
305 return;
306 }
307
PlayerStop(SLPlayItf playItf,SLOHBufferQueueItf bufferQueueItf)308 static void PlayerStop(SLPlayItf playItf, SLOHBufferQueueItf bufferQueueItf)
309 {
310 AUDIO_INFO_LOG("PlayerStop");
311 (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
312 return;
313 }
314