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