playbq.c revision ebca1a420c4ada9eff2e82f0100abaea95b48f24
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;
40ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn KastenSLuint32 byteOrder; // desired to use for PCM buffers
41ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn KastenSLuint32 nativeByteOrder;   // of platform
42ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn KastenSLuint32 bitsPerSample = 16;
43ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten
44ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten// swap adjacent bytes; this would normally be in <unistd.h> but is missing here
45ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kastenstatic void swab(const void *from, void *to, ssize_t n)
46ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten{
47ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    // from and to as char pointers
48ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    const char *from_ch = (const char *) from;
49ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    char *to_ch = (char *) to;
50ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    // note that we don't swap the last odd byte
51ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    while (n >= 2) {
52ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        to_ch[0] = from_ch[1];
53ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        to_ch[1] = from_ch[0];
54ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        to_ch += 2;
55ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        from_ch += 2;
56ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        n -= 2;
57ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    }
58ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten}
59ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten
60ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten// squeeze 16-bit signed PCM samples down to 8-bit unsigned PCM samples by truncation; no dithering
61ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kastenstatic void squeeze(const short *from, unsigned char *to, ssize_t n)
62ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten{
63ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    // note that we don't squeeze the last odd byte
64ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    while (n >= 2) {
65ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        *to++ = (*from++ + 32768) >> 8;
66ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        n -= 2;
67ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    }
68ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten}
690a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
700a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten// This callback is called each time a buffer finishes playing
710a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
720a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenstatic void callback(SLBufferQueueItf bufq, void *param)
730a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten{
749a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    assert(NULL == param);
750a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    if (!eof) {
760a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        short *buffer = &buffers[framesPerBuffer * sfinfo.channels * which];
770a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        sf_count_t count;
780a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        count = sf_readf_short(sndfile, buffer, (sf_count_t) framesPerBuffer);
790a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        if (0 >= count) {
800a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            eof = SL_BOOLEAN_TRUE;
810a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        } else {
82ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            SLuint32 nbytes = count * sfinfo.channels * sizeof(short);
83ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            if (byteOrder != nativeByteOrder) {
84ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten                swab(buffer, buffer, nbytes);
85ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            }
86ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            if (bitsPerSample == 8) {
87ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten                squeeze(buffer, (unsigned char *) buffer, nbytes);
88ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten                nbytes /= 2;
89ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            }
90ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            SLresult result = (*bufq)->Enqueue(bufq, buffer, nbytes);
910a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            assert(SL_RESULT_SUCCESS == result);
920a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            if (++which >= numBuffers)
930a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten                which = 0;
940a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        }
950a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
960a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten}
970a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
980a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenint main(int argc, char **argv)
990a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten{
100ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    // Determine the native byte order (SL_BYTEORDER_NATIVE not available until 1.1)
101ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    union {
102ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        short s;
103ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        char c[2];
104ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    } u;
105ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    u.s = 0x1234;
106ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    if (u.c[0] == 0x34) {
107ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        nativeByteOrder = SL_BYTEORDER_LITTLEENDIAN;
108ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    } else if (u.c[0] == 0x12) {
109ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        nativeByteOrder = SL_BYTEORDER_BIGENDIAN;
110ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    } else {
111ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        fprintf(stderr, "Unable to determine native byte order\n");
112ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        return EXIT_FAILURE;
113ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    }
114ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    byteOrder = nativeByteOrder;
115ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten
1160a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLboolean enableReverb = SL_BOOLEAN_FALSE;
1179a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    SLpermille rate = 1000;
1180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
1190a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // process command-line options
1200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    int i;
1210a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    for (i = 1; i < argc; ++i) {
1220a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        char *arg = argv[i];
1230a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        if (arg[0] != '-')
1240a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            break;
125ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        if (!strcmp(arg, "-b")) {
126ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            byteOrder = SL_BYTEORDER_BIGENDIAN;
127ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        } else if (!strcmp(arg, "-l")) {
128ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            byteOrder = SL_BYTEORDER_LITTLEENDIAN;
129ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        } else if (!strcmp(arg, "-8")) {
130ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            bitsPerSample = 8;
131ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        } else if (!strncmp(arg, "-f", 2)) {
1320a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            framesPerBuffer = atoi(&arg[2]);
1330a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        } else if (!strncmp(arg, "-n", 2)) {
1340a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            numBuffers = atoi(&arg[2]);
1359a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten        } else if (!strncmp(arg, "-p", 2)) {
1369a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten            rate = atoi(&arg[2]);
1370a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        } else if (!strcmp(arg, "-r")) {
1380a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            enableReverb = SL_BOOLEAN_TRUE;
1390a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        } else {
1400a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            fprintf(stderr, "option %s ignored\n", arg);
1410a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        }
1420a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
1430a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
1440a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    if (argc - i != 1) {
145ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        fprintf(stderr, "usage: [-b/l] [-8] [-f#] [-n#] [-p#] [-r] %s filename\n", argv[0]);
1460a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        return EXIT_FAILURE;
1470a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
1480a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
1490a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    const char *filename = argv[i];
1500a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    //memset(&sfinfo, 0, sizeof(SF_INFO));
1510a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    sfinfo.format = 0;
1520a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    sndfile = sf_open(filename, SFM_READ, &sfinfo);
1530a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    if (NULL == sndfile) {
1540a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        perror(filename);
1550a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        return EXIT_FAILURE;
1560a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
1570a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
1580a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // verify the file format
1590a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    switch (sfinfo.channels) {
1600a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 1:
1610a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 2:
1620a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        break;
1630a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    default:
1640a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        fprintf(stderr, "unsupported channel count %d\n", sfinfo.channels);
1650a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        break;
1660a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
1670a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    switch (sfinfo.samplerate) {
1680a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case  8000:
1690a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 11025:
1700a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 12000:
1710a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 16000:
1720a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 22050:
1730a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 24000:
1740a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 32000:
1750a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 44100:
1760a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 48000:
1770a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        break;
1780a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    default:
1790a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        fprintf(stderr, "unsupported sample rate %d\n", sfinfo.samplerate);
1800a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        break;
1810a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
1820a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    switch (sfinfo.format & SF_FORMAT_TYPEMASK) {
1830a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case SF_FORMAT_WAV:
1840a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        break;
1850a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    default:
1860a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        fprintf(stderr, "unsupported format type 0x%x\n", sfinfo.format & SF_FORMAT_TYPEMASK);
1870a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        break;
1880a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
1890a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    switch (sfinfo.format & SF_FORMAT_SUBMASK) {
1900a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case SF_FORMAT_PCM_16:
1910a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case SF_FORMAT_PCM_U8:
1920a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case SF_FORMAT_ULAW:
1930a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case SF_FORMAT_ALAW:
1940a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case SF_FORMAT_IMA_ADPCM:
1950a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        break;
1960a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    default:
1970a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        fprintf(stderr, "unsupported sub-format 0x%x\n", sfinfo.format & SF_FORMAT_SUBMASK);
1980a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        break;
1990a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
2000a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2010a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    buffers = (short *) malloc(framesPerBuffer * sfinfo.channels * sizeof(short) * numBuffers);
2020a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2030a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // create engine
2040a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLresult result;
2050a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLObjectItf engineObject;
2060a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
2070a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
2080a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLEngineItf engineEngine;
2090a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
2100a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
2110a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
2120a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
2130a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2140a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // create output mix
2150a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLObjectItf outputMixObject;
2160a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};
2170a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLboolean req[1] = {SL_BOOLEAN_TRUE};
2180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, enableReverb ? 1 : 0,
2190a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            ids, req);
2200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
2210a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
2220a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
2230a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2240a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // configure environmental reverb on output mix
2250a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLEnvironmentalReverbItf mixEnvironmentalReverb = NULL;
2260a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    if (enableReverb) {
2270a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB,
2280a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten                &mixEnvironmentalReverb);
2290a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
2300a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        SLEnvironmentalReverbSettings settings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR;
2310a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        result = (*mixEnvironmentalReverb)->SetEnvironmentalReverbProperties(mixEnvironmentalReverb,
2320a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten                &settings);
2330a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
2340a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
2350a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2360a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // configure audio source
2370a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLDataLocator_BufferQueue loc_bufq;
2380a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    loc_bufq.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
2390a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    loc_bufq.numBuffers = numBuffers;
2400a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLDataFormat_PCM format_pcm;
2410a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    format_pcm.formatType = SL_DATAFORMAT_PCM;
2420a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    format_pcm.numChannels = sfinfo.channels;
2430a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    format_pcm.samplesPerSec = sfinfo.samplerate * 1000;
244ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    format_pcm.bitsPerSample = bitsPerSample;
2450a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    format_pcm.containerSize = format_pcm.bitsPerSample;
2460a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    format_pcm.channelMask = 1 == format_pcm.numChannels ? SL_SPEAKER_FRONT_CENTER :
2470a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
248ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    format_pcm.endianness = byteOrder;
2490a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLDataSource audioSrc;
2500a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    audioSrc.pLocator = &loc_bufq;
2510a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    audioSrc.pFormat = &format_pcm;
2520a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2530a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // configure audio sink
2540a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLDataLocator_OutputMix loc_outmix;
2550a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
2560a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    loc_outmix.outputMix = outputMixObject;
2570a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLDataSink audioSnk;
2580a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    audioSnk.pLocator = &loc_outmix;
2590a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    audioSnk.pFormat = NULL;
2600a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2610a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // create audio player
2629a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    SLInterfaceID ids2[3] = {SL_IID_BUFFERQUEUE, SL_IID_PLAYBACKRATE, SL_IID_EFFECTSEND};
2639a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    SLboolean req2[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
2640a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLObjectItf playerObject;
2650a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audioSrc,
2669a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten            &audioSnk, enableReverb ? 3 : 2, ids2, req2);
2670a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
2680a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2690a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // realize the player
2700a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
2710a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
2720a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2730a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // get the effect send interface and enable effect send reverb for this player
2740a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    if (enableReverb) {
2750a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        SLEffectSendItf playerEffectSend;
2760a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        result = (*playerObject)->GetInterface(playerObject, SL_IID_EFFECTSEND, &playerEffectSend);
2770a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
2780a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        result = (*playerEffectSend)->EnableEffectSend(playerEffectSend, mixEnvironmentalReverb,
2790a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten                SL_BOOLEAN_TRUE, (SLmillibel) 0);
2800a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
2810a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
2820a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2839a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    // get the playback rate interface and configure the rate
2849a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    SLPlaybackRateItf playerPlaybackRate;
2859a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAYBACKRATE, &playerPlaybackRate);
2869a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
2879a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    SLpermille defaultRate;
2889a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    result = (*playerPlaybackRate)->GetRate(playerPlaybackRate, &defaultRate);
2899a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
2909a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    SLuint32 defaultProperties;
2919a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    result = (*playerPlaybackRate)->GetProperties(playerPlaybackRate, &defaultProperties);
2929a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
2939a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    printf("default playback rate %d per mille, properties 0x%x\n", defaultRate, defaultProperties);
2949a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    if (rate != defaultRate) {
2959a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten        result = (*playerPlaybackRate)->SetRate(playerPlaybackRate, rate);
2969a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten        if (SL_RESULT_FEATURE_UNSUPPORTED == result) {
2979a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten            fprintf(stderr, "playback rate %d is unsupported\n", rate);
2989a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten        } else if (SL_RESULT_PARAMETER_INVALID == result) {
2999a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten            fprintf(stderr, "playback rate %d is invalid", rate);
3009a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten        } else {
3019a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten            assert(SL_RESULT_SUCCESS == result);
3029a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten        }
3039a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    }
3049a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten
3050a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // get the play interface
3060a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLPlayItf playerPlay;
3070a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay);
3080a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
3090a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
3100a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // get the buffer queue interface
3110a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLBufferQueueItf playerBufferQueue;
3120a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE,
3130a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            &playerBufferQueue);
3140a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
3150a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
3160a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // loop until EOF or no more buffers
3170a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    for (which = 0; which < numBuffers; ++which) {
3180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        short *buffer = &buffers[framesPerBuffer * sfinfo.channels * which];
3190a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        sf_count_t frames = framesPerBuffer;
3200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        sf_count_t count;
3210a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        count = sf_readf_short(sndfile, buffer, frames);
3220a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        if (0 >= count) {
3230a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            eof = SL_BOOLEAN_TRUE;
3240a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            break;
3250a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        }
3260a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
3270a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        // enqueue a buffer
328ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        SLuint32 nbytes = count * sfinfo.channels * sizeof(short);
329ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        if (byteOrder != nativeByteOrder) {
330ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            swab(buffer, buffer, nbytes);
331ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        }
332ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        if (bitsPerSample == 8) {
333ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            squeeze(buffer, (unsigned char *) buffer, nbytes);
334ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            nbytes /= 2;
335ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        }
336ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, nbytes);
3370a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
3380a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
3390a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    if (which >= numBuffers)
3400a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        which = 0;
3410a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
3420a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // register a callback on the buffer queue
3430a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, callback, NULL);
3440a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
3450a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
3460a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // set the player's state to playing
3470a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
3480a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
3490a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
3500a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // wait until the buffer queue is empty
3510a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLBufferQueueState bufqstate;
3520a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    for (;;) {
3530a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        result = (*playerBufferQueue)->GetState(playerBufferQueue, &bufqstate);
3540a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
3550a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        if (0 >= bufqstate.count) {
3560a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            break;
3570a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        }
3580a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        sleep(1);
3590a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
3600a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
3610a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // destroy audio player
3620a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    (*playerObject)->Destroy(playerObject);
3630a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
3640a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // destroy output mix
3650a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    (*outputMixObject)->Destroy(outputMixObject);
3660a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
3670a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // destroy engine
3680a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    (*engineObject)->Destroy(engineObject);
3690a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
3700a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    return EXIT_SUCCESS;
3710a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten}
372