playbq.c revision 9a6c9db763121c3b11765c6c8cf935983c0385bf
10a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten/*
20a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * Copyright (C) 2010 The Android Open Source Project
30a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten *
40a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * Licensed under the Apache License, Version 2.0 (the "License");
50a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * you may not use this file except in compliance with the License.
60a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * You may obtain a copy of the License at
70a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten *
80a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten *      http://www.apache.org/licenses/LICENSE-2.0
90a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten *
100a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * Unless required by applicable law or agreed to in writing, software
110a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * distributed under the License is distributed on an "AS IS" BASIS,
120a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * See the License for the specific language governing permissions and
140a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * limitations under the License.
150a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten */
160a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
170a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten// Play an audio file using buffer queue
180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
190a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <assert.h>
200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <math.h>
210a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <stdio.h>
220a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <stdlib.h>
230a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <string.h>
240a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <unistd.h>
250a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
26c6853892c94800e72c0bd676d5d2136d48cea76eGlenn Kasten#include <SLES/OpenSLES.h>
270a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#ifdef ANDROID
280a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include "sndfile.h"
290a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#else
300a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <sndfile.h>
310a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#endif
320a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
330a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenunsigned numBuffers = 2;
340a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenint framesPerBuffer = 512;
350a058cc3d720cdf3f0f8222472a862258482f34fGlenn KastenSNDFILE *sndfile;
360a058cc3d720cdf3f0f8222472a862258482f34fGlenn KastenSF_INFO sfinfo;
370a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenunsigned which; // which buffer to use next
380a058cc3d720cdf3f0f8222472a862258482f34fGlenn KastenSLboolean eof;  // whether we have hit EOF on input yet
390a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenshort *buffers;
400a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
410a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten// This callback is called each time a buffer finishes playing
420a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
430a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenstatic void callback(SLBufferQueueItf bufq, void *param)
440a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten{
459a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    assert(NULL == param);
460a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    if (!eof) {
470a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        short *buffer = &buffers[framesPerBuffer * sfinfo.channels * which];
480a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        sf_count_t count;
490a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        count = sf_readf_short(sndfile, buffer, (sf_count_t) framesPerBuffer);
500a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        if (0 >= count) {
510a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            eof = SL_BOOLEAN_TRUE;
520a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        } else {
530a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            SLresult result = (*bufq)->Enqueue(bufq, buffer, count * sfinfo.channels *
540a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten                    sizeof(short));
550a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            assert(SL_RESULT_SUCCESS == result);
560a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            if (++which >= numBuffers)
570a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten                which = 0;
580a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        }
590a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
600a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten}
610a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
620a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenint main(int argc, char **argv)
630a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten{
640a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLboolean enableReverb = SL_BOOLEAN_FALSE;
659a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    SLpermille rate = 1000;
660a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
670a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // process command-line options
680a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    int i;
690a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    for (i = 1; i < argc; ++i) {
700a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        char *arg = argv[i];
710a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        if (arg[0] != '-')
720a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            break;
730a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        if (!strncmp(arg, "-f", 2)) {
740a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            framesPerBuffer = atoi(&arg[2]);
750a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        } else if (!strncmp(arg, "-n", 2)) {
760a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            numBuffers = atoi(&arg[2]);
779a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten        } else if (!strncmp(arg, "-p", 2)) {
789a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten            rate = atoi(&arg[2]);
790a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        } else if (!strcmp(arg, "-r")) {
800a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            enableReverb = SL_BOOLEAN_TRUE;
810a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        } else {
820a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            fprintf(stderr, "option %s ignored\n", arg);
830a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        }
840a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
850a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
860a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    if (argc - i != 1) {
879a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten        fprintf(stderr, "usage: [-f#] [-n] [-p#] [-r] %s filename\n", argv[0]);
880a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        return EXIT_FAILURE;
890a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
900a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
910a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    const char *filename = argv[i];
920a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    //memset(&sfinfo, 0, sizeof(SF_INFO));
930a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    sfinfo.format = 0;
940a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    sndfile = sf_open(filename, SFM_READ, &sfinfo);
950a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    if (NULL == sndfile) {
960a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        perror(filename);
970a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        return EXIT_FAILURE;
980a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
990a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
1000a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // verify the file format
1010a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    switch (sfinfo.channels) {
1020a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 1:
1030a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 2:
1040a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        break;
1050a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    default:
1060a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        fprintf(stderr, "unsupported channel count %d\n", sfinfo.channels);
1070a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        break;
1080a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
1090a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    switch (sfinfo.samplerate) {
1100a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case  8000:
1110a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 11025:
1120a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 12000:
1130a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 16000:
1140a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 22050:
1150a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 24000:
1160a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 32000:
1170a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 44100:
1180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 48000:
1190a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        break;
1200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    default:
1210a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        fprintf(stderr, "unsupported sample rate %d\n", sfinfo.samplerate);
1220a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        break;
1230a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
1240a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    switch (sfinfo.format & SF_FORMAT_TYPEMASK) {
1250a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case SF_FORMAT_WAV:
1260a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        break;
1270a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    default:
1280a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        fprintf(stderr, "unsupported format type 0x%x\n", sfinfo.format & SF_FORMAT_TYPEMASK);
1290a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        break;
1300a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
1310a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    switch (sfinfo.format & SF_FORMAT_SUBMASK) {
1320a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case SF_FORMAT_PCM_16:
1330a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case SF_FORMAT_PCM_U8:
1340a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case SF_FORMAT_ULAW:
1350a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case SF_FORMAT_ALAW:
1360a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case SF_FORMAT_IMA_ADPCM:
1370a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        break;
1380a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    default:
1390a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        fprintf(stderr, "unsupported sub-format 0x%x\n", sfinfo.format & SF_FORMAT_SUBMASK);
1400a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        break;
1410a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
1420a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
1430a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    buffers = (short *) malloc(framesPerBuffer * sfinfo.channels * sizeof(short) * numBuffers);
1440a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
1450a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // create engine
1460a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLresult result;
1470a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLObjectItf engineObject;
1480a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
1490a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
1500a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLEngineItf engineEngine;
1510a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
1520a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
1530a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
1540a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
1550a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
1560a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // create output mix
1570a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLObjectItf outputMixObject;
1580a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};
1590a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLboolean req[1] = {SL_BOOLEAN_TRUE};
1600a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, enableReverb ? 1 : 0,
1610a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            ids, req);
1620a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
1630a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
1640a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
1650a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
1660a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // configure environmental reverb on output mix
1670a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLEnvironmentalReverbItf mixEnvironmentalReverb = NULL;
1680a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    if (enableReverb) {
1690a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB,
1700a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten                &mixEnvironmentalReverb);
1710a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
1720a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        SLEnvironmentalReverbSettings settings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR;
1730a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        result = (*mixEnvironmentalReverb)->SetEnvironmentalReverbProperties(mixEnvironmentalReverb,
1740a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten                &settings);
1750a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
1760a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
1770a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
1780a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // configure audio source
1790a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLDataLocator_BufferQueue loc_bufq;
1800a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    loc_bufq.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
1810a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    loc_bufq.numBuffers = numBuffers;
1820a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLDataFormat_PCM format_pcm;
1830a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    format_pcm.formatType = SL_DATAFORMAT_PCM;
1840a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    format_pcm.numChannels = sfinfo.channels;
1850a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    format_pcm.samplesPerSec = sfinfo.samplerate * 1000;
1860a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    format_pcm.bitsPerSample = 16;
1870a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    format_pcm.containerSize = format_pcm.bitsPerSample;
1880a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    format_pcm.channelMask = 1 == format_pcm.numChannels ? SL_SPEAKER_FRONT_CENTER :
1890a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
1900a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
1910a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLDataSource audioSrc;
1920a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    audioSrc.pLocator = &loc_bufq;
1930a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    audioSrc.pFormat = &format_pcm;
1940a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
1950a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // configure audio sink
1960a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLDataLocator_OutputMix loc_outmix;
1970a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
1980a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    loc_outmix.outputMix = outputMixObject;
1990a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLDataSink audioSnk;
2000a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    audioSnk.pLocator = &loc_outmix;
2010a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    audioSnk.pFormat = NULL;
2020a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2030a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // create audio player
2049a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    SLInterfaceID ids2[3] = {SL_IID_BUFFERQUEUE, SL_IID_PLAYBACKRATE, SL_IID_EFFECTSEND};
2059a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    SLboolean req2[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
2060a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLObjectItf playerObject;
2070a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audioSrc,
2089a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten            &audioSnk, enableReverb ? 3 : 2, ids2, req2);
2090a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
2100a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2110a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // realize the player
2120a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
2130a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
2140a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2150a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // get the effect send interface and enable effect send reverb for this player
2160a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    if (enableReverb) {
2170a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        SLEffectSendItf playerEffectSend;
2180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        result = (*playerObject)->GetInterface(playerObject, SL_IID_EFFECTSEND, &playerEffectSend);
2190a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
2200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        result = (*playerEffectSend)->EnableEffectSend(playerEffectSend, mixEnvironmentalReverb,
2210a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten                SL_BOOLEAN_TRUE, (SLmillibel) 0);
2220a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
2230a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
2240a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2259a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    // get the playback rate interface and configure the rate
2269a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    SLPlaybackRateItf playerPlaybackRate;
2279a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAYBACKRATE, &playerPlaybackRate);
2289a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
2299a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    SLpermille defaultRate;
2309a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    result = (*playerPlaybackRate)->GetRate(playerPlaybackRate, &defaultRate);
2319a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
2329a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    SLuint32 defaultProperties;
2339a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    result = (*playerPlaybackRate)->GetProperties(playerPlaybackRate, &defaultProperties);
2349a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
2359a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    printf("default playback rate %d per mille, properties 0x%x\n", defaultRate, defaultProperties);
2369a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    if (rate != defaultRate) {
2379a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten        result = (*playerPlaybackRate)->SetRate(playerPlaybackRate, rate);
2389a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten        if (SL_RESULT_FEATURE_UNSUPPORTED == result) {
2399a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten            fprintf(stderr, "playback rate %d is unsupported\n", rate);
2409a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten        } else if (SL_RESULT_PARAMETER_INVALID == result) {
2419a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten            fprintf(stderr, "playback rate %d is invalid", rate);
2429a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten        } else {
2439a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten            assert(SL_RESULT_SUCCESS == result);
2449a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten        }
2459a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    }
2469a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten
2470a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // get the play interface
2480a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLPlayItf playerPlay;
2490a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay);
2500a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
2510a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2520a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // get the buffer queue interface
2530a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLBufferQueueItf playerBufferQueue;
2540a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE,
2550a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            &playerBufferQueue);
2560a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
2570a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2580a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // loop until EOF or no more buffers
2590a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    for (which = 0; which < numBuffers; ++which) {
2600a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        short *buffer = &buffers[framesPerBuffer * sfinfo.channels * which];
2610a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        sf_count_t frames = framesPerBuffer;
2620a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        sf_count_t count;
2630a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        count = sf_readf_short(sndfile, buffer, frames);
2640a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        if (0 >= count) {
2650a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            eof = SL_BOOLEAN_TRUE;
2660a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            break;
2670a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        }
2680a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2690a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        // enqueue a buffer
2700a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, count * sfinfo.channels *
2710a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten                sizeof(short));
2720a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
2730a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
2740a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    if (which >= numBuffers)
2750a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        which = 0;
2760a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2770a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // register a callback on the buffer queue
2780a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, callback, NULL);
2790a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
2800a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2810a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // set the player's state to playing
2820a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
2830a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
2840a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2850a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // wait until the buffer queue is empty
2860a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLBufferQueueState bufqstate;
2870a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    for (;;) {
2880a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        result = (*playerBufferQueue)->GetState(playerBufferQueue, &bufqstate);
2890a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
2900a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        if (0 >= bufqstate.count) {
2910a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            break;
2920a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        }
2930a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        sleep(1);
2940a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
2950a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2960a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // destroy audio player
2970a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    (*playerObject)->Destroy(playerObject);
2980a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2990a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // destroy output mix
3000a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    (*outputMixObject)->Destroy(outputMixObject);
3010a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
3020a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // destroy engine
3030a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    (*engineObject)->Destroy(engineObject);
3040a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
3050a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    return EXIT_SUCCESS;
3060a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten}
307