Home | History | Annotate | Download | only in sandbox
      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 
     33 unsigned numBuffers = 2;
     34 int framesPerBuffer = 512;
     35 SNDFILE *sndfile;
     36 SF_INFO sfinfo;
     37 unsigned which; // which buffer to use next
     38 SLboolean eof;  // whether we have hit EOF on input yet
     39 short *buffers;
     40 
     41 // This callback is called each time a buffer finishes playing
     42 
     43 static 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 
     61 int 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