playbq.cpp revision c6853892c94800e72c0bd676d5d2136d48cea76e
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    if (!eof) {
46        short *buffer = &buffers[framesPerBuffer * sfinfo.channels * which];
47        sf_count_t count;
48        count = sf_readf_short(sndfile, buffer, (sf_count_t) framesPerBuffer);
49        if (0 >= count) {
50            eof = SL_BOOLEAN_TRUE;
51        } else {
52            SLresult result = (*bufq)->Enqueue(bufq, buffer, count * sfinfo.channels *
53                    sizeof(short));
54            assert(SL_RESULT_SUCCESS == result);
55            if (++which >= numBuffers)
56                which = 0;
57        }
58    }
59}
60
61int main(int argc, char **argv)
62{
63    SLboolean enableReverb = SL_BOOLEAN_FALSE;
64
65    // process command-line options
66    int i;
67    for (i = 1; i < argc; ++i) {
68        char *arg = argv[i];
69        if (arg[0] != '-')
70            break;
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;
77        } else {
78            fprintf(stderr, "option %s ignored\n", arg);
79        }
80    }
81
82    if (argc - i != 1) {
83        fprintf(stderr, "usage: [-r] %s filename\n", argv[0]);
84        return EXIT_FAILURE;
85    }
86
87    const char *filename = argv[i];
88    //memset(&sfinfo, 0, sizeof(SF_INFO));
89    sfinfo.format = 0;
90    sndfile = sf_open(filename, SFM_READ, &sfinfo);
91    if (NULL == sndfile) {
92        perror(filename);
93        return EXIT_FAILURE;
94    }
95
96    // verify the file format
97    switch (sfinfo.channels) {
98    case 1:
99    case 2:
100        break;
101    default:
102        fprintf(stderr, "unsupported channel count %d\n", sfinfo.channels);
103        break;
104    }
105    switch (sfinfo.samplerate) {
106    case  8000:
107    case 11025:
108    case 12000:
109    case 16000:
110    case 22050:
111    case 24000:
112    case 32000:
113    case 44100:
114    case 48000:
115        break;
116    default:
117        fprintf(stderr, "unsupported sample rate %d\n", sfinfo.samplerate);
118        break;
119    }
120    switch (sfinfo.format & SF_FORMAT_TYPEMASK) {
121    case SF_FORMAT_WAV:
122        break;
123    default:
124        fprintf(stderr, "unsupported format type 0x%x\n", sfinfo.format & SF_FORMAT_TYPEMASK);
125        break;
126    }
127    switch (sfinfo.format & SF_FORMAT_SUBMASK) {
128    case SF_FORMAT_PCM_16:
129    case SF_FORMAT_PCM_U8:
130    case SF_FORMAT_ULAW:
131    case SF_FORMAT_ALAW:
132    case SF_FORMAT_IMA_ADPCM:
133        break;
134    default:
135        fprintf(stderr, "unsupported sub-format 0x%x\n", sfinfo.format & SF_FORMAT_SUBMASK);
136        break;
137    }
138
139    buffers = (short *) malloc(framesPerBuffer * sfinfo.channels * sizeof(short) * numBuffers);
140
141    // create engine
142    SLresult result;
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);
151
152    // create output mix
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,
157            ids, req);
158    assert(SL_RESULT_SUCCESS == result);
159    result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
160    assert(SL_RESULT_SUCCESS == result);
161
162    // configure environmental reverb on output mix
163    SLEnvironmentalReverbItf mixEnvironmentalReverb = NULL;
164    if (enableReverb) {
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,
170                &settings);
171        assert(SL_RESULT_SUCCESS == result);
172    }
173
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;
190
191    // configure audio sink
192    SLDataLocator_OutputMix loc_outmix;
193    loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
194    loc_outmix.outputMix = outputMixObject;
195    SLDataSink audioSnk;
196    audioSnk.pLocator = &loc_outmix;
197    audioSnk.pFormat = NULL;
198
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);
206
207    // realize the player
208    result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
209    assert(SL_RESULT_SUCCESS == result);
210
211    // get the effect send interface and enable effect send reverb for this player
212    if (enableReverb) {
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);
219    }
220
221    // get the play interface
222    SLPlayItf playerPlay;
223    result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay);
224    assert(SL_RESULT_SUCCESS == result);
225
226    // get the buffer queue interface
227    SLBufferQueueItf playerBufferQueue;
228    result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE,
229            &playerBufferQueue);
230    assert(SL_RESULT_SUCCESS == result);
231
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;
236        sf_count_t count;
237        count = sf_readf_short(sndfile, buffer, frames);
238        if (0 >= count) {
239            eof = SL_BOOLEAN_TRUE;
240            break;
241        }
242
243        // enqueue a buffer
244        result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, count * sfinfo.channels *
245                sizeof(short));
246        assert(SL_RESULT_SUCCESS == result);
247    }
248    if (which >= numBuffers)
249        which = 0;
250
251    // register a callback on the buffer queue
252    result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, callback, NULL);
253    assert(SL_RESULT_SUCCESS == result);
254
255    // set the player's state to playing
256    result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
257    assert(SL_RESULT_SUCCESS == result);
258
259    // wait until the buffer queue is empty
260    SLBufferQueueState bufqstate;
261    for (;;) {
262        result = (*playerBufferQueue)->GetState(playerBufferQueue, &bufqstate);
263        assert(SL_RESULT_SUCCESS == result);
264        if (0 >= bufqstate.count) {
265            break;
266        }
267        sleep(1);
268    }
269
270    // destroy audio player
271    (*playerObject)->Destroy(playerObject);
272
273    // destroy output mix
274    (*outputMixObject)->Destroy(outputMixObject);
275
276    // destroy engine
277    (*engineObject)->Destroy(engineObject);
278
279    return EXIT_SUCCESS;
280}
281