playbq.c revision ad6c970f500cf99dd1eb23b9f5b2360948db90e7
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>
290a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#ifdef ANDROID
3056847632bc2fd39a8fff68fa1e883f06310c876aGlenn Kasten#include <audio_utils/sndfile.h>
310a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#else
320a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <sndfile.h>
330a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#endif
340a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
35ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten#include <media/nbaio/MonoPipe.h>
36ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten#include <media/nbaio/MonoPipeReader.h>
37ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
38701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten#define max(a, b) ((a) > (b) ? (a) : (b))
39701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten#define min(a, b) ((a) < (b) ? (a) : (b))
40701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten
410a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenunsigned numBuffers = 2;
420a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenint framesPerBuffer = 512;
430a058cc3d720cdf3f0f8222472a862258482f34fGlenn KastenSNDFILE *sndfile;
440a058cc3d720cdf3f0f8222472a862258482f34fGlenn KastenSF_INFO sfinfo;
450a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenunsigned which; // which buffer to use next
460a058cc3d720cdf3f0f8222472a862258482f34fGlenn KastenSLboolean eof;  // whether we have hit EOF on input yet
470a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenshort *buffers;
48ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn KastenSLuint32 byteOrder; // desired to use for PCM buffers
49ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn KastenSLuint32 nativeByteOrder;   // of platform
50ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn KastenSLuint32 bitsPerSample = 16;
51ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten
52ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten// swap adjacent bytes; this would normally be in <unistd.h> but is missing here
53ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kastenstatic void swab(const void *from, void *to, ssize_t n)
54ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten{
55ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    // from and to as char pointers
56ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    const char *from_ch = (const char *) from;
57ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    char *to_ch = (char *) to;
58ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    // note that we don't swap the last odd byte
59ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    while (n >= 2) {
60ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        to_ch[0] = from_ch[1];
61ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        to_ch[1] = from_ch[0];
62ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        to_ch += 2;
63ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        from_ch += 2;
64ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        n -= 2;
65ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    }
66ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten}
67ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten
68ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten// squeeze 16-bit signed PCM samples down to 8-bit unsigned PCM samples by truncation; no dithering
69ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kastenstatic void squeeze(const short *from, unsigned char *to, ssize_t n)
70ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten{
71ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    // note that we don't squeeze the last odd byte
72ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    while (n >= 2) {
73ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        *to++ = (*from++ + 32768) >> 8;
74ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        n -= 2;
75ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    }
76ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten}
770a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
78ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kastenstatic android::MonoPipeReader *pipeReader;
79ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kastenstatic android::MonoPipe *pipeWriter;
80ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kastenstatic unsigned underruns = 0;
81ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
820a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten// This callback is called each time a buffer finishes playing
830a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
840a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenstatic void callback(SLBufferQueueItf bufq, void *param)
850a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten{
869a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    assert(NULL == param);
870a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    if (!eof) {
880a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        short *buffer = &buffers[framesPerBuffer * sfinfo.channels * which];
89ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten        ssize_t count = pipeReader->read(buffer, framesPerBuffer, (int64_t) -1);
90ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten        // on underrun from pipe, substitute silence
910a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        if (0 >= count) {
92ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            memset(buffer, 0, framesPerBuffer * sfinfo.channels * sizeof(short));
93ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            count = framesPerBuffer;
94ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            ++underruns;
95ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten        }
96ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten        if (count > 0) {
97ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            SLuint32 nbytes = count * sfinfo.channels * sizeof(short);
98ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            if (byteOrder != nativeByteOrder) {
99ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten                swab(buffer, buffer, nbytes);
100ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            }
101ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            if (bitsPerSample == 8) {
102ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten                squeeze(buffer, (unsigned char *) buffer, nbytes);
103ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten                nbytes /= 2;
104ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            }
105ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            SLresult result = (*bufq)->Enqueue(bufq, buffer, nbytes);
1060a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            assert(SL_RESULT_SUCCESS == result);
1070a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            if (++which >= numBuffers)
1080a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten                which = 0;
1090a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        }
1100a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
1110a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten}
1120a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
113ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten// This thread reads from a (slow) filesystem with unpredictable latency and writes to pipe
114ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
115ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kastenstatic void *file_reader_loop(void *arg)
116ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten{
117ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten#define READ_FRAMES 256
118ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    short *temp = (short *) malloc(READ_FRAMES * sfinfo.channels * sizeof(short));
119ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    sf_count_t total = 0;
120ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    for (;;) {
121ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten        sf_count_t count = sf_readf_short(sndfile, temp, (sf_count_t) READ_FRAMES);
122ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten        if (0 >= count) {
123ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            eof = SL_BOOLEAN_TRUE;
124ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            break;
125ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten        }
126ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten        const short *ptr = temp;
127ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten        while (count > 0) {
128ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            ssize_t actual = pipeWriter->write(ptr, (size_t) count);
129ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            if (actual < 0) {
130ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten                break;
131ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            }
132ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            if ((sf_count_t) actual < count) {
133ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten                usleep(10000);
134ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            }
135ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            ptr += actual * sfinfo.channels;
136ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            count -= actual;
137ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            total += actual;
138ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten        }
139ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten        // simulate occasional filesystem latency
140ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten        if ((total & 0xFF00) == 0xFF00) {
141ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten            usleep(100000);
142ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten        }
143ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    }
144ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    free(temp);
145ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    return NULL;
146ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten}
147ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
148ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten// Main program
149ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
1500a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenint main(int argc, char **argv)
1510a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten{
152ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    // Determine the native byte order (SL_BYTEORDER_NATIVE not available until 1.1)
153ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    union {
154ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        short s;
155ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        char c[2];
156ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    } u;
157ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    u.s = 0x1234;
158ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    if (u.c[0] == 0x34) {
159ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        nativeByteOrder = SL_BYTEORDER_LITTLEENDIAN;
160ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    } else if (u.c[0] == 0x12) {
161ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        nativeByteOrder = SL_BYTEORDER_BIGENDIAN;
162ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    } else {
163ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        fprintf(stderr, "Unable to determine native byte order\n");
164ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        return EXIT_FAILURE;
165ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    }
166ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    byteOrder = nativeByteOrder;
167ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten
1680a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLboolean enableReverb = SL_BOOLEAN_FALSE;
169f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten    SLboolean enablePlaybackRate = SL_BOOLEAN_FALSE;
170701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    SLpermille initialRate = 0;
171701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    SLpermille finalRate = 0;
172701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    SLpermille deltaRate = 1;
173701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    SLmillisecond deltaRateMs = 0;
1740a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
1750a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // process command-line options
1760a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    int i;
1770a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    for (i = 1; i < argc; ++i) {
1780a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        char *arg = argv[i];
179701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        if (arg[0] != '-') {
1800a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            break;
181701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        }
182ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        if (!strcmp(arg, "-b")) {
183ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            byteOrder = SL_BYTEORDER_BIGENDIAN;
184ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        } else if (!strcmp(arg, "-l")) {
185ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            byteOrder = SL_BYTEORDER_LITTLEENDIAN;
186ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        } else if (!strcmp(arg, "-8")) {
187ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            bitsPerSample = 8;
188ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        } else if (!strncmp(arg, "-f", 2)) {
1890a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            framesPerBuffer = atoi(&arg[2]);
1900a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        } else if (!strncmp(arg, "-n", 2)) {
1910a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            numBuffers = atoi(&arg[2]);
1929a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten        } else if (!strncmp(arg, "-p", 2)) {
193701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            initialRate = atoi(&arg[2]);
194f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            enablePlaybackRate = SL_BOOLEAN_TRUE;
195701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        } else if (!strncmp(arg, "-P", 2)) {
196701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            finalRate = atoi(&arg[2]);
197f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            enablePlaybackRate = SL_BOOLEAN_TRUE;
198701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        } else if (!strncmp(arg, "-q", 2)) {
199701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            deltaRate = atoi(&arg[2]);
200701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            // deltaRate is a magnitude, so take absolute value
201701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            if (deltaRate < 0) {
202701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten                deltaRate = -deltaRate;
203701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            }
204f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            enablePlaybackRate = SL_BOOLEAN_TRUE;
205701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        } else if (!strncmp(arg, "-Q", 2)) {
206701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            deltaRateMs = atoi(&arg[2]);
207f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            enablePlaybackRate = SL_BOOLEAN_TRUE;
2080a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        } else if (!strcmp(arg, "-r")) {
2090a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            enableReverb = SL_BOOLEAN_TRUE;
2100a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        } else {
2110a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            fprintf(stderr, "option %s ignored\n", arg);
2120a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        }
2130a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
2140a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2150a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    if (argc - i != 1) {
216ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        fprintf(stderr, "usage: [-b/l] [-8] [-f#] [-n#] [-p#] [-r] %s filename\n", argv[0]);
217701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        fprintf(stderr, "    -b  force big-endian byte order (default is native byte order)\n");
218701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        fprintf(stderr, "    -l  force little-endian byte order (default is native byte order)\n");
219701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        fprintf(stderr, "    -8  output 8-bits per sample (default is 16-bits per sample)\n");
220701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        fprintf(stderr, "    -f# frames per buffer (default 512)\n");
221701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        fprintf(stderr, "    -n# number of buffers (default 2)\n");
222701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        fprintf(stderr, "    -p# initial playback rate in per mille (default 1000)\n");
223701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        fprintf(stderr, "    -P# final playback rate in per mille (default same as -p#)\n");
224701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        fprintf(stderr, "    -q# magnitude of playback rate changes in per mille (default 1)\n");
225701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        fprintf(stderr, "    -Q# period between playback rate changes in ms (default 50)\n");
226701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        fprintf(stderr, "    -r  enable reverb (default disabled)\n");
2270a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        return EXIT_FAILURE;
2280a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
2290a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2300a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    const char *filename = argv[i];
2310a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    //memset(&sfinfo, 0, sizeof(SF_INFO));
2320a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    sfinfo.format = 0;
2330a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    sndfile = sf_open(filename, SFM_READ, &sfinfo);
2340a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    if (NULL == sndfile) {
2350a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        perror(filename);
2360a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        return EXIT_FAILURE;
2370a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
2380a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
239ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    // The sample rate is a lie, but it doesn't actually matter
240ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    const android::NBAIO_Format nbaio_format = android::Format_from_SR_C(44100, sfinfo.channels);
241ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
2420a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // verify the file format
2430a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    switch (sfinfo.channels) {
2440a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 1:
2450a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 2:
2460a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        break;
2470a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    default:
2480a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        fprintf(stderr, "unsupported channel count %d\n", sfinfo.channels);
249701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        goto close_sndfile;
2500a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
251701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten
2520a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    switch (sfinfo.samplerate) {
2530a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case  8000:
2540a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 11025:
2550a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 12000:
2560a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 16000:
2570a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 22050:
2580a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 24000:
2590a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 32000:
2600a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 44100:
2610a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case 48000:
2620a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        break;
2630a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    default:
2640a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        fprintf(stderr, "unsupported sample rate %d\n", sfinfo.samplerate);
265701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        goto close_sndfile;
2660a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
267701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten
2680a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    switch (sfinfo.format & SF_FORMAT_TYPEMASK) {
2690a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case SF_FORMAT_WAV:
2700a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        break;
2710a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    default:
2720a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        fprintf(stderr, "unsupported format type 0x%x\n", sfinfo.format & SF_FORMAT_TYPEMASK);
273701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        goto close_sndfile;
2740a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
275701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten
2760a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    switch (sfinfo.format & SF_FORMAT_SUBMASK) {
2770a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case SF_FORMAT_PCM_16:
2780a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    case SF_FORMAT_PCM_U8:
2790a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        break;
2800a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    default:
2810a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        fprintf(stderr, "unsupported sub-format 0x%x\n", sfinfo.format & SF_FORMAT_SUBMASK);
282701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        goto close_sndfile;
2830a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
2840a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
285ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    {
286ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
2870a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    buffers = (short *) malloc(framesPerBuffer * sfinfo.channels * sizeof(short) * numBuffers);
2880a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
2890a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // create engine
2900a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLresult result;
2910a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLObjectItf engineObject;
2920a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
2930a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
2940a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLEngineItf engineEngine;
2950a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
2960a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
2970a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
2980a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
2990a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
3000a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // create output mix
3010a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLObjectItf outputMixObject;
3020a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};
3030a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLboolean req[1] = {SL_BOOLEAN_TRUE};
3040a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, enableReverb ? 1 : 0,
3050a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            ids, req);
3060a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
3070a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
3080a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
3090a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
3100a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // configure environmental reverb on output mix
3110a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLEnvironmentalReverbItf mixEnvironmentalReverb = NULL;
3120a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    if (enableReverb) {
3130a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB,
3140a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten                &mixEnvironmentalReverb);
3150a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
3160a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        SLEnvironmentalReverbSettings settings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR;
3170a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        result = (*mixEnvironmentalReverb)->SetEnvironmentalReverbProperties(mixEnvironmentalReverb,
3180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten                &settings);
3190a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
3200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
3210a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
3220a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // configure audio source
3230a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLDataLocator_BufferQueue loc_bufq;
3240a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    loc_bufq.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
3250a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    loc_bufq.numBuffers = numBuffers;
3260a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLDataFormat_PCM format_pcm;
3270a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    format_pcm.formatType = SL_DATAFORMAT_PCM;
3280a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    format_pcm.numChannels = sfinfo.channels;
3290a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    format_pcm.samplesPerSec = sfinfo.samplerate * 1000;
330ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    format_pcm.bitsPerSample = bitsPerSample;
3310a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    format_pcm.containerSize = format_pcm.bitsPerSample;
3320a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    format_pcm.channelMask = 1 == format_pcm.numChannels ? SL_SPEAKER_FRONT_CENTER :
3330a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
334ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten    format_pcm.endianness = byteOrder;
3350a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLDataSource audioSrc;
3360a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    audioSrc.pLocator = &loc_bufq;
3370a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    audioSrc.pFormat = &format_pcm;
3380a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
3390a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // configure audio sink
3400a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLDataLocator_OutputMix loc_outmix;
3410a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
3420a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    loc_outmix.outputMix = outputMixObject;
3430a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLDataSink audioSnk;
3440a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    audioSnk.pLocator = &loc_outmix;
3450a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    audioSnk.pFormat = NULL;
3460a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
3470a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // create audio player
3489a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    SLInterfaceID ids2[3] = {SL_IID_BUFFERQUEUE, SL_IID_PLAYBACKRATE, SL_IID_EFFECTSEND};
3499a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    SLboolean req2[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
3500a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLObjectItf playerObject;
3510a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audioSrc,
352f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            &audioSnk, enableReverb ? 3 : (enablePlaybackRate ? 2 : 1), ids2, req2);
353701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    if (SL_RESULT_SUCCESS != result) {
354701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        fprintf(stderr, "can't create audio player\n");
355701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        goto no_player;
356701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    }
3570a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
358ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    {
359ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
3600a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // realize the player
3610a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
3620a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
3630a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
3640a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // get the effect send interface and enable effect send reverb for this player
3650a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    if (enableReverb) {
3660a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        SLEffectSendItf playerEffectSend;
3670a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        result = (*playerObject)->GetInterface(playerObject, SL_IID_EFFECTSEND, &playerEffectSend);
3680a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
3690a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        result = (*playerEffectSend)->EnableEffectSend(playerEffectSend, mixEnvironmentalReverb,
3700a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten                SL_BOOLEAN_TRUE, (SLmillibel) 0);
3710a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
3720a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
3730a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
3749a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    // get the playback rate interface and configure the rate
3759a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    SLPlaybackRateItf playerPlaybackRate;
376f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten    SLpermille currentRate;
377f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten    if (enablePlaybackRate) {
378f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAYBACKRATE,
379f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten                &playerPlaybackRate);
380f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
381f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        SLpermille defaultRate;
382f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        result = (*playerPlaybackRate)->GetRate(playerPlaybackRate, &defaultRate);
383f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
384f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        SLuint32 defaultProperties;
385f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        result = (*playerPlaybackRate)->GetProperties(playerPlaybackRate, &defaultProperties);
386f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
387f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        printf("default playback rate %d per mille, properties 0x%x\n", defaultRate,
388f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten                defaultProperties);
389f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        if (initialRate <= 0) {
390f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            initialRate = defaultRate;
391f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        }
392f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        if (finalRate <= 0) {
393f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            finalRate = initialRate;
394f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        }
395f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        currentRate = defaultRate;
396f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        if (finalRate == initialRate) {
397701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            deltaRate = 0;
398f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        } else if (finalRate < initialRate) {
399f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            deltaRate = -deltaRate;
400f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        }
401f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        if (initialRate != defaultRate) {
402f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            result = (*playerPlaybackRate)->SetRate(playerPlaybackRate, initialRate);
403f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            if (SL_RESULT_FEATURE_UNSUPPORTED == result) {
404f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten                fprintf(stderr, "initial playback rate %d is unsupported\n", initialRate);
405f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten                deltaRate = 0;
406f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            } else if (SL_RESULT_PARAMETER_INVALID == result) {
407f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten                fprintf(stderr, "initial playback rate %d is invalid\n", initialRate);
408f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten                deltaRate = 0;
409f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            } else {
410f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten                assert(SL_RESULT_SUCCESS == result);
411f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten                currentRate = initialRate;
412f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten            }
4139a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten        }
4149a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten    }
4159a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten
4160a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // get the play interface
4170a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLPlayItf playerPlay;
4180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay);
4190a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
4200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
4210a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // get the buffer queue interface
4220a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLBufferQueueItf playerBufferQueue;
4230a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE,
4240a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            &playerBufferQueue);
4250a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
4260a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
4270a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // loop until EOF or no more buffers
4280a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    for (which = 0; which < numBuffers; ++which) {
4290a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        short *buffer = &buffers[framesPerBuffer * sfinfo.channels * which];
4300a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        sf_count_t frames = framesPerBuffer;
4310a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        sf_count_t count;
4320a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        count = sf_readf_short(sndfile, buffer, frames);
4330a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        if (0 >= count) {
4340a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            eof = SL_BOOLEAN_TRUE;
4350a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            break;
4360a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        }
4370a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
4380a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        // enqueue a buffer
439ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        SLuint32 nbytes = count * sfinfo.channels * sizeof(short);
440ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        if (byteOrder != nativeByteOrder) {
441ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            swab(buffer, buffer, nbytes);
442ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        }
443ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        if (bitsPerSample == 8) {
444ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            squeeze(buffer, (unsigned char *) buffer, nbytes);
445ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten            nbytes /= 2;
446ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        }
447ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten        result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, nbytes);
4480a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
4490a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
450701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    if (which >= numBuffers) {
4510a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        which = 0;
452701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    }
4530a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
4540a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // register a callback on the buffer queue
4550a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, callback, NULL);
4560a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
4570a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
458ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    pipeWriter = new android::MonoPipe(16384, nbaio_format, false /*writeCanBlock*/);
459ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    android::NBAIO_Format offer = nbaio_format;
460ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    size_t numCounterOffers = 0;
461ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    ssize_t neg = pipeWriter->negotiate(&offer, 1, NULL, numCounterOffers);
462ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    assert(0 == neg);
463ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    pipeReader = new android::MonoPipeReader(pipeWriter);
464ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    numCounterOffers = 0;
465ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    neg = pipeReader->negotiate(&offer, 1, NULL, numCounterOffers);
466ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    assert(0 == neg);
467ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
468ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    // create thread to read from file
469ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    pthread_t thread;
470ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    int ok = pthread_create(&thread, (const pthread_attr_t *) NULL, file_reader_loop, NULL);
471ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    assert(0 == ok);
472ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
473ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    // give thread a head start so that the pipe is initially filled
474ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    sleep(1);
475ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
4760a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // set the player's state to playing
4770a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
4780a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    assert(SL_RESULT_SUCCESS == result);
4790a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
480701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    // get the initial time
481701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    struct timespec prevTs;
482701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    clock_gettime(CLOCK_MONOTONIC, &prevTs);
483701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    long elapsedNs = 0;
484701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    long deltaRateNs = deltaRateMs * 1000000;
485701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten
4860a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // wait until the buffer queue is empty
4870a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    SLBufferQueueState bufqstate;
4880a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    for (;;) {
4890a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        result = (*playerBufferQueue)->GetState(playerBufferQueue, &bufqstate);
4900a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        assert(SL_RESULT_SUCCESS == result);
4910a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        if (0 >= bufqstate.count) {
4920a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            break;
4930a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        }
494f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten        if (!enablePlaybackRate || deltaRate == 0) {
495701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            sleep(1);
496701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        } else {
497701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            struct timespec curTs;
498701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            clock_gettime(CLOCK_MONOTONIC, &curTs);
499701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            elapsedNs += (curTs.tv_sec - prevTs.tv_sec) * 1000000000 +
500701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten                    // this term can be negative
501701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten                    (curTs.tv_nsec - prevTs.tv_nsec);
502701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            prevTs = curTs;
503701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            if (elapsedNs < deltaRateNs) {
504701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten                usleep((deltaRateNs - elapsedNs) / 1000);
505701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten                continue;
506701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            }
507701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            elapsedNs -= deltaRateNs;
508701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            SLpermille nextRate = currentRate + deltaRate;
509701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            result = (*playerPlaybackRate)->SetRate(playerPlaybackRate, nextRate);
510701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            if (SL_RESULT_SUCCESS != result) {
511701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten                fprintf(stderr, "next playback rate %d is unsupported\n", nextRate);
512701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            } else if (SL_RESULT_PARAMETER_INVALID == result) {
513701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten                fprintf(stderr, "next playback rate %d is invalid\n", nextRate);
514701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            } else {
515701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten                assert(SL_RESULT_SUCCESS == result);
516701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            }
517701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            currentRate = nextRate;
518701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            if (currentRate >= max(initialRate, finalRate)) {
519701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten                currentRate = max(initialRate, finalRate);
520701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten                deltaRate = -abs(deltaRate);
521701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            } else if (currentRate <= min(initialRate, finalRate)) {
522701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten                currentRate = min(initialRate, finalRate);
523701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten                deltaRate = abs(deltaRate);
524701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten            }
525701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten        }
5260a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
5270a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
5280a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // destroy audio player
5290a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    (*playerObject)->Destroy(playerObject);
5300a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
531ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    }
532ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
533701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kastenno_player:
534701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten
5350a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // destroy output mix
5360a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    (*outputMixObject)->Destroy(outputMixObject);
5370a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
5380a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    // destroy engine
5390a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    (*engineObject)->Destroy(engineObject);
5400a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten
541ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten    }
542ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten
543701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kastenclose_sndfile:
544701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten
545701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten    (void) sf_close(sndfile);
546701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten
5470a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    return EXIT_SUCCESS;
5480a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten}
549