2 * Copyright (C) 2010 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 // Play an audio file using buffer queue
26 #include <SLES/OpenSLES.h>
33 unsigned numBuffers = 2;
34 int framesPerBuffer = 512;
37 unsigned which; // which buffer to use next
38 SLboolean eof; // whether we have hit EOF on input yet
41 // This callback is called each time a buffer finishes playing
43 static void callback(SLBufferQueueItf bufq, void *param)
46 short *buffer = &buffers[framesPerBuffer * sfinfo.channels * which];
48 count = sf_readf_short(sndfile, buffer, (sf_count_t) framesPerBuffer);
50 eof = SL_BOOLEAN_TRUE;
52 SLresult result = (*bufq)->Enqueue(bufq, buffer, count * sfinfo.channels *
54 assert(SL_RESULT_SUCCESS == result);
55 if (++which >= numBuffers)
61 int main(int argc, char **argv)
63 SLboolean enableReverb = SL_BOOLEAN_FALSE;
65 // process command-line options
67 for (i = 1; i < argc; ++i) {
71 if (!strncmp(arg, "-f", 2)) {
72 framesPerBuffer = atoi(&arg[2]);
73 } else if (!strncmp(arg, "-n", 2)) {
74 numBuffers = atoi(&arg[2]);
75 } else if (!strcmp(arg, "-r")) {
76 enableReverb = SL_BOOLEAN_TRUE;
78 fprintf(stderr, "option %s ignored\n", arg);
83 fprintf(stderr, "usage: [-r] %s filename\n", argv[0]);
87 const char *filename = argv[i];
88 //memset(&sfinfo, 0, sizeof(SF_INFO));
90 sndfile = sf_open(filename, SFM_READ, &sfinfo);
91 if (NULL == sndfile) {
96 // verify the file format
97 switch (sfinfo.channels) {
102 fprintf(stderr, "unsupported channel count %d\n", sfinfo.channels);
105 switch (sfinfo.samplerate) {
117 fprintf(stderr, "unsupported sample rate %d\n", sfinfo.samplerate);
120 switch (sfinfo.format & SF_FORMAT_TYPEMASK) {
124 fprintf(stderr, "unsupported format type 0x%x\n", sfinfo.format & SF_FORMAT_TYPEMASK);
127 switch (sfinfo.format & SF_FORMAT_SUBMASK) {
128 case SF_FORMAT_PCM_16:
129 case SF_FORMAT_PCM_U8:
132 case SF_FORMAT_IMA_ADPCM:
135 fprintf(stderr, "unsupported sub-format 0x%x\n", sfinfo.format & SF_FORMAT_SUBMASK);
139 buffers = (short *) malloc(framesPerBuffer * sfinfo.channels * sizeof(short) * numBuffers);
143 SLObjectItf engineObject;
144 result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
145 assert(SL_RESULT_SUCCESS == result);
146 SLEngineItf engineEngine;
147 result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
148 assert(SL_RESULT_SUCCESS == result);
149 result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
150 assert(SL_RESULT_SUCCESS == result);
153 SLObjectItf outputMixObject;
154 SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};
155 SLboolean req[1] = {SL_BOOLEAN_TRUE};
156 result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, enableReverb ? 1 : 0,
158 assert(SL_RESULT_SUCCESS == result);
159 result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
160 assert(SL_RESULT_SUCCESS == result);
162 // configure environmental reverb on output mix
163 SLEnvironmentalReverbItf mixEnvironmentalReverb = NULL;
165 result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB,
166 &mixEnvironmentalReverb);
167 assert(SL_RESULT_SUCCESS == result);
168 SLEnvironmentalReverbSettings settings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR;
169 result = (*mixEnvironmentalReverb)->SetEnvironmentalReverbProperties(mixEnvironmentalReverb,
171 assert(SL_RESULT_SUCCESS == result);
174 // configure audio source
175 SLDataLocator_BufferQueue loc_bufq;
176 loc_bufq.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
177 loc_bufq.numBuffers = numBuffers;
178 SLDataFormat_PCM format_pcm;
179 format_pcm.formatType = SL_DATAFORMAT_PCM;
180 format_pcm.numChannels = sfinfo.channels;
181 format_pcm.samplesPerSec = sfinfo.samplerate * 1000;
182 format_pcm.bitsPerSample = 16;
183 format_pcm.containerSize = format_pcm.bitsPerSample;
184 format_pcm.channelMask = 1 == format_pcm.numChannels ? SL_SPEAKER_FRONT_CENTER :
185 SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
186 format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
187 SLDataSource audioSrc;
188 audioSrc.pLocator = &loc_bufq;
189 audioSrc.pFormat = &format_pcm;
191 // configure audio sink
192 SLDataLocator_OutputMix loc_outmix;
193 loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
194 loc_outmix.outputMix = outputMixObject;
196 audioSnk.pLocator = &loc_outmix;
197 audioSnk.pFormat = NULL;
199 // create audio player
200 SLInterfaceID ids2[2] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND};
201 SLboolean req2[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
202 SLObjectItf playerObject;
203 result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audioSrc,
204 &audioSnk, enableReverb ? 2 : 1, ids2, req2);
205 assert(SL_RESULT_SUCCESS == result);
207 // realize the player
208 result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
209 assert(SL_RESULT_SUCCESS == result);
211 // get the effect send interface and enable effect send reverb for this player
213 SLEffectSendItf playerEffectSend;
214 result = (*playerObject)->GetInterface(playerObject, SL_IID_EFFECTSEND, &playerEffectSend);
215 assert(SL_RESULT_SUCCESS == result);
216 result = (*playerEffectSend)->EnableEffectSend(playerEffectSend, mixEnvironmentalReverb,
217 SL_BOOLEAN_TRUE, (SLmillibel) 0);
218 assert(SL_RESULT_SUCCESS == result);
221 // get the play interface
222 SLPlayItf playerPlay;
223 result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay);
224 assert(SL_RESULT_SUCCESS == result);
226 // get the buffer queue interface
227 SLBufferQueueItf playerBufferQueue;
228 result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE,
230 assert(SL_RESULT_SUCCESS == result);
232 // loop until EOF or no more buffers
233 for (which = 0; which < numBuffers; ++which) {
234 short *buffer = &buffers[framesPerBuffer * sfinfo.channels * which];
235 sf_count_t frames = framesPerBuffer;
237 count = sf_readf_short(sndfile, buffer, frames);
239 eof = SL_BOOLEAN_TRUE;
244 result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, count * sfinfo.channels *
246 assert(SL_RESULT_SUCCESS == result);
248 if (which >= numBuffers)
251 // register a callback on the buffer queue
252 result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, callback, NULL);
253 assert(SL_RESULT_SUCCESS == result);
255 // set the player's state to playing
256 result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
257 assert(SL_RESULT_SUCCESS == result);
259 // wait until the buffer queue is empty
260 SLBufferQueueState bufqstate;
262 result = (*playerBufferQueue)->GetState(playerBufferQueue, &bufqstate);
263 assert(SL_RESULT_SUCCESS == result);
264 if (0 >= bufqstate.count) {
270 // destroy audio player
271 (*playerObject)->Destroy(playerObject);
273 // destroy output mix
274 (*outputMixObject)->Destroy(outputMixObject);
277 (*engineObject)->Destroy(engineObject);