playbq.c revision 208a2dae4b1bc98de4282f08c5b5acad0d797eb0
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>
21ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten#include <pthread.h>
220a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <stdio.h>
230a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <stdlib.h>
240a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <string.h>
25701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten#include <time.h>
260a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <unistd.h>
270a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
28c6853892c94800e72c0bd676d5d2136d48cea76eGlenn Kasten#include <SLES/OpenSLES.h>
29e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung#include <SLES/OpenSLES_Android.h>
30208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten#include <system/audio.h>
31208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten#include <audio_utils/fifo.h>
3256847632bc2fd39a8fff68fa1e883f06310c876aGlenn Kasten#include <audio_utils/sndfile.h>
33ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
34701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten#define max(a, b) ((a) > (b) ? (a) : (b))
35701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten#define min(a, b) ((a) < (b) ? (a) : (b))
36701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten
370a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenunsigned numBuffers = 2;
380a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenint framesPerBuffer = 512;
390a058cc3d720cdf3f0f8222472a862258482f34fGlenn KastenSNDFILE *sndfile;
400a058cc3d720cdf3f0f8222472a862258482f34fGlenn KastenSF_INFO sfinfo;
410a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenunsigned which; // which buffer to use next
420a058cc3d720cdf3f0f8222472a862258482f34fGlenn KastenSLboolean eof;  // whether we have hit EOF on input yet
43c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hungvoid *buffers;
44ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn KastenSLuint32 byteOrder; // desired to use for PCM buffers
45ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn KastenSLuint32 nativeByteOrder;   // of platform
46c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hungaudio_format_t transferFormat = AUDIO_FORMAT_PCM_16_BIT;
47c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hungsize_t sfframesize = 0;
48ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten
49ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten// swap adjacent bytes; this would normally be in <unistd.h> but is missing here
50ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kastenstatic void swab(const void *from, void *to, ssize_t n)
51ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten{
52ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    // from and to as char pointers
53ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    const char *from_ch = (const char *) from;
54ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    char *to_ch = (char *) to;
55ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    // note that we don't swap the last odd byte
56ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    while (n >= 2) {
57ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        to_ch[0] = from_ch[1];
58ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        to_ch[1] = from_ch[0];
59ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        to_ch += 2;
60ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        from_ch += 2;
61ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        n -= 2;
62ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    }
63ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten}
64ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten
65ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten// squeeze 16-bit signed PCM samples down to 8-bit unsigned PCM samples by truncation; no dithering
66ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kastenstatic void squeeze(const short *from, unsigned char *to, ssize_t n)
67ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten{
68ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    // note that we don't squeeze the last odd byte
69ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    while (n >= 2) {
70ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        *to++ = (*from++ + 32768) >> 8;
71ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        n -= 2;
72ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    }
73ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten}
740a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
75c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung// squeeze 32-bit signed PCM samples down to 24-bit unsigned PCM samples by truncation
76c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hungstatic void squeeze24(const unsigned char *from, unsigned char *to, ssize_t n)
77c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung{
78c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung    // note that we don't squeeze the last odd bytes
79c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung    while (n >= 3) {
80c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        ++from;
81c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        *to++ = *from++;
82c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        *to++ = *from++;
83c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        *to++ = *from++;
84c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        n -= 4;
85c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung    }
86c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung}
87c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung
88208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kastenstatic audio_utils_fifo fifo;
89ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kastenstatic unsigned underruns = 0;
90ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
910a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten// This callback is called each time a buffer finishes playing
920a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
930a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenstatic void callback(SLBufferQueueItf bufq, void *param)
940a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten{
959a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    assert(NULL == param);
960a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    if (!eof) {
97c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        void *buffer = (char *)buffers + framesPerBuffer * sfframesize * which;
98208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten        ssize_t count = audio_utils_fifo_read(&fifo, buffer, framesPerBuffer);
99ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten        // on underrun from pipe, substitute silence
1000a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        if (0 >= count) {
101c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            memset(buffer, 0, framesPerBuffer * sfframesize);
102ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            count = framesPerBuffer;
103ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            ++underruns;
104ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten        }
105ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten        if (count > 0) {
106c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            SLuint32 nbytes = count * sfframesize;
107ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            if (byteOrder != nativeByteOrder) {
108ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten                swab(buffer, buffer, nbytes);
109ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            }
110c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            if (transferFormat == AUDIO_FORMAT_PCM_8_BIT) {
111c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung                squeeze((short *) buffer, (unsigned char *) buffer, nbytes);
112ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten                nbytes /= 2;
113c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            } else if (transferFormat == AUDIO_FORMAT_PCM_24_BIT_PACKED) {
114c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung                squeeze24((unsigned char *) buffer, (unsigned char *) buffer, nbytes);
115c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung                nbytes = nbytes * 3 / 4;
116ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            }
117ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            SLresult result = (*bufq)->Enqueue(bufq, buffer, nbytes);
1180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            assert(SL_RESULT_SUCCESS == result);
1190a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            if (++which >= numBuffers)
1200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten                which = 0;
1210a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        }
1220a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
1230a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten}
1240a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
125ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten// This thread reads from a (slow) filesystem with unpredictable latency and writes to pipe
126ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
127c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hungstatic void *file_reader_loop(void *arg __unused)
128ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten{
129ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten#define READ_FRAMES 256
130c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung    void *temp = malloc(READ_FRAMES * sfframesize);
131ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    sf_count_t total = 0;
132c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung    sf_count_t count;
133ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    for (;;) {
134c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        switch (transferFormat) {
135c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        case AUDIO_FORMAT_PCM_FLOAT:
136c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            count = sf_readf_float(sndfile, (float *) temp, READ_FRAMES);
137c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            break;
138c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        case AUDIO_FORMAT_PCM_32_BIT:
139c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        case AUDIO_FORMAT_PCM_24_BIT_PACKED:
140c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            count = sf_readf_int(sndfile, (int *) temp, READ_FRAMES);
141c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            break;
142c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        case AUDIO_FORMAT_PCM_16_BIT:
143c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        case AUDIO_FORMAT_PCM_8_BIT:
144c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            count = sf_readf_short(sndfile, (short *) temp, READ_FRAMES);
145c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            break;
146c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        default:
147c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            count = 0;
148c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            break;
149c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        }
150ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten        if (0 >= count) {
151ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            eof = SL_BOOLEAN_TRUE;
152ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            break;
153ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten        }
154c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        const unsigned char *ptr = (unsigned char *) temp;
155ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten        while (count > 0) {
156208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten            ssize_t actual = audio_utils_fifo_write(&fifo, ptr, (size_t) count);
157ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            if (actual < 0) {
158ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten                break;
159ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            }
160ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            if ((sf_count_t) actual < count) {
161ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten                usleep(10000);
162ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            }
163c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            ptr += actual * sfframesize;
164ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            count -= actual;
165ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            total += actual;
166ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten        }
167ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten        // simulate occasional filesystem latency
168ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten        if ((total & 0xFF00) == 0xFF00) {
169ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            usleep(100000);
170ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten        }
171ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    }
172ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    free(temp);
173ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    return NULL;
174ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten}
175ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
176ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten// Main program
177ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
1780a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenint main(int argc, char **argv)
1790a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten{
180ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    // Determine the native byte order (SL_BYTEORDER_NATIVE not available until 1.1)
181ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    union {
182ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        short s;
183ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        char c[2];
184ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    } u;
185ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    u.s = 0x1234;
186ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    if (u.c[0] == 0x34) {
187ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        nativeByteOrder = SL_BYTEORDER_LITTLEENDIAN;
188ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    } else if (u.c[0] == 0x12) {
189ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        nativeByteOrder = SL_BYTEORDER_BIGENDIAN;
190ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    } else {
191ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        fprintf(stderr, "Unable to determine native byte order\n");
192ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        return EXIT_FAILURE;
193ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    }
194ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    byteOrder = nativeByteOrder;
195ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten
1960a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLboolean enableReverb = SL_BOOLEAN_FALSE;
197f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten    SLboolean enablePlaybackRate = SL_BOOLEAN_FALSE;
198701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    SLpermille initialRate = 0;
199701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    SLpermille finalRate = 0;
200701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    SLpermille deltaRate = 1;
201701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    SLmillisecond deltaRateMs = 0;
2020a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2030a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // process command-line options
2040a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    int i;
2050a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    for (i = 1; i < argc; ++i) {
2060a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        char *arg = argv[i];
207701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        if (arg[0] != '-') {
2080a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            break;
209701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        }
210ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        if (!strcmp(arg, "-b")) {
211ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            byteOrder = SL_BYTEORDER_BIGENDIAN;
212ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        } else if (!strcmp(arg, "-l")) {
213ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            byteOrder = SL_BYTEORDER_LITTLEENDIAN;
214ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        } else if (!strcmp(arg, "-8")) {
215c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            transferFormat = AUDIO_FORMAT_PCM_8_BIT;
216c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        } else if (!strcmp(arg, "-24")) {
217c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            transferFormat = AUDIO_FORMAT_PCM_24_BIT_PACKED;
218c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        } else if (!strcmp(arg, "-32")) {
219c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            transferFormat = AUDIO_FORMAT_PCM_32_BIT;
220e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung        } else if (!strcmp(arg, "-32f")) {
221e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung            transferFormat = AUDIO_FORMAT_PCM_FLOAT;
222ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        } else if (!strncmp(arg, "-f", 2)) {
2230a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            framesPerBuffer = atoi(&arg[2]);
2240a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        } else if (!strncmp(arg, "-n", 2)) {
2250a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            numBuffers = atoi(&arg[2]);
2269a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten        } else if (!strncmp(arg, "-p", 2)) {
227701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            initialRate = atoi(&arg[2]);
228f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            enablePlaybackRate = SL_BOOLEAN_TRUE;
229701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        } else if (!strncmp(arg, "-P", 2)) {
230701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            finalRate = atoi(&arg[2]);
231f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            enablePlaybackRate = SL_BOOLEAN_TRUE;
232701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        } else if (!strncmp(arg, "-q", 2)) {
233701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            deltaRate = atoi(&arg[2]);
234701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            // deltaRate is a magnitude, so take absolute value
235701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            if (deltaRate < 0) {
236701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten                deltaRate = -deltaRate;
237701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            }
238f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            enablePlaybackRate = SL_BOOLEAN_TRUE;
239701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        } else if (!strncmp(arg, "-Q", 2)) {
240701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            deltaRateMs = atoi(&arg[2]);
241f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            enablePlaybackRate = SL_BOOLEAN_TRUE;
2420a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        } else if (!strcmp(arg, "-r")) {
2430a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            enableReverb = SL_BOOLEAN_TRUE;
2440a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        } else {
2450a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            fprintf(stderr, "option %s ignored\n", arg);
2460a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        }
2470a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
2480a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2490a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    if (argc - i != 1) {
250e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung        fprintf(stderr, "usage: [-b/l] [-8 | -24 | -32 | -32f] [-f#] [-n#] [-p#] [-r]"
251c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung                " %s filename\n", argv[0]);
252701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        fprintf(stderr, "    -b  force big-endian byte order (default is native byte order)\n");
253701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        fprintf(stderr, "    -l  force little-endian byte order (default is native byte order)\n");
254701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        fprintf(stderr, "    -8  output 8-bits per sample (default is 16-bits per sample)\n");
255c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        fprintf(stderr, "    -24 output 24-bits per sample\n");
256c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        fprintf(stderr, "    -32 output 32-bits per sample\n");
257e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung        fprintf(stderr, "    -32f output float 32-bits per sample\n");
258701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        fprintf(stderr, "    -f# frames per buffer (default 512)\n");
259701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        fprintf(stderr, "    -n# number of buffers (default 2)\n");
260701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        fprintf(stderr, "    -p# initial playback rate in per mille (default 1000)\n");
261701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        fprintf(stderr, "    -P# final playback rate in per mille (default same as -p#)\n");
262701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        fprintf(stderr, "    -q# magnitude of playback rate changes in per mille (default 1)\n");
263701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        fprintf(stderr, "    -Q# period between playback rate changes in ms (default 50)\n");
264701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        fprintf(stderr, "    -r  enable reverb (default disabled)\n");
2650a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        return EXIT_FAILURE;
2660a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
2670a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2680a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    const char *filename = argv[i];
2690a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    //memset(&sfinfo, 0, sizeof(SF_INFO));
2700a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    sfinfo.format = 0;
2710a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    sndfile = sf_open(filename, SFM_READ, &sfinfo);
2720a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    if (NULL == sndfile) {
2730a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        perror(filename);
2740a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        return EXIT_FAILURE;
2750a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
2760a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2770a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // verify the file format
2780a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    switch (sfinfo.channels) {
2790a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 1:
2800a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 2:
2810a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        break;
2820a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    default:
2830a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        fprintf(stderr, "unsupported channel count %d\n", sfinfo.channels);
284701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        goto close_sndfile;
2850a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
286701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten
2870a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    switch (sfinfo.samplerate) {
2880a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case  8000:
2890a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 11025:
2900a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 12000:
2910a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 16000:
2920a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 22050:
2930a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 24000:
2940a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 32000:
2950a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 44100:
2960a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 48000:
2970a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        break;
2980a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    default:
2990a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        fprintf(stderr, "unsupported sample rate %d\n", sfinfo.samplerate);
300701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        goto close_sndfile;
3010a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
302701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten
3030a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    switch (sfinfo.format & SF_FORMAT_TYPEMASK) {
3040a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case SF_FORMAT_WAV:
3050a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        break;
3060a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    default:
3070a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        fprintf(stderr, "unsupported format type 0x%x\n", sfinfo.format & SF_FORMAT_TYPEMASK);
308701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        goto close_sndfile;
3090a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
310701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten
3110a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    switch (sfinfo.format & SF_FORMAT_SUBMASK) {
312c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung    case SF_FORMAT_FLOAT:
313c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung    case SF_FORMAT_PCM_32:
3140a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case SF_FORMAT_PCM_16:
3150a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case SF_FORMAT_PCM_U8:
3160a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        break;
3170a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    default:
3180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        fprintf(stderr, "unsupported sub-format 0x%x\n", sfinfo.format & SF_FORMAT_SUBMASK);
319701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        goto close_sndfile;
3200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
3210a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
322c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung    SLuint32 bitsPerSample;
323c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung    switch (transferFormat) {
324c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung    case AUDIO_FORMAT_PCM_FLOAT:
325c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        bitsPerSample = 32;
326c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        sfframesize = sfinfo.channels * sizeof(float);
327c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        break;
328c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung    case AUDIO_FORMAT_PCM_32_BIT:
329c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        bitsPerSample = 32;
330c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        sfframesize = sfinfo.channels * sizeof(int);
331c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        break;
332c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung    case AUDIO_FORMAT_PCM_24_BIT_PACKED:
333c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        bitsPerSample = 24;
334c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        sfframesize = sfinfo.channels * sizeof(int); // use int size
335c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        break;
336c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung    case AUDIO_FORMAT_PCM_16_BIT:
337c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        bitsPerSample = 16;
338c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        sfframesize = sfinfo.channels * sizeof(short);
339c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        break;
340c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung    case AUDIO_FORMAT_PCM_8_BIT:
341c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        bitsPerSample = 8;
342c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        sfframesize = sfinfo.channels * sizeof(short); // use short size
343c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        break;
344c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung    default:
345c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        fprintf(stderr, "unsupported transfer format %#x\n", transferFormat);
346c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        goto close_sndfile;
347c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung    }
348ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
349c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung    {
350c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung    buffers = malloc(framesPerBuffer * sfframesize * numBuffers);
3510a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
3520a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // create engine
3530a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLresult result;
3540a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLObjectItf engineObject;
3550a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
3560a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
3570a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLEngineItf engineEngine;
3580a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
3590a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
3600a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
3610a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
3620a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
3630a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // create output mix
3640a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLObjectItf outputMixObject;
3650a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};
3660a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLboolean req[1] = {SL_BOOLEAN_TRUE};
3670a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, enableReverb ? 1 : 0,
3680a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            ids, req);
3690a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
3700a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
3710a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
3720a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
3730a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // configure environmental reverb on output mix
3740a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLEnvironmentalReverbItf mixEnvironmentalReverb = NULL;
3750a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    if (enableReverb) {
3760a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB,
3770a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten                &mixEnvironmentalReverb);
3780a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
3790a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        SLEnvironmentalReverbSettings settings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR;
3800a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        result = (*mixEnvironmentalReverb)->SetEnvironmentalReverbProperties(mixEnvironmentalReverb,
3810a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten                &settings);
3820a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
3830a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
3840a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
3850a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // configure audio source
3860a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLDataLocator_BufferQueue loc_bufq;
3870a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    loc_bufq.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
3880a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    loc_bufq.numBuffers = numBuffers;
389e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung    SLAndroidDataFormat_PCM_EX format_pcm;
390e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung    format_pcm.formatType = transferFormat == AUDIO_FORMAT_PCM_FLOAT
391e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung            ? SL_ANDROID_DATAFORMAT_PCM_EX : SL_DATAFORMAT_PCM;
3920a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    format_pcm.numChannels = sfinfo.channels;
393e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung    format_pcm.sampleRate = sfinfo.samplerate * 1000;
394ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    format_pcm.bitsPerSample = bitsPerSample;
3950a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    format_pcm.containerSize = format_pcm.bitsPerSample;
3960a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    format_pcm.channelMask = 1 == format_pcm.numChannels ? SL_SPEAKER_FRONT_CENTER :
3970a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
398ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    format_pcm.endianness = byteOrder;
399e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung    format_pcm.representation = transferFormat == AUDIO_FORMAT_PCM_FLOAT
400e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung            ? SL_ANDROID_PCM_REPRESENTATION_FLOAT : transferFormat == AUDIO_FORMAT_PCM_8_BIT
401e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung                    ? SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT
402e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung                            : SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT;
4030a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLDataSource audioSrc;
4040a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    audioSrc.pLocator = &loc_bufq;
4050a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    audioSrc.pFormat = &format_pcm;
4060a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
4070a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // configure audio sink
4080a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLDataLocator_OutputMix loc_outmix;
4090a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
4100a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    loc_outmix.outputMix = outputMixObject;
4110a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLDataSink audioSnk;
4120a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    audioSnk.pLocator = &loc_outmix;
4130a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    audioSnk.pFormat = NULL;
4140a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
4150a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // create audio player
4169a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    SLInterfaceID ids2[3] = {SL_IID_BUFFERQUEUE, SL_IID_PLAYBACKRATE, SL_IID_EFFECTSEND};
4179a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    SLboolean req2[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
4180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLObjectItf playerObject;
4190a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audioSrc,
420f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            &audioSnk, enableReverb ? 3 : (enablePlaybackRate ? 2 : 1), ids2, req2);
421701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    if (SL_RESULT_SUCCESS != result) {
422701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        fprintf(stderr, "can't create audio player\n");
423701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        goto no_player;
424701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    }
4250a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
426ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    {
427ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
4280a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // realize the player
4290a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
4300a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
4310a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
4320a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // get the effect send interface and enable effect send reverb for this player
4330a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    if (enableReverb) {
4340a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        SLEffectSendItf playerEffectSend;
4350a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        result = (*playerObject)->GetInterface(playerObject, SL_IID_EFFECTSEND, &playerEffectSend);
4360a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
4370a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        result = (*playerEffectSend)->EnableEffectSend(playerEffectSend, mixEnvironmentalReverb,
4380a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten                SL_BOOLEAN_TRUE, (SLmillibel) 0);
4390a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
4400a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
4410a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
4429a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    // get the playback rate interface and configure the rate
4439a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    SLPlaybackRateItf playerPlaybackRate;
4443eaa329775fc522d8ea4acd4edc379eabf9ac332Glenn Kasten    SLpermille currentRate = 0;
445f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten    if (enablePlaybackRate) {
446f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAYBACKRATE,
447f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten                &playerPlaybackRate);
448f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
449f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        SLpermille defaultRate;
450f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        result = (*playerPlaybackRate)->GetRate(playerPlaybackRate, &defaultRate);
451f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
452f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        SLuint32 defaultProperties;
453f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        result = (*playerPlaybackRate)->GetProperties(playerPlaybackRate, &defaultProperties);
454f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
455f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        printf("default playback rate %d per mille, properties 0x%x\n", defaultRate,
456f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten                defaultProperties);
457f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        if (initialRate <= 0) {
458f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            initialRate = defaultRate;
459f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        }
460f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        if (finalRate <= 0) {
461f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            finalRate = initialRate;
462f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        }
463f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        currentRate = defaultRate;
464f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        if (finalRate == initialRate) {
465701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            deltaRate = 0;
466f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        } else if (finalRate < initialRate) {
467f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            deltaRate = -deltaRate;
468f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        }
469f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        if (initialRate != defaultRate) {
470f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            result = (*playerPlaybackRate)->SetRate(playerPlaybackRate, initialRate);
471f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            if (SL_RESULT_FEATURE_UNSUPPORTED == result) {
472f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten                fprintf(stderr, "initial playback rate %d is unsupported\n", initialRate);
473f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten                deltaRate = 0;
474f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            } else if (SL_RESULT_PARAMETER_INVALID == result) {
475f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten                fprintf(stderr, "initial playback rate %d is invalid\n", initialRate);
476f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten                deltaRate = 0;
477f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            } else {
478f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten                assert(SL_RESULT_SUCCESS == result);
479f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten                currentRate = initialRate;
480f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            }
4819a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten        }
4829a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    }
4839a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten
4840a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // get the play interface
4850a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLPlayItf playerPlay;
4860a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay);
4870a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
4880a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
4890a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // get the buffer queue interface
4900a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLBufferQueueItf playerBufferQueue;
4910a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE,
4920a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            &playerBufferQueue);
4930a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
4940a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
4950a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // loop until EOF or no more buffers
4960a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    for (which = 0; which < numBuffers; ++which) {
497c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        void *buffer = (char *)buffers + framesPerBuffer * sfframesize * which;
4980a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        sf_count_t frames = framesPerBuffer;
4990a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        sf_count_t count;
500c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        switch (transferFormat) {
501c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        case AUDIO_FORMAT_PCM_FLOAT:
502c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            count = sf_readf_float(sndfile, (float *) buffer, frames);
503c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            break;
504c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        case AUDIO_FORMAT_PCM_32_BIT:
505c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            count = sf_readf_int(sndfile, (int *) buffer, frames);
506c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            break;
507c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        case AUDIO_FORMAT_PCM_24_BIT_PACKED:
508c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            count = sf_readf_int(sndfile, (int *) buffer, frames);
509c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            break;
510c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        case AUDIO_FORMAT_PCM_16_BIT:
511c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        case AUDIO_FORMAT_PCM_8_BIT:
512c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            count = sf_readf_short(sndfile, (short *) buffer, frames);
513c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            break;
514c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        default:
515c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            count = 0;
516c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            break;
517c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        }
5180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        if (0 >= count) {
5190a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            eof = SL_BOOLEAN_TRUE;
5200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            break;
5210a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        }
5220a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
5230a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        // enqueue a buffer
524c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        SLuint32 nbytes = count * sfframesize;
525ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        if (byteOrder != nativeByteOrder) {
526ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            swab(buffer, buffer, nbytes);
527ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        }
528c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        if (transferFormat == AUDIO_FORMAT_PCM_8_BIT) {
529c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            squeeze((short *) buffer, (unsigned char *) buffer, nbytes);
530ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            nbytes /= 2;
531c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung        } else if (transferFormat == AUDIO_FORMAT_PCM_24_BIT_PACKED) {
532c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            squeeze24((unsigned char *) buffer, (unsigned char *) buffer, nbytes);
533c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung            nbytes = nbytes * 3 / 4;
534ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        }
535ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, nbytes);
5360a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
5370a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
538701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    if (which >= numBuffers) {
5390a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        which = 0;
540701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    }
5410a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
5420a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // register a callback on the buffer queue
5430a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, callback, NULL);
5440a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
5450a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
546208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten    size_t frameSize = sfinfo.channels * audio_bytes_per_sample(transferFormat);
547208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten#define FIFO_FRAMES 16384
548208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten    void *fifoBuffer = malloc(FIFO_FRAMES * frameSize);
549208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten    audio_utils_fifo_init(&fifo, FIFO_FRAMES, frameSize, fifoBuffer);
550ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
551ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    // create thread to read from file
552ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    pthread_t thread;
553ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    int ok = pthread_create(&thread, (const pthread_attr_t *) NULL, file_reader_loop, NULL);
554ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    assert(0 == ok);
555ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
556ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    // give thread a head start so that the pipe is initially filled
557ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    sleep(1);
558ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
5590a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // set the player's state to playing
5600a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
5610a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
5620a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
563701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    // get the initial time
564701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    struct timespec prevTs;
565701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    clock_gettime(CLOCK_MONOTONIC, &prevTs);
566701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    long elapsedNs = 0;
567701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    long deltaRateNs = deltaRateMs * 1000000;
568701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten
5690a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // wait until the buffer queue is empty
5700a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLBufferQueueState bufqstate;
5710a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    for (;;) {
5720a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        result = (*playerBufferQueue)->GetState(playerBufferQueue, &bufqstate);
5730a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
5740a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        if (0 >= bufqstate.count) {
5750a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            break;
5760a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        }
577f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        if (!enablePlaybackRate || deltaRate == 0) {
578701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            sleep(1);
579701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        } else {
580701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            struct timespec curTs;
581701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            clock_gettime(CLOCK_MONOTONIC, &curTs);
582701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            elapsedNs += (curTs.tv_sec - prevTs.tv_sec) * 1000000000 +
583701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten                    // this term can be negative
584701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten                    (curTs.tv_nsec - prevTs.tv_nsec);
585701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            prevTs = curTs;
586701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            if (elapsedNs < deltaRateNs) {
587701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten                usleep((deltaRateNs - elapsedNs) / 1000);
588701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten                continue;
589701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            }
590701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            elapsedNs -= deltaRateNs;
591701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            SLpermille nextRate = currentRate + deltaRate;
592701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            result = (*playerPlaybackRate)->SetRate(playerPlaybackRate, nextRate);
593701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            if (SL_RESULT_SUCCESS != result) {
594701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten                fprintf(stderr, "next playback rate %d is unsupported\n", nextRate);
595701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            } else if (SL_RESULT_PARAMETER_INVALID == result) {
596701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten                fprintf(stderr, "next playback rate %d is invalid\n", nextRate);
597701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            } else {
598701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten                assert(SL_RESULT_SUCCESS == result);
599701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            }
600701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            currentRate = nextRate;
601701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            if (currentRate >= max(initialRate, finalRate)) {
602701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten                currentRate = max(initialRate, finalRate);
603701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten                deltaRate = -abs(deltaRate);
604701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            } else if (currentRate <= min(initialRate, finalRate)) {
605701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten                currentRate = min(initialRate, finalRate);
606701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten                deltaRate = abs(deltaRate);
607701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            }
608701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        }
609208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten
6100a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
6110a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
612208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten    // wait for reader thread to exit
613208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten    ok = pthread_join(thread, (void **) NULL);
614208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten    assert(0 == ok);
615208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten
616208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten    // set the player's state to stopped
617208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten    result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_STOPPED);
618208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten    assert(SL_RESULT_SUCCESS == result);
619208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten
6200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // destroy audio player
6210a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    (*playerObject)->Destroy(playerObject);
6220a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
623208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten    audio_utils_fifo_deinit(&fifo);
624208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten    free(fifoBuffer);
625208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten
626ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    }
627ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
628701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kastenno_player:
629701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten
6300a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // destroy output mix
6310a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    (*outputMixObject)->Destroy(outputMixObject);
6320a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
6330a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // destroy engine
6340a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    (*engineObject)->Destroy(engineObject);
6350a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
636ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    }
637ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
638701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kastenclose_sndfile:
639701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten
640701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    (void) sf_close(sndfile);
641701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten
6420a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    return EXIT_SUCCESS;
6430a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten}
644