15bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten/*
25bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten * Copyright (C) 2010 The Android Open Source Project
35bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten *
45bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten * Licensed under the Apache License, Version 2.0 (the "License");
55bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten * you may not use this file except in compliance with the License.
65bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten * You may obtain a copy of the License at
75bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten *
85bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten *      http://www.apache.org/licenses/LICENSE-2.0
95bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten *
105bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten * Unless required by applicable law or agreed to in writing, software
115bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten * distributed under the License is distributed on an "AS IS" BASIS,
125bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten * See the License for the specific language governing permissions and
145bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten * limitations under the License.
155bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten */
165bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
175bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten// Play an audio file using buffer queue
185bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
195bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <assert.h>
205bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <math.h>
215bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <pthread.h>
225bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <stdio.h>
235bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <stdlib.h>
245bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <string.h>
255bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <time.h>
265bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <unistd.h>
275bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
285bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <SLES/OpenSLES.h>
295bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <SLES/OpenSLES_Android.h>
305bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <system/audio.h>
315bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <audio_utils/fifo.h>
325bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <audio_utils/primitives.h>
335bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <audio_utils/sndfile.h>
345bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
355bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#define max(a, b) ((a) > (b) ? (a) : (b))
365bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#define min(a, b) ((a) < (b) ? (a) : (b))
375bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
385bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastenunsigned numBuffers = 2;
395bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastenint framesPerBuffer = 512;
405bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn KastenSNDFILE *sndfile;
415bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn KastenSF_INFO sfinfo;
425bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastenunsigned which; // which buffer to use next
435bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn KastenSLboolean eof;  // whether we have hit EOF on input yet
445bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastenvoid *buffers;
455bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn KastenSLuint32 byteOrder; // desired to use for PCM buffers
465bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn KastenSLuint32 nativeByteOrder;   // of platform
475bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastenaudio_format_t transferFormat = AUDIO_FORMAT_DEFAULT;
485bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastensize_t sfframesize = 0;
495bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
50add2a2112de08f840459de78e8f8eb16d8c888c3Glenn Kastenstatic audio_utils_fifo *fifo;
5113e4fe3294ea101738253c72a3382101918d5682Glenn Kastenstatic audio_utils_fifo_reader *fifoReader;
5213e4fe3294ea101738253c72a3382101918d5682Glenn Kastenstatic audio_utils_fifo_writer *fifoWriter;
535bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastenstatic unsigned underruns = 0;
545bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
555bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastenstatic SLuint32 squeeze(void *buffer, SLuint32 nbytes)
565bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten{
575bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    if (byteOrder != nativeByteOrder) {
585bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        // FIXME does not work for non 16-bit
595bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        swab(buffer, buffer, nbytes);
605bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    }
615bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    if (transferFormat == AUDIO_FORMAT_PCM_8_BIT) {
625bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        memcpy_to_u8_from_i16((uint8_t *) buffer, (const int16_t *) buffer,
635bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                nbytes / sizeof(int16_t));
645bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        nbytes /= 2;
655bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    } else if (transferFormat == AUDIO_FORMAT_PCM_24_BIT_PACKED) {
665bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        memcpy_to_p24_from_i32((uint8_t *) buffer, (const int32_t *) buffer,
675bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                nbytes / sizeof(int32_t));
685bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        nbytes = nbytes * 3 / 4;
695bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    }
705bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    return nbytes;
715bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten}
725bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
735bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten// This callback is called each time a buffer finishes playing
745bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
755bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastenstatic void callback(SLBufferQueueItf bufq, void *param)
765bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten{
775bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    assert(NULL == param);
785bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    if (!eof) {
795bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        void *buffer = (char *)buffers + framesPerBuffer * sfframesize * which;
8013e4fe3294ea101738253c72a3382101918d5682Glenn Kasten        ssize_t count = fifoReader->read(buffer, framesPerBuffer);
815bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        // on underrun from pipe, substitute silence
825bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        if (0 >= count) {
835bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            memset(buffer, 0, framesPerBuffer * sfframesize);
845bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            count = framesPerBuffer;
855bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            ++underruns;
865bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        }
875bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        if (count > 0) {
885bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            SLuint32 nbytes = count * sfframesize;
895bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            nbytes = squeeze(buffer, nbytes);
905bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            SLresult result = (*bufq)->Enqueue(bufq, buffer, nbytes);
915bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            assert(SL_RESULT_SUCCESS == result);
925bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            if (++which >= numBuffers)
935bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                which = 0;
945bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        }
955bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    }
965bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten}
975bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
985bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten// This thread reads from a (slow) filesystem with unpredictable latency and writes to pipe
995bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
1005bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastenstatic void *file_reader_loop(void *arg __unused)
1015bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten{
1025bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#define READ_FRAMES 256
1035bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    void *temp = malloc(READ_FRAMES * sfframesize);
1045bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    sf_count_t total = 0;
1055bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    sf_count_t count;
1065bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    for (;;) {
1075bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        switch (transferFormat) {
1085bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        case AUDIO_FORMAT_PCM_FLOAT:
1095bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            count = sf_readf_float(sndfile, (float *) temp, READ_FRAMES);
1105bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            break;
1115bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        case AUDIO_FORMAT_PCM_32_BIT:
1125bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        case AUDIO_FORMAT_PCM_24_BIT_PACKED:
1135bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            count = sf_readf_int(sndfile, (int *) temp, READ_FRAMES);
1145bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            break;
1155bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        case AUDIO_FORMAT_PCM_16_BIT:
1165bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        case AUDIO_FORMAT_PCM_8_BIT:
1175bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            count = sf_readf_short(sndfile, (short *) temp, READ_FRAMES);
1185bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            break;
1195bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        default:
1205bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            count = 0;
1215bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            break;
1225bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        }
1235bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        if (0 >= count) {
1245bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            eof = SL_BOOLEAN_TRUE;
1255bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            break;
1265bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        }
1275bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        const unsigned char *ptr = (unsigned char *) temp;
1285bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        while (count > 0) {
12913e4fe3294ea101738253c72a3382101918d5682Glenn Kasten            ssize_t actual = fifoWriter->write(ptr, (size_t) count);
1305bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            if (actual < 0) {
1315bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                break;
1325bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            }
1335bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            if ((sf_count_t) actual < count) {
1345bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                usleep(10000);
1355bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            }
1365bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            ptr += actual * sfframesize;
1375bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            count -= actual;
1385bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            total += actual;
1395bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        }
1405bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        // simulate occasional filesystem latency
1415bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        if ((total & 0xFF00) == 0xFF00) {
1425bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            usleep(100000);
1435bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        }
1445bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    }
1455bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    free(temp);
1465bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    return NULL;
1475bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten}
1485bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
1495bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten// Main program
1505bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
1515bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastenint main(int argc, char **argv)
1525bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten{
1535bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // Determine the native byte order (SL_BYTEORDER_NATIVE not available until 1.1)
1545bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    union {
1555bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        short s;
1565bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        char c[2];
1575bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    } u;
1585bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    u.s = 0x1234;
1595bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    if (u.c[0] == 0x34) {
1605bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        nativeByteOrder = SL_BYTEORDER_LITTLEENDIAN;
1615bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    } else if (u.c[0] == 0x12) {
1625bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        nativeByteOrder = SL_BYTEORDER_BIGENDIAN;
1635bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    } else {
1645bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        fprintf(stderr, "Unable to determine native byte order\n");
1655bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        return EXIT_FAILURE;
1665bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    }
1675bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    byteOrder = nativeByteOrder;
1685bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
1695bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLboolean enableReverb = SL_BOOLEAN_FALSE;
1705bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLboolean enablePlaybackRate = SL_BOOLEAN_FALSE;
1715bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLpermille initialRate = 0;
1725bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLpermille finalRate = 0;
1735bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLpermille deltaRate = 1;
1745bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLmillisecond deltaRateMs = 0;
1755bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
1765bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // process command-line options
1775bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    int i;
1785bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    for (i = 1; i < argc; ++i) {
1795bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        char *arg = argv[i];
1805bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        if (arg[0] != '-') {
1815bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            break;
1825bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        }
1835bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        if (!strcmp(arg, "-b")) {
1845bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            byteOrder = SL_BYTEORDER_BIGENDIAN;
1855bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        } else if (!strcmp(arg, "-l")) {
1865bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            byteOrder = SL_BYTEORDER_LITTLEENDIAN;
1875bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        } else if (!strcmp(arg, "-8")) {
1885bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            transferFormat = AUDIO_FORMAT_PCM_8_BIT;
1895bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        } else if (!strcmp(arg, "-16")) {
1905bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            transferFormat = AUDIO_FORMAT_PCM_16_BIT;
1915bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        } else if (!strcmp(arg, "-24")) {
1925bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            transferFormat = AUDIO_FORMAT_PCM_24_BIT_PACKED;
1935bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        } else if (!strcmp(arg, "-32")) {
1945bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            transferFormat = AUDIO_FORMAT_PCM_32_BIT;
1955bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        } else if (!strcmp(arg, "-32f")) {
1965bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            transferFormat = AUDIO_FORMAT_PCM_FLOAT;
1975bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        } else if (!strncmp(arg, "-f", 2)) {
1985bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            framesPerBuffer = atoi(&arg[2]);
1995bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        } else if (!strncmp(arg, "-n", 2)) {
2005bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            numBuffers = atoi(&arg[2]);
2015bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        } else if (!strncmp(arg, "-p", 2)) {
2025bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            initialRate = atoi(&arg[2]);
2035bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            enablePlaybackRate = SL_BOOLEAN_TRUE;
2045bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        } else if (!strncmp(arg, "-P", 2)) {
2055bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            finalRate = atoi(&arg[2]);
2065bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            enablePlaybackRate = SL_BOOLEAN_TRUE;
2075bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        } else if (!strncmp(arg, "-q", 2)) {
2085bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            deltaRate = atoi(&arg[2]);
2095bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            // deltaRate is a magnitude, so take absolute value
2105bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            if (deltaRate < 0) {
2115bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                deltaRate = -deltaRate;
2125bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            }
2135bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            enablePlaybackRate = SL_BOOLEAN_TRUE;
2145bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        } else if (!strncmp(arg, "-Q", 2)) {
2155bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            deltaRateMs = atoi(&arg[2]);
2165bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            enablePlaybackRate = SL_BOOLEAN_TRUE;
2175bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        } else if (!strcmp(arg, "-r")) {
2185bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            enableReverb = SL_BOOLEAN_TRUE;
2195bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        } else {
2205bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            fprintf(stderr, "option %s ignored\n", arg);
2215bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        }
2225bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    }
2235bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
2245bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    if (argc - i != 1) {
2255bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        fprintf(stderr, "usage: [-b/l] [-8 | | -16 | -24 | -32 | -32f] [-f#] [-n#] [-p#] [-r]"
2265bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                " %s filename\n", argv[0]);
2275bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        fprintf(stderr, "    -b  force big-endian byte order (default is native byte order)\n");
2285bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        fprintf(stderr, "    -l  force little-endian byte order (default is native byte order)\n");
2295bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        fprintf(stderr, "    -8  output 8-bits per sample (default is that of input file)\n");
2305bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        fprintf(stderr, "    -16 output 16-bits per sample\n");
2315bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        fprintf(stderr, "    -24 output 24-bits per sample\n");
2325bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        fprintf(stderr, "    -32 output 32-bits per sample\n");
2335bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        fprintf(stderr, "    -32f output float 32-bits per sample\n");
2345bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        fprintf(stderr, "    -f# frames per buffer (default 512)\n");
2355bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        fprintf(stderr, "    -n# number of buffers (default 2)\n");
2365bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        fprintf(stderr, "    -p# initial playback rate in per mille (default 1000)\n");
2375bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        fprintf(stderr, "    -P# final playback rate in per mille (default same as -p#)\n");
2385bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        fprintf(stderr, "    -q# magnitude of playback rate changes in per mille (default 1)\n");
2395bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        fprintf(stderr, "    -Q# period between playback rate changes in ms (default 50)\n");
2405bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        fprintf(stderr, "    -r  enable reverb (default disabled)\n");
2415bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        return EXIT_FAILURE;
2425bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    }
2435bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
2445bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    const char *filename = argv[i];
2455bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    //memset(&sfinfo, 0, sizeof(SF_INFO));
2465bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    sfinfo.format = 0;
2475bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    sndfile = sf_open(filename, SFM_READ, &sfinfo);
2485bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    if (NULL == sndfile) {
2495bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        perror(filename);
2505bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        return EXIT_FAILURE;
2515bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    }
2525bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
2535bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // verify the file format
2545bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    switch (sfinfo.channels) {
2555bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    case 1:
2565bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    case 2:
2575bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        break;
2585bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    default:
2595bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        fprintf(stderr, "unsupported channel count %d\n", sfinfo.channels);
2605bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        goto close_sndfile;
2615bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    }
2625bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
2635bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    if (sfinfo.samplerate < 8000 || sfinfo.samplerate > 192000) {
2645bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        fprintf(stderr, "unsupported sample rate %d\n", sfinfo.samplerate);
2655bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        goto close_sndfile;
2665bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    }
2675bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
2685bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    switch (sfinfo.format & SF_FORMAT_TYPEMASK) {
2695bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    case SF_FORMAT_WAV:
2705bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        break;
2715bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    default:
2725bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        fprintf(stderr, "unsupported format type 0x%x\n", sfinfo.format & SF_FORMAT_TYPEMASK);
2735bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        goto close_sndfile;
2745bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    }
2755bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
2765bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    switch (sfinfo.format & SF_FORMAT_SUBMASK) {
2775bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    case SF_FORMAT_FLOAT:
2785bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        if (transferFormat == AUDIO_FORMAT_DEFAULT) {
2795bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            transferFormat = AUDIO_FORMAT_PCM_FLOAT;
2805bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        }
2815bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        break;
2825bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    case SF_FORMAT_PCM_32:
2835bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        if (transferFormat == AUDIO_FORMAT_DEFAULT) {
2845bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            transferFormat = AUDIO_FORMAT_PCM_32_BIT;
2855bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        }
2865bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        break;
2875bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    case SF_FORMAT_PCM_16:
2885bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        if (transferFormat == AUDIO_FORMAT_DEFAULT) {
2895bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            transferFormat = AUDIO_FORMAT_PCM_16_BIT;
2905bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        }
2915bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        break;
2925bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    case SF_FORMAT_PCM_U8:
2935bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        if (transferFormat == AUDIO_FORMAT_DEFAULT) {
2945bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            transferFormat = AUDIO_FORMAT_PCM_8_BIT;
2955bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        }
2965bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        break;
2975bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    case SF_FORMAT_PCM_24:
2985bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        if (transferFormat == AUDIO_FORMAT_DEFAULT) {
2995bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            transferFormat = AUDIO_FORMAT_PCM_24_BIT_PACKED;
3005bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        }
3015bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        break;
3025bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    default:
3035bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        fprintf(stderr, "unsupported sub-format 0x%x\n", sfinfo.format & SF_FORMAT_SUBMASK);
3045bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        goto close_sndfile;
3055bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    }
3065bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
3075bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLuint32 bitsPerSample;
3085bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    switch (transferFormat) {
3095bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    case AUDIO_FORMAT_PCM_FLOAT:
3105bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        bitsPerSample = 32;
3115bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        sfframesize = sfinfo.channels * sizeof(float);
3125bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        break;
3135bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    case AUDIO_FORMAT_PCM_32_BIT:
3145bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        bitsPerSample = 32;
3155bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        sfframesize = sfinfo.channels * sizeof(int);
3165bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        break;
3175bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    case AUDIO_FORMAT_PCM_24_BIT_PACKED:
3185bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        bitsPerSample = 24;
3195bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        sfframesize = sfinfo.channels * sizeof(int); // use int size
3205bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        break;
3215bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    case AUDIO_FORMAT_PCM_16_BIT:
3225bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        bitsPerSample = 16;
3235bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        sfframesize = sfinfo.channels * sizeof(short);
3245bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        break;
3255bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    case AUDIO_FORMAT_PCM_8_BIT:
3265bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        bitsPerSample = 8;
3275bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        sfframesize = sfinfo.channels * sizeof(short); // use short size
3285bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        break;
3295bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    default:
3305bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        fprintf(stderr, "unsupported transfer format %#x\n", transferFormat);
3315bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        goto close_sndfile;
3325bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    }
3335bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
3345bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    {
3355bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    buffers = malloc(framesPerBuffer * sfframesize * numBuffers);
3365bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
3375bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // create engine
3385bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLresult result;
3395bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLObjectItf engineObject;
3405bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
3415bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
3425bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLEngineItf engineEngine;
3435bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
3445bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
3455bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
3465bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
3475bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
3485bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // create output mix
3495bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLObjectItf outputMixObject;
3505bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};
3515bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLboolean req[1] = {SL_BOOLEAN_TRUE};
3525bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, enableReverb ? 1 : 0,
3535bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            ids, req);
3545bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
3555bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
3565bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
3575bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
3585bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // configure environmental reverb on output mix
3595bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLEnvironmentalReverbItf mixEnvironmentalReverb = NULL;
3605bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    if (enableReverb) {
3615bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB,
3625bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                &mixEnvironmentalReverb);
3635bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
3645bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        SLEnvironmentalReverbSettings settings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR;
3655bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        result = (*mixEnvironmentalReverb)->SetEnvironmentalReverbProperties(mixEnvironmentalReverb,
3665bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                &settings);
3675bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
3685bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    }
3695bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
3705bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // configure audio source
3715bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLDataLocator_BufferQueue loc_bufq;
3725bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    loc_bufq.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
3735bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    loc_bufq.numBuffers = numBuffers;
3745bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLAndroidDataFormat_PCM_EX format_pcm;
3755bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    format_pcm.formatType = transferFormat == AUDIO_FORMAT_PCM_FLOAT
3765bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            ? SL_ANDROID_DATAFORMAT_PCM_EX : SL_DATAFORMAT_PCM;
3775bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    format_pcm.numChannels = sfinfo.channels;
3785bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    format_pcm.sampleRate = sfinfo.samplerate * 1000;
3795bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    format_pcm.bitsPerSample = bitsPerSample;
3805bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    format_pcm.containerSize = format_pcm.bitsPerSample;
3815bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    format_pcm.channelMask = 1 == format_pcm.numChannels ? SL_SPEAKER_FRONT_CENTER :
3825bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
3835bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    format_pcm.endianness = byteOrder;
3845bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    format_pcm.representation = transferFormat == AUDIO_FORMAT_PCM_FLOAT
3855bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            ? SL_ANDROID_PCM_REPRESENTATION_FLOAT : transferFormat == AUDIO_FORMAT_PCM_8_BIT
3865bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                    ? SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT
3875bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                            : SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT;
3885bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLDataSource audioSrc;
3895bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    audioSrc.pLocator = &loc_bufq;
3905bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    audioSrc.pFormat = &format_pcm;
3915bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
3925bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // configure audio sink
3935bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLDataLocator_OutputMix loc_outmix;
3945bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
3955bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    loc_outmix.outputMix = outputMixObject;
3965bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLDataSink audioSnk;
3975bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    audioSnk.pLocator = &loc_outmix;
3985bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    audioSnk.pFormat = NULL;
3995bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
4005bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // create audio player
4015bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLInterfaceID ids2[3] = {SL_IID_BUFFERQUEUE, SL_IID_PLAYBACKRATE, SL_IID_EFFECTSEND};
4025bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLboolean req2[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
4035bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLObjectItf playerObject;
4045bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audioSrc,
4055bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            &audioSnk, enableReverb ? 3 : (enablePlaybackRate ? 2 : 1), ids2, req2);
4065bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    if (SL_RESULT_SUCCESS != result) {
4075bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        fprintf(stderr, "can't create audio player\n");
4085bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        goto no_player;
4095bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    }
4105bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
4115bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    {
4125bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
4135bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // realize the player
4145bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
4155bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
4165bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
4175bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // get the effect send interface and enable effect send reverb for this player
4185bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    if (enableReverb) {
4195bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        SLEffectSendItf playerEffectSend;
4205bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        result = (*playerObject)->GetInterface(playerObject, SL_IID_EFFECTSEND, &playerEffectSend);
4215bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
4225bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        result = (*playerEffectSend)->EnableEffectSend(playerEffectSend, mixEnvironmentalReverb,
4235bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                SL_BOOLEAN_TRUE, (SLmillibel) 0);
4245bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
4255bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    }
4265bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
4275bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // get the playback rate interface and configure the rate
4285bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLPlaybackRateItf playerPlaybackRate;
4295bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLpermille currentRate = 0;
4305bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    if (enablePlaybackRate) {
4315bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAYBACKRATE,
4325bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                &playerPlaybackRate);
4335bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
4345bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        SLpermille defaultRate;
4355bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        result = (*playerPlaybackRate)->GetRate(playerPlaybackRate, &defaultRate);
4365bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
4375bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        SLuint32 defaultProperties;
4385bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        result = (*playerPlaybackRate)->GetProperties(playerPlaybackRate, &defaultProperties);
4395bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
4405bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        printf("default playback rate %d per mille, properties 0x%x\n", defaultRate,
4415bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                defaultProperties);
4425bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        if (initialRate <= 0) {
4435bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            initialRate = defaultRate;
4445bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        }
4455bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        if (finalRate <= 0) {
4465bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            finalRate = initialRate;
4475bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        }
4485bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        currentRate = defaultRate;
4495bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        if (finalRate == initialRate) {
4505bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            deltaRate = 0;
4515bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        } else if (finalRate < initialRate) {
4525bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            deltaRate = -deltaRate;
4535bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        }
4545bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        if (initialRate != defaultRate) {
4555bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            result = (*playerPlaybackRate)->SetRate(playerPlaybackRate, initialRate);
4565bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            if (SL_RESULT_FEATURE_UNSUPPORTED == result) {
4575bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                fprintf(stderr, "initial playback rate %d is unsupported\n", initialRate);
4585bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                deltaRate = 0;
4595bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            } else if (SL_RESULT_PARAMETER_INVALID == result) {
4605bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                fprintf(stderr, "initial playback rate %d is invalid\n", initialRate);
4615bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                deltaRate = 0;
4625bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            } else {
4635bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                assert(SL_RESULT_SUCCESS == result);
4645bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                currentRate = initialRate;
4655bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            }
4665bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        }
4675bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    }
4685bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
4695bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // get the play interface
4705bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLPlayItf playerPlay;
4715bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay);
4725bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
4735bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
4745bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // get the buffer queue interface
4755bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLBufferQueueItf playerBufferQueue;
4765bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE,
4775bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            &playerBufferQueue);
4785bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
4795bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
4805bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // loop until EOF or no more buffers
4815bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    for (which = 0; which < numBuffers; ++which) {
4825bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        void *buffer = (char *)buffers + framesPerBuffer * sfframesize * which;
4835bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        sf_count_t frames = framesPerBuffer;
4845bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        sf_count_t count;
4855bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        switch (transferFormat) {
4865bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        case AUDIO_FORMAT_PCM_FLOAT:
4875bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            count = sf_readf_float(sndfile, (float *) buffer, frames);
4885bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            break;
4895bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        case AUDIO_FORMAT_PCM_32_BIT:
4905bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            count = sf_readf_int(sndfile, (int *) buffer, frames);
4915bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            break;
4925bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        case AUDIO_FORMAT_PCM_24_BIT_PACKED:
4935bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            count = sf_readf_int(sndfile, (int *) buffer, frames);
4945bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            break;
4955bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        case AUDIO_FORMAT_PCM_16_BIT:
4965bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        case AUDIO_FORMAT_PCM_8_BIT:
4975bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            count = sf_readf_short(sndfile, (short *) buffer, frames);
4985bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            break;
4995bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        default:
5005bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            count = 0;
5015bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            break;
5025bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        }
5035bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        if (0 >= count) {
5045bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            eof = SL_BOOLEAN_TRUE;
5055bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            break;
5065bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        }
5075bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
5085bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        // enqueue a buffer
5095bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        SLuint32 nbytes = count * sfframesize;
5105bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        nbytes = squeeze(buffer, nbytes);
5115bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, nbytes);
5125bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
5135bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    }
5145bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    if (which >= numBuffers) {
5155bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        which = 0;
5165bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    }
5175bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
5185bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // register a callback on the buffer queue
5195bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, callback, NULL);
5205bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
5215bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
5225bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#define FIFO_FRAMES 16384
5235bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    void *fifoBuffer = malloc(FIFO_FRAMES * sfframesize);
524add2a2112de08f840459de78e8f8eb16d8c888c3Glenn Kasten    fifo = new audio_utils_fifo(FIFO_FRAMES, sfframesize, fifoBuffer);
52513e4fe3294ea101738253c72a3382101918d5682Glenn Kasten    fifoReader = new audio_utils_fifo_reader(*fifo, true /*throttlesWriter*/);
52613e4fe3294ea101738253c72a3382101918d5682Glenn Kasten    fifoWriter = new audio_utils_fifo_writer(*fifo);
5275bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
5285bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // create thread to read from file
5295bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    pthread_t thread;
5305bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    int ok = pthread_create(&thread, (const pthread_attr_t *) NULL, file_reader_loop, NULL);
5315bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    assert(0 == ok);
5325bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
5335bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // give thread a head start so that the pipe is initially filled
5345bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    sleep(1);
5355bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
5365bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // set the player's state to playing
5375bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
5385bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
5395bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
5405bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // get the initial time
5415bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    struct timespec prevTs;
5425bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    clock_gettime(CLOCK_MONOTONIC, &prevTs);
5435bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    long elapsedNs = 0;
5445bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    long deltaRateNs = deltaRateMs * 1000000;
5455bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
5465bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // wait until the buffer queue is empty
5475bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    SLBufferQueueState bufqstate;
5485bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    for (;;) {
5495bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        result = (*playerBufferQueue)->GetState(playerBufferQueue, &bufqstate);
5505bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
5515bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        if (0 >= bufqstate.count) {
5525bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            break;
5535bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        }
5545bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        if (!enablePlaybackRate || deltaRate == 0) {
5555bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            sleep(1);
5565bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        } else {
5575bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            struct timespec curTs;
5585bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            clock_gettime(CLOCK_MONOTONIC, &curTs);
5595bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            elapsedNs += (curTs.tv_sec - prevTs.tv_sec) * 1000000000 +
5605bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                    // this term can be negative
5615bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                    (curTs.tv_nsec - prevTs.tv_nsec);
5625bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            prevTs = curTs;
5635bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            if (elapsedNs < deltaRateNs) {
5645bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                usleep((deltaRateNs - elapsedNs) / 1000);
5655bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                continue;
5665bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            }
5675bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            elapsedNs -= deltaRateNs;
5685bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            SLpermille nextRate = currentRate + deltaRate;
5695bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            result = (*playerPlaybackRate)->SetRate(playerPlaybackRate, nextRate);
5705bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            if (SL_RESULT_SUCCESS != result) {
5715bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                fprintf(stderr, "next playback rate %d is unsupported\n", nextRate);
5725bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            } else if (SL_RESULT_PARAMETER_INVALID == result) {
5735bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                fprintf(stderr, "next playback rate %d is invalid\n", nextRate);
5745bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            } else {
5755bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                assert(SL_RESULT_SUCCESS == result);
5765bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            }
5775bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            currentRate = nextRate;
5785bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            if (currentRate >= max(initialRate, finalRate)) {
5795bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                currentRate = max(initialRate, finalRate);
5805bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                deltaRate = -abs(deltaRate);
5815bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            } else if (currentRate <= min(initialRate, finalRate)) {
5825bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                currentRate = min(initialRate, finalRate);
5835bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten                deltaRate = abs(deltaRate);
5845bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten            }
5855bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten        }
5865bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
5875bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    }
5885bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
5895bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // wait for reader thread to exit
5905bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    ok = pthread_join(thread, (void **) NULL);
5915bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    assert(0 == ok);
5925bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
5935bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // set the player's state to stopped
5945bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_STOPPED);
5955bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
5965bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
5975bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // destroy audio player
5985bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    (*playerObject)->Destroy(playerObject);
5995bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
60013e4fe3294ea101738253c72a3382101918d5682Glenn Kasten    delete fifoWriter;
60113e4fe3294ea101738253c72a3382101918d5682Glenn Kasten    fifoWriter = NULL;
60213e4fe3294ea101738253c72a3382101918d5682Glenn Kasten    delete fifoReader;
60313e4fe3294ea101738253c72a3382101918d5682Glenn Kasten    fifoReader = NULL;
604add2a2112de08f840459de78e8f8eb16d8c888c3Glenn Kasten    delete fifo;
605add2a2112de08f840459de78e8f8eb16d8c888c3Glenn Kasten    fifo = NULL;
6065bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    free(fifoBuffer);
607add2a2112de08f840459de78e8f8eb16d8c888c3Glenn Kasten    fifoBuffer = NULL;
6085bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
6095bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    }
6105bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
6115bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastenno_player:
6125bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
6135bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // destroy output mix
6145bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    (*outputMixObject)->Destroy(outputMixObject);
6155bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
6165bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    // destroy engine
6175bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    (*engineObject)->Destroy(engineObject);
6185bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
6195bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    }
6205bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
6215bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastenclose_sndfile:
6225bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
6235bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    (void) sf_close(sndfile);
6245bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten
6255bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten    return EXIT_SUCCESS;
6265bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten}
627