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