playbq.c revision 9a6c9db763121c3b11765c6c8cf935983c0385bf
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
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
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17// Play an audio file using buffer queue
18
19#include <assert.h>
20#include <math.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <unistd.h>
25
26#include <SLES/OpenSLES.h>
27#ifdef ANDROID
28#include "sndfile.h"
29#else
30#include <sndfile.h>
31#endif
32
33unsigned numBuffers = 2;
34int framesPerBuffer = 512;
35SNDFILE *sndfile;
36SF_INFO sfinfo;
37unsigned which; // which buffer to use next
38SLboolean eof;  // whether we have hit EOF on input yet
39short *buffers;
40
41// This callback is called each time a buffer finishes playing
42
43static void callback(SLBufferQueueItf bufq, void *param)
44{
45    assert(NULL == param);
46    if (!eof) {
47        short *buffer = &buffers[framesPerBuffer * sfinfo.channels * which];
48        sf_count_t count;
49        count = sf_readf_short(sndfile, buffer, (sf_count_t) framesPerBuffer);
50        if (0 >= count) {
51            eof = SL_BOOLEAN_TRUE;
52        } else {
53            SLresult result = (*bufq)->Enqueue(bufq, buffer, count * sfinfo.channels *
54                    sizeof(short));
55            assert(SL_RESULT_SUCCESS == result);
56            if (++which >= numBuffers)
57                which = 0;
58        }
59    }
60}
61
62int main(int argc, char **argv)
63{
64    SLboolean enableReverb = SL_BOOLEAN_FALSE;
65    SLpermille rate = 1000;
66
67    // process command-line options
68    int i;
69    for (i = 1; i < argc; ++i) {
70        char *arg = argv[i];
71        if (arg[0] != '-')
72            break;
73        if (!strncmp(arg, "-f", 2)) {
74            framesPerBuffer = atoi(&arg[2]);
75        } else if (!strncmp(arg, "-n", 2)) {
76            numBuffers = atoi(&arg[2]);
77        } else if (!strncmp(arg, "-p", 2)) {
78            rate = atoi(&arg[2]);
79        } else if (!strcmp(arg, "-r")) {
80            enableReverb = SL_BOOLEAN_TRUE;
81        } else {
82            fprintf(stderr, "option %s ignored\n", arg);
83        }
84    }
85
86    if (argc - i != 1) {
87        fprintf(stderr, "usage: [-f#] [-n] [-p#] [-r] %s filename\n", argv[0]);
88        return EXIT_FAILURE;
89    }
90
91    const char *filename = argv[i];
92    //memset(&sfinfo, 0, sizeof(SF_INFO));
93    sfinfo.format = 0;
94    sndfile = sf_open(filename, SFM_READ, &sfinfo);
95    if (NULL == sndfile) {
96        perror(filename);
97        return EXIT_FAILURE;
98    }
99
100    // verify the file format
101    switch (sfinfo.channels) {
102    case 1:
103    case 2:
104        break;
105    default:
106        fprintf(stderr, "unsupported channel count %d\n", sfinfo.channels);
107        break;
108    }
109    switch (sfinfo.samplerate) {
110    case  8000:
111    case 11025:
112    case 12000:
113    case 16000:
114    case 22050:
115    case 24000:
116    case 32000:
117    case 44100:
118    case 48000:
119        break;
120    default:
121        fprintf(stderr, "unsupported sample rate %d\n", sfinfo.samplerate);
122        break;
123    }
124    switch (sfinfo.format & SF_FORMAT_TYPEMASK) {
125    case SF_FORMAT_WAV:
126        break;
127    default:
128        fprintf(stderr, "unsupported format type 0x%x\n", sfinfo.format & SF_FORMAT_TYPEMASK);
129        break;
130    }
131    switch (sfinfo.format & SF_FORMAT_SUBMASK) {
132    case SF_FORMAT_PCM_16:
133    case SF_FORMAT_PCM_U8:
134    case SF_FORMAT_ULAW:
135    case SF_FORMAT_ALAW:
136    case SF_FORMAT_IMA_ADPCM:
137        break;
138    default:
139        fprintf(stderr, "unsupported sub-format 0x%x\n", sfinfo.format & SF_FORMAT_SUBMASK);
140        break;
141    }
142
143    buffers = (short *) malloc(framesPerBuffer * sfinfo.channels * sizeof(short) * numBuffers);
144
145    // create engine
146    SLresult result;
147    SLObjectItf engineObject;
148    result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
149    assert(SL_RESULT_SUCCESS == result);
150    SLEngineItf engineEngine;
151    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
152    assert(SL_RESULT_SUCCESS == result);
153    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
154    assert(SL_RESULT_SUCCESS == result);
155
156    // create output mix
157    SLObjectItf outputMixObject;
158    SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};
159    SLboolean req[1] = {SL_BOOLEAN_TRUE};
160    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, enableReverb ? 1 : 0,
161            ids, req);
162    assert(SL_RESULT_SUCCESS == result);
163    result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
164    assert(SL_RESULT_SUCCESS == result);
165
166    // configure environmental reverb on output mix
167    SLEnvironmentalReverbItf mixEnvironmentalReverb = NULL;
168    if (enableReverb) {
169        result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB,
170                &mixEnvironmentalReverb);
171        assert(SL_RESULT_SUCCESS == result);
172        SLEnvironmentalReverbSettings settings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR;
173        result = (*mixEnvironmentalReverb)->SetEnvironmentalReverbProperties(mixEnvironmentalReverb,
174                &settings);
175        assert(SL_RESULT_SUCCESS == result);
176    }
177
178    // configure audio source
179    SLDataLocator_BufferQueue loc_bufq;
180    loc_bufq.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
181    loc_bufq.numBuffers = numBuffers;
182    SLDataFormat_PCM format_pcm;
183    format_pcm.formatType = SL_DATAFORMAT_PCM;
184    format_pcm.numChannels = sfinfo.channels;
185    format_pcm.samplesPerSec = sfinfo.samplerate * 1000;
186    format_pcm.bitsPerSample = 16;
187    format_pcm.containerSize = format_pcm.bitsPerSample;
188    format_pcm.channelMask = 1 == format_pcm.numChannels ? SL_SPEAKER_FRONT_CENTER :
189            SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
190    format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
191    SLDataSource audioSrc;
192    audioSrc.pLocator = &loc_bufq;
193    audioSrc.pFormat = &format_pcm;
194
195    // configure audio sink
196    SLDataLocator_OutputMix loc_outmix;
197    loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
198    loc_outmix.outputMix = outputMixObject;
199    SLDataSink audioSnk;
200    audioSnk.pLocator = &loc_outmix;
201    audioSnk.pFormat = NULL;
202
203    // create audio player
204    SLInterfaceID ids2[3] = {SL_IID_BUFFERQUEUE, SL_IID_PLAYBACKRATE, SL_IID_EFFECTSEND};
205    SLboolean req2[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
206    SLObjectItf playerObject;
207    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audioSrc,
208            &audioSnk, enableReverb ? 3 : 2, ids2, req2);
209    assert(SL_RESULT_SUCCESS == result);
210
211    // realize the player
212    result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
213    assert(SL_RESULT_SUCCESS == result);
214
215    // get the effect send interface and enable effect send reverb for this player
216    if (enableReverb) {
217        SLEffectSendItf playerEffectSend;
218        result = (*playerObject)->GetInterface(playerObject, SL_IID_EFFECTSEND, &playerEffectSend);
219        assert(SL_RESULT_SUCCESS == result);
220        result = (*playerEffectSend)->EnableEffectSend(playerEffectSend, mixEnvironmentalReverb,
221                SL_BOOLEAN_TRUE, (SLmillibel) 0);
222        assert(SL_RESULT_SUCCESS == result);
223    }
224
225    // get the playback rate interface and configure the rate
226    SLPlaybackRateItf playerPlaybackRate;
227    result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAYBACKRATE, &playerPlaybackRate);
228    assert(SL_RESULT_SUCCESS == result);
229    SLpermille defaultRate;
230    result = (*playerPlaybackRate)->GetRate(playerPlaybackRate, &defaultRate);
231    assert(SL_RESULT_SUCCESS == result);
232    SLuint32 defaultProperties;
233    result = (*playerPlaybackRate)->GetProperties(playerPlaybackRate, &defaultProperties);
234    assert(SL_RESULT_SUCCESS == result);
235    printf("default playback rate %d per mille, properties 0x%x\n", defaultRate, defaultProperties);
236    if (rate != defaultRate) {
237        result = (*playerPlaybackRate)->SetRate(playerPlaybackRate, rate);
238        if (SL_RESULT_FEATURE_UNSUPPORTED == result) {
239            fprintf(stderr, "playback rate %d is unsupported\n", rate);
240        } else if (SL_RESULT_PARAMETER_INVALID == result) {
241            fprintf(stderr, "playback rate %d is invalid", rate);
242        } else {
243            assert(SL_RESULT_SUCCESS == result);
244        }
245    }
246
247    // get the play interface
248    SLPlayItf playerPlay;
249    result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay);
250    assert(SL_RESULT_SUCCESS == result);
251
252    // get the buffer queue interface
253    SLBufferQueueItf playerBufferQueue;
254    result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE,
255            &playerBufferQueue);
256    assert(SL_RESULT_SUCCESS == result);
257
258    // loop until EOF or no more buffers
259    for (which = 0; which < numBuffers; ++which) {
260        short *buffer = &buffers[framesPerBuffer * sfinfo.channels * which];
261        sf_count_t frames = framesPerBuffer;
262        sf_count_t count;
263        count = sf_readf_short(sndfile, buffer, frames);
264        if (0 >= count) {
265            eof = SL_BOOLEAN_TRUE;
266            break;
267        }
268
269        // enqueue a buffer
270        result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, count * sfinfo.channels *
271                sizeof(short));
272        assert(SL_RESULT_SUCCESS == result);
273    }
274    if (which >= numBuffers)
275        which = 0;
276
277    // register a callback on the buffer queue
278    result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, callback, NULL);
279    assert(SL_RESULT_SUCCESS == result);
280
281    // set the player's state to playing
282    result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
283    assert(SL_RESULT_SUCCESS == result);
284
285    // wait until the buffer queue is empty
286    SLBufferQueueState bufqstate;
287    for (;;) {
288        result = (*playerBufferQueue)->GetState(playerBufferQueue, &bufqstate);
289        assert(SL_RESULT_SUCCESS == result);
290        if (0 >= bufqstate.count) {
291            break;
292        }
293        sleep(1);
294    }
295
296    // destroy audio player
297    (*playerObject)->Destroy(playerObject);
298
299    // destroy output mix
300    (*outputMixObject)->Destroy(outputMixObject);
301
302    // destroy engine
303    (*engineObject)->Destroy(engineObject);
304
305    return EXIT_SUCCESS;
306}
307