1*bebae9c0SAndroid Build Coastguard Worker /*
2*bebae9c0SAndroid Build Coastguard Worker * Copyright (C) 2010 The Android Open Source Project
3*bebae9c0SAndroid Build Coastguard Worker *
4*bebae9c0SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*bebae9c0SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*bebae9c0SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*bebae9c0SAndroid Build Coastguard Worker *
8*bebae9c0SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*bebae9c0SAndroid Build Coastguard Worker *
10*bebae9c0SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*bebae9c0SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*bebae9c0SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*bebae9c0SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*bebae9c0SAndroid Build Coastguard Worker * limitations under the License.
15*bebae9c0SAndroid Build Coastguard Worker */
16*bebae9c0SAndroid Build Coastguard Worker
17*bebae9c0SAndroid Build Coastguard Worker // Play an audio file using buffer queue
18*bebae9c0SAndroid Build Coastguard Worker
19*bebae9c0SAndroid Build Coastguard Worker #include <assert.h>
20*bebae9c0SAndroid Build Coastguard Worker #include <math.h>
21*bebae9c0SAndroid Build Coastguard Worker #include <pthread.h>
22*bebae9c0SAndroid Build Coastguard Worker #include <stdio.h>
23*bebae9c0SAndroid Build Coastguard Worker #include <stdlib.h>
24*bebae9c0SAndroid Build Coastguard Worker #include <string.h>
25*bebae9c0SAndroid Build Coastguard Worker #include <time.h>
26*bebae9c0SAndroid Build Coastguard Worker #include <unistd.h>
27*bebae9c0SAndroid Build Coastguard Worker
28*bebae9c0SAndroid Build Coastguard Worker #include <SLES/OpenSLES.h>
29*bebae9c0SAndroid Build Coastguard Worker #include <SLES/OpenSLES_Android.h>
30*bebae9c0SAndroid Build Coastguard Worker #include <system/audio.h>
31*bebae9c0SAndroid Build Coastguard Worker #include <audio_utils/fifo.h>
32*bebae9c0SAndroid Build Coastguard Worker #include <audio_utils/primitives.h>
33*bebae9c0SAndroid Build Coastguard Worker #include <audio_utils/sndfile.h>
34*bebae9c0SAndroid Build Coastguard Worker
35*bebae9c0SAndroid Build Coastguard Worker #define max(a, b) ((a) > (b) ? (a) : (b))
36*bebae9c0SAndroid Build Coastguard Worker #define min(a, b) ((a) < (b) ? (a) : (b))
37*bebae9c0SAndroid Build Coastguard Worker
38*bebae9c0SAndroid Build Coastguard Worker unsigned numBuffers = 2;
39*bebae9c0SAndroid Build Coastguard Worker int framesPerBuffer = 512;
40*bebae9c0SAndroid Build Coastguard Worker SNDFILE *sndfile;
41*bebae9c0SAndroid Build Coastguard Worker SF_INFO sfinfo;
42*bebae9c0SAndroid Build Coastguard Worker unsigned which; // which buffer to use next
43*bebae9c0SAndroid Build Coastguard Worker SLboolean eof; // whether we have hit EOF on input yet
44*bebae9c0SAndroid Build Coastguard Worker void *buffers;
45*bebae9c0SAndroid Build Coastguard Worker SLuint32 byteOrder; // desired to use for PCM buffers
46*bebae9c0SAndroid Build Coastguard Worker SLuint32 nativeByteOrder; // of platform
47*bebae9c0SAndroid Build Coastguard Worker audio_format_t transferFormat = AUDIO_FORMAT_DEFAULT;
48*bebae9c0SAndroid Build Coastguard Worker size_t sfframesize = 0;
49*bebae9c0SAndroid Build Coastguard Worker
50*bebae9c0SAndroid Build Coastguard Worker static audio_utils_fifo *fifo;
51*bebae9c0SAndroid Build Coastguard Worker static audio_utils_fifo_reader *fifoReader;
52*bebae9c0SAndroid Build Coastguard Worker static audio_utils_fifo_writer *fifoWriter;
53*bebae9c0SAndroid Build Coastguard Worker static unsigned underruns = 0;
54*bebae9c0SAndroid Build Coastguard Worker
squeeze(void * buffer,SLuint32 nbytes)55*bebae9c0SAndroid Build Coastguard Worker static SLuint32 squeeze(void *buffer, SLuint32 nbytes)
56*bebae9c0SAndroid Build Coastguard Worker {
57*bebae9c0SAndroid Build Coastguard Worker if (byteOrder != nativeByteOrder) {
58*bebae9c0SAndroid Build Coastguard Worker // FIXME does not work for non 16-bit
59*bebae9c0SAndroid Build Coastguard Worker swab(buffer, buffer, nbytes);
60*bebae9c0SAndroid Build Coastguard Worker }
61*bebae9c0SAndroid Build Coastguard Worker if (transferFormat == AUDIO_FORMAT_PCM_8_BIT) {
62*bebae9c0SAndroid Build Coastguard Worker memcpy_to_u8_from_i16((uint8_t *) buffer, (const int16_t *) buffer,
63*bebae9c0SAndroid Build Coastguard Worker nbytes / sizeof(int16_t));
64*bebae9c0SAndroid Build Coastguard Worker nbytes /= 2;
65*bebae9c0SAndroid Build Coastguard Worker } else if (transferFormat == AUDIO_FORMAT_PCM_24_BIT_PACKED) {
66*bebae9c0SAndroid Build Coastguard Worker memcpy_to_p24_from_i32((uint8_t *) buffer, (const int32_t *) buffer,
67*bebae9c0SAndroid Build Coastguard Worker nbytes / sizeof(int32_t));
68*bebae9c0SAndroid Build Coastguard Worker nbytes = nbytes * 3 / 4;
69*bebae9c0SAndroid Build Coastguard Worker }
70*bebae9c0SAndroid Build Coastguard Worker return nbytes;
71*bebae9c0SAndroid Build Coastguard Worker }
72*bebae9c0SAndroid Build Coastguard Worker
73*bebae9c0SAndroid Build Coastguard Worker // This callback is called each time a buffer finishes playing
74*bebae9c0SAndroid Build Coastguard Worker
callback(SLBufferQueueItf bufq,void * param)75*bebae9c0SAndroid Build Coastguard Worker static void callback(SLBufferQueueItf bufq, void *param)
76*bebae9c0SAndroid Build Coastguard Worker {
77*bebae9c0SAndroid Build Coastguard Worker assert(NULL == param);
78*bebae9c0SAndroid Build Coastguard Worker if (!eof) {
79*bebae9c0SAndroid Build Coastguard Worker void *buffer = (char *)buffers + framesPerBuffer * sfframesize * which;
80*bebae9c0SAndroid Build Coastguard Worker ssize_t count = fifoReader->read(buffer, framesPerBuffer);
81*bebae9c0SAndroid Build Coastguard Worker // on underrun from pipe, substitute silence
82*bebae9c0SAndroid Build Coastguard Worker if (0 >= count) {
83*bebae9c0SAndroid Build Coastguard Worker memset(buffer, 0, framesPerBuffer * sfframesize);
84*bebae9c0SAndroid Build Coastguard Worker count = framesPerBuffer;
85*bebae9c0SAndroid Build Coastguard Worker ++underruns;
86*bebae9c0SAndroid Build Coastguard Worker }
87*bebae9c0SAndroid Build Coastguard Worker if (count > 0) {
88*bebae9c0SAndroid Build Coastguard Worker SLuint32 nbytes = count * sfframesize;
89*bebae9c0SAndroid Build Coastguard Worker nbytes = squeeze(buffer, nbytes);
90*bebae9c0SAndroid Build Coastguard Worker SLresult result = (*bufq)->Enqueue(bufq, buffer, nbytes);
91*bebae9c0SAndroid Build Coastguard Worker assert(SL_RESULT_SUCCESS == result);
92*bebae9c0SAndroid Build Coastguard Worker if (++which >= numBuffers)
93*bebae9c0SAndroid Build Coastguard Worker which = 0;
94*bebae9c0SAndroid Build Coastguard Worker }
95*bebae9c0SAndroid Build Coastguard Worker }
96*bebae9c0SAndroid Build Coastguard Worker }
97*bebae9c0SAndroid Build Coastguard Worker
98*bebae9c0SAndroid Build Coastguard Worker // This thread reads from a (slow) filesystem with unpredictable latency and writes to pipe
99*bebae9c0SAndroid Build Coastguard Worker
file_reader_loop(void * arg __unused)100*bebae9c0SAndroid Build Coastguard Worker static void *file_reader_loop(void *arg __unused)
101*bebae9c0SAndroid Build Coastguard Worker {
102*bebae9c0SAndroid Build Coastguard Worker #define READ_FRAMES 256
103*bebae9c0SAndroid Build Coastguard Worker void *temp = malloc(READ_FRAMES * sfframesize);
104*bebae9c0SAndroid Build Coastguard Worker sf_count_t total = 0;
105*bebae9c0SAndroid Build Coastguard Worker sf_count_t count;
106*bebae9c0SAndroid Build Coastguard Worker for (;;) {
107*bebae9c0SAndroid Build Coastguard Worker switch (transferFormat) {
108*bebae9c0SAndroid Build Coastguard Worker case AUDIO_FORMAT_PCM_FLOAT:
109*bebae9c0SAndroid Build Coastguard Worker count = sf_readf_float(sndfile, (float *) temp, READ_FRAMES);
110*bebae9c0SAndroid Build Coastguard Worker break;
111*bebae9c0SAndroid Build Coastguard Worker case AUDIO_FORMAT_PCM_32_BIT:
112*bebae9c0SAndroid Build Coastguard Worker case AUDIO_FORMAT_PCM_24_BIT_PACKED:
113*bebae9c0SAndroid Build Coastguard Worker count = sf_readf_int(sndfile, (int *) temp, READ_FRAMES);
114*bebae9c0SAndroid Build Coastguard Worker break;
115*bebae9c0SAndroid Build Coastguard Worker case AUDIO_FORMAT_PCM_16_BIT:
116*bebae9c0SAndroid Build Coastguard Worker case AUDIO_FORMAT_PCM_8_BIT:
117*bebae9c0SAndroid Build Coastguard Worker count = sf_readf_short(sndfile, (short *) temp, READ_FRAMES);
118*bebae9c0SAndroid Build Coastguard Worker break;
119*bebae9c0SAndroid Build Coastguard Worker default:
120*bebae9c0SAndroid Build Coastguard Worker count = 0;
121*bebae9c0SAndroid Build Coastguard Worker break;
122*bebae9c0SAndroid Build Coastguard Worker }
123*bebae9c0SAndroid Build Coastguard Worker if (0 >= count) {
124*bebae9c0SAndroid Build Coastguard Worker eof = SL_BOOLEAN_TRUE;
125*bebae9c0SAndroid Build Coastguard Worker break;
126*bebae9c0SAndroid Build Coastguard Worker }
127*bebae9c0SAndroid Build Coastguard Worker const unsigned char *ptr = (unsigned char *) temp;
128*bebae9c0SAndroid Build Coastguard Worker while (count > 0) {
129*bebae9c0SAndroid Build Coastguard Worker ssize_t actual = fifoWriter->write(ptr, (size_t) count);
130*bebae9c0SAndroid Build Coastguard Worker if (actual < 0) {
131*bebae9c0SAndroid Build Coastguard Worker break;
132*bebae9c0SAndroid Build Coastguard Worker }
133*bebae9c0SAndroid Build Coastguard Worker if ((sf_count_t) actual < count) {
134*bebae9c0SAndroid Build Coastguard Worker usleep(10000);
135*bebae9c0SAndroid Build Coastguard Worker }
136*bebae9c0SAndroid Build Coastguard Worker ptr += actual * sfframesize;
137*bebae9c0SAndroid Build Coastguard Worker count -= actual;
138*bebae9c0SAndroid Build Coastguard Worker total += actual;
139*bebae9c0SAndroid Build Coastguard Worker }
140*bebae9c0SAndroid Build Coastguard Worker // simulate occasional filesystem latency
141*bebae9c0SAndroid Build Coastguard Worker if ((total & 0xFF00) == 0xFF00) {
142*bebae9c0SAndroid Build Coastguard Worker usleep(100000);
143*bebae9c0SAndroid Build Coastguard Worker }
144*bebae9c0SAndroid Build Coastguard Worker }
145*bebae9c0SAndroid Build Coastguard Worker free(temp);
146*bebae9c0SAndroid Build Coastguard Worker return NULL;
147*bebae9c0SAndroid Build Coastguard Worker }
148*bebae9c0SAndroid Build Coastguard Worker
149*bebae9c0SAndroid Build Coastguard Worker // Main program
150*bebae9c0SAndroid Build Coastguard Worker
main(int argc,char ** argv)151*bebae9c0SAndroid Build Coastguard Worker int main(int argc, char **argv)
152*bebae9c0SAndroid Build Coastguard Worker {
153*bebae9c0SAndroid Build Coastguard Worker // Determine the native byte order (SL_BYTEORDER_NATIVE not available until 1.1)
154*bebae9c0SAndroid Build Coastguard Worker union {
155*bebae9c0SAndroid Build Coastguard Worker short s;
156*bebae9c0SAndroid Build Coastguard Worker char c[2];
157*bebae9c0SAndroid Build Coastguard Worker } u;
158*bebae9c0SAndroid Build Coastguard Worker u.s = 0x1234;
159*bebae9c0SAndroid Build Coastguard Worker if (u.c[0] == 0x34) {
160*bebae9c0SAndroid Build Coastguard Worker nativeByteOrder = SL_BYTEORDER_LITTLEENDIAN;
161*bebae9c0SAndroid Build Coastguard Worker } else if (u.c[0] == 0x12) {
162*bebae9c0SAndroid Build Coastguard Worker nativeByteOrder = SL_BYTEORDER_BIGENDIAN;
163*bebae9c0SAndroid Build Coastguard Worker } else {
164*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "Unable to determine native byte order\n");
165*bebae9c0SAndroid Build Coastguard Worker return EXIT_FAILURE;
166*bebae9c0SAndroid Build Coastguard Worker }
167*bebae9c0SAndroid Build Coastguard Worker byteOrder = nativeByteOrder;
168*bebae9c0SAndroid Build Coastguard Worker
169*bebae9c0SAndroid Build Coastguard Worker SLboolean enableReverb = SL_BOOLEAN_FALSE;
170*bebae9c0SAndroid Build Coastguard Worker SLboolean enablePlaybackRate = SL_BOOLEAN_FALSE;
171*bebae9c0SAndroid Build Coastguard Worker SLpermille initialRate = 0;
172*bebae9c0SAndroid Build Coastguard Worker SLpermille finalRate = 0;
173*bebae9c0SAndroid Build Coastguard Worker SLpermille deltaRate = 1;
174*bebae9c0SAndroid Build Coastguard Worker SLmillisecond deltaRateMs = 0;
175*bebae9c0SAndroid Build Coastguard Worker
176*bebae9c0SAndroid Build Coastguard Worker // process command-line options
177*bebae9c0SAndroid Build Coastguard Worker int i;
178*bebae9c0SAndroid Build Coastguard Worker for (i = 1; i < argc; ++i) {
179*bebae9c0SAndroid Build Coastguard Worker char *arg = argv[i];
180*bebae9c0SAndroid Build Coastguard Worker if (arg[0] != '-') {
181*bebae9c0SAndroid Build Coastguard Worker break;
182*bebae9c0SAndroid Build Coastguard Worker }
183*bebae9c0SAndroid Build Coastguard Worker if (!strcmp(arg, "-b")) {
184*bebae9c0SAndroid Build Coastguard Worker byteOrder = SL_BYTEORDER_BIGENDIAN;
185*bebae9c0SAndroid Build Coastguard Worker } else if (!strcmp(arg, "-l")) {
186*bebae9c0SAndroid Build Coastguard Worker byteOrder = SL_BYTEORDER_LITTLEENDIAN;
187*bebae9c0SAndroid Build Coastguard Worker } else if (!strcmp(arg, "-8")) {
188*bebae9c0SAndroid Build Coastguard Worker transferFormat = AUDIO_FORMAT_PCM_8_BIT;
189*bebae9c0SAndroid Build Coastguard Worker } else if (!strcmp(arg, "-16")) {
190*bebae9c0SAndroid Build Coastguard Worker transferFormat = AUDIO_FORMAT_PCM_16_BIT;
191*bebae9c0SAndroid Build Coastguard Worker } else if (!strcmp(arg, "-24")) {
192*bebae9c0SAndroid Build Coastguard Worker transferFormat = AUDIO_FORMAT_PCM_24_BIT_PACKED;
193*bebae9c0SAndroid Build Coastguard Worker } else if (!strcmp(arg, "-32")) {
194*bebae9c0SAndroid Build Coastguard Worker transferFormat = AUDIO_FORMAT_PCM_32_BIT;
195*bebae9c0SAndroid Build Coastguard Worker } else if (!strcmp(arg, "-32f")) {
196*bebae9c0SAndroid Build Coastguard Worker transferFormat = AUDIO_FORMAT_PCM_FLOAT;
197*bebae9c0SAndroid Build Coastguard Worker } else if (!strncmp(arg, "-f", 2)) {
198*bebae9c0SAndroid Build Coastguard Worker framesPerBuffer = atoi(&arg[2]);
199*bebae9c0SAndroid Build Coastguard Worker } else if (!strncmp(arg, "-n", 2)) {
200*bebae9c0SAndroid Build Coastguard Worker numBuffers = atoi(&arg[2]);
201*bebae9c0SAndroid Build Coastguard Worker } else if (!strncmp(arg, "-p", 2)) {
202*bebae9c0SAndroid Build Coastguard Worker initialRate = atoi(&arg[2]);
203*bebae9c0SAndroid Build Coastguard Worker enablePlaybackRate = SL_BOOLEAN_TRUE;
204*bebae9c0SAndroid Build Coastguard Worker } else if (!strncmp(arg, "-P", 2)) {
205*bebae9c0SAndroid Build Coastguard Worker finalRate = atoi(&arg[2]);
206*bebae9c0SAndroid Build Coastguard Worker enablePlaybackRate = SL_BOOLEAN_TRUE;
207*bebae9c0SAndroid Build Coastguard Worker } else if (!strncmp(arg, "-q", 2)) {
208*bebae9c0SAndroid Build Coastguard Worker deltaRate = atoi(&arg[2]);
209*bebae9c0SAndroid Build Coastguard Worker // deltaRate is a magnitude, so take absolute value
210*bebae9c0SAndroid Build Coastguard Worker if (deltaRate < 0) {
211*bebae9c0SAndroid Build Coastguard Worker deltaRate = -deltaRate;
212*bebae9c0SAndroid Build Coastguard Worker }
213*bebae9c0SAndroid Build Coastguard Worker enablePlaybackRate = SL_BOOLEAN_TRUE;
214*bebae9c0SAndroid Build Coastguard Worker } else if (!strncmp(arg, "-Q", 2)) {
215*bebae9c0SAndroid Build Coastguard Worker deltaRateMs = atoi(&arg[2]);
216*bebae9c0SAndroid Build Coastguard Worker enablePlaybackRate = SL_BOOLEAN_TRUE;
217*bebae9c0SAndroid Build Coastguard Worker } else if (!strcmp(arg, "-r")) {
218*bebae9c0SAndroid Build Coastguard Worker enableReverb = SL_BOOLEAN_TRUE;
219*bebae9c0SAndroid Build Coastguard Worker } else {
220*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "option %s ignored\n", arg);
221*bebae9c0SAndroid Build Coastguard Worker }
222*bebae9c0SAndroid Build Coastguard Worker }
223*bebae9c0SAndroid Build Coastguard Worker
224*bebae9c0SAndroid Build Coastguard Worker if (argc - i != 1) {
225*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "usage: [-b/l] [-8 | | -16 | -24 | -32 | -32f] [-f#] [-n#] [-p#] [-r]"
226*bebae9c0SAndroid Build Coastguard Worker " %s filename\n", argv[0]);
227*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, " -b force big-endian byte order (default is native byte order)\n");
228*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, " -l force little-endian byte order (default is native byte order)\n");
229*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, " -8 output 8-bits per sample (default is that of input file)\n");
230*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, " -16 output 16-bits per sample\n");
231*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, " -24 output 24-bits per sample\n");
232*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, " -32 output 32-bits per sample\n");
233*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, " -32f output float 32-bits per sample\n");
234*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, " -f# frames per buffer (default 512)\n");
235*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, " -n# number of buffers (default 2)\n");
236*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, " -p# initial playback rate in per mille (default 1000)\n");
237*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, " -P# final playback rate in per mille (default same as -p#)\n");
238*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, " -q# magnitude of playback rate changes in per mille (default 1)\n");
239*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, " -Q# period between playback rate changes in ms (default 50)\n");
240*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, " -r enable reverb (default disabled)\n");
241*bebae9c0SAndroid Build Coastguard Worker return EXIT_FAILURE;
242*bebae9c0SAndroid Build Coastguard Worker }
243*bebae9c0SAndroid Build Coastguard Worker
244*bebae9c0SAndroid Build Coastguard Worker const char *filename = argv[i];
245*bebae9c0SAndroid Build Coastguard Worker //memset(&sfinfo, 0, sizeof(SF_INFO));
246*bebae9c0SAndroid Build Coastguard Worker sfinfo.format = 0;
247*bebae9c0SAndroid Build Coastguard Worker sndfile = sf_open(filename, SFM_READ, &sfinfo);
248*bebae9c0SAndroid Build Coastguard Worker if (NULL == sndfile) {
249*bebae9c0SAndroid Build Coastguard Worker perror(filename);
250*bebae9c0SAndroid Build Coastguard Worker return EXIT_FAILURE;
251*bebae9c0SAndroid Build Coastguard Worker }
252*bebae9c0SAndroid Build Coastguard Worker
253*bebae9c0SAndroid Build Coastguard Worker // verify the file format
254*bebae9c0SAndroid Build Coastguard Worker switch (sfinfo.channels) {
255*bebae9c0SAndroid Build Coastguard Worker case 1:
256*bebae9c0SAndroid Build Coastguard Worker case 2:
257*bebae9c0SAndroid Build Coastguard Worker break;
258*bebae9c0SAndroid Build Coastguard Worker default:
259*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "unsupported channel count %d\n", sfinfo.channels);
260*bebae9c0SAndroid Build Coastguard Worker goto close_sndfile;
261*bebae9c0SAndroid Build Coastguard Worker }
262*bebae9c0SAndroid Build Coastguard Worker
263*bebae9c0SAndroid Build Coastguard Worker if (sfinfo.samplerate < 8000 || sfinfo.samplerate > 192000) {
264*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "unsupported sample rate %d\n", sfinfo.samplerate);
265*bebae9c0SAndroid Build Coastguard Worker goto close_sndfile;
266*bebae9c0SAndroid Build Coastguard Worker }
267*bebae9c0SAndroid Build Coastguard Worker
268*bebae9c0SAndroid Build Coastguard Worker switch (sfinfo.format & SF_FORMAT_TYPEMASK) {
269*bebae9c0SAndroid Build Coastguard Worker case SF_FORMAT_WAV:
270*bebae9c0SAndroid Build Coastguard Worker break;
271*bebae9c0SAndroid Build Coastguard Worker default:
272*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "unsupported format type 0x%x\n", sfinfo.format & SF_FORMAT_TYPEMASK);
273*bebae9c0SAndroid Build Coastguard Worker goto close_sndfile;
274*bebae9c0SAndroid Build Coastguard Worker }
275*bebae9c0SAndroid Build Coastguard Worker
276*bebae9c0SAndroid Build Coastguard Worker switch (sfinfo.format & SF_FORMAT_SUBMASK) {
277*bebae9c0SAndroid Build Coastguard Worker case SF_FORMAT_FLOAT:
278*bebae9c0SAndroid Build Coastguard Worker if (transferFormat == AUDIO_FORMAT_DEFAULT) {
279*bebae9c0SAndroid Build Coastguard Worker transferFormat = AUDIO_FORMAT_PCM_FLOAT;
280*bebae9c0SAndroid Build Coastguard Worker }
281*bebae9c0SAndroid Build Coastguard Worker break;
282*bebae9c0SAndroid Build Coastguard Worker case SF_FORMAT_PCM_32:
283*bebae9c0SAndroid Build Coastguard Worker if (transferFormat == AUDIO_FORMAT_DEFAULT) {
284*bebae9c0SAndroid Build Coastguard Worker transferFormat = AUDIO_FORMAT_PCM_32_BIT;
285*bebae9c0SAndroid Build Coastguard Worker }
286*bebae9c0SAndroid Build Coastguard Worker break;
287*bebae9c0SAndroid Build Coastguard Worker case SF_FORMAT_PCM_16:
288*bebae9c0SAndroid Build Coastguard Worker if (transferFormat == AUDIO_FORMAT_DEFAULT) {
289*bebae9c0SAndroid Build Coastguard Worker transferFormat = AUDIO_FORMAT_PCM_16_BIT;
290*bebae9c0SAndroid Build Coastguard Worker }
291*bebae9c0SAndroid Build Coastguard Worker break;
292*bebae9c0SAndroid Build Coastguard Worker case SF_FORMAT_PCM_U8:
293*bebae9c0SAndroid Build Coastguard Worker if (transferFormat == AUDIO_FORMAT_DEFAULT) {
294*bebae9c0SAndroid Build Coastguard Worker transferFormat = AUDIO_FORMAT_PCM_8_BIT;
295*bebae9c0SAndroid Build Coastguard Worker }
296*bebae9c0SAndroid Build Coastguard Worker break;
297*bebae9c0SAndroid Build Coastguard Worker case SF_FORMAT_PCM_24:
298*bebae9c0SAndroid Build Coastguard Worker if (transferFormat == AUDIO_FORMAT_DEFAULT) {
299*bebae9c0SAndroid Build Coastguard Worker transferFormat = AUDIO_FORMAT_PCM_24_BIT_PACKED;
300*bebae9c0SAndroid Build Coastguard Worker }
301*bebae9c0SAndroid Build Coastguard Worker break;
302*bebae9c0SAndroid Build Coastguard Worker default:
303*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "unsupported sub-format 0x%x\n", sfinfo.format & SF_FORMAT_SUBMASK);
304*bebae9c0SAndroid Build Coastguard Worker goto close_sndfile;
305*bebae9c0SAndroid Build Coastguard Worker }
306*bebae9c0SAndroid Build Coastguard Worker
307*bebae9c0SAndroid Build Coastguard Worker SLuint32 bitsPerSample;
308*bebae9c0SAndroid Build Coastguard Worker switch (transferFormat) {
309*bebae9c0SAndroid Build Coastguard Worker case AUDIO_FORMAT_PCM_FLOAT:
310*bebae9c0SAndroid Build Coastguard Worker bitsPerSample = 32;
311*bebae9c0SAndroid Build Coastguard Worker sfframesize = sfinfo.channels * sizeof(float);
312*bebae9c0SAndroid Build Coastguard Worker break;
313*bebae9c0SAndroid Build Coastguard Worker case AUDIO_FORMAT_PCM_32_BIT:
314*bebae9c0SAndroid Build Coastguard Worker bitsPerSample = 32;
315*bebae9c0SAndroid Build Coastguard Worker sfframesize = sfinfo.channels * sizeof(int);
316*bebae9c0SAndroid Build Coastguard Worker break;
317*bebae9c0SAndroid Build Coastguard Worker case AUDIO_FORMAT_PCM_24_BIT_PACKED:
318*bebae9c0SAndroid Build Coastguard Worker bitsPerSample = 24;
319*bebae9c0SAndroid Build Coastguard Worker sfframesize = sfinfo.channels * sizeof(int); // use int size
320*bebae9c0SAndroid Build Coastguard Worker break;
321*bebae9c0SAndroid Build Coastguard Worker case AUDIO_FORMAT_PCM_16_BIT:
322*bebae9c0SAndroid Build Coastguard Worker bitsPerSample = 16;
323*bebae9c0SAndroid Build Coastguard Worker sfframesize = sfinfo.channels * sizeof(short);
324*bebae9c0SAndroid Build Coastguard Worker break;
325*bebae9c0SAndroid Build Coastguard Worker case AUDIO_FORMAT_PCM_8_BIT:
326*bebae9c0SAndroid Build Coastguard Worker bitsPerSample = 8;
327*bebae9c0SAndroid Build Coastguard Worker sfframesize = sfinfo.channels * sizeof(short); // use short size
328*bebae9c0SAndroid Build Coastguard Worker break;
329*bebae9c0SAndroid Build Coastguard Worker default:
330*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "unsupported transfer format %#x\n", transferFormat);
331*bebae9c0SAndroid Build Coastguard Worker goto close_sndfile;
332*bebae9c0SAndroid Build Coastguard Worker }
333*bebae9c0SAndroid Build Coastguard Worker
334*bebae9c0SAndroid Build Coastguard Worker {
335*bebae9c0SAndroid Build Coastguard Worker buffers = malloc(framesPerBuffer * sfframesize * numBuffers);
336*bebae9c0SAndroid Build Coastguard Worker
337*bebae9c0SAndroid Build Coastguard Worker // create engine
338*bebae9c0SAndroid Build Coastguard Worker SLresult result;
339*bebae9c0SAndroid Build Coastguard Worker SLObjectItf engineObject;
340*bebae9c0SAndroid Build Coastguard Worker result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
341*bebae9c0SAndroid Build Coastguard Worker assert(SL_RESULT_SUCCESS == result);
342*bebae9c0SAndroid Build Coastguard Worker SLEngineItf engineEngine;
343*bebae9c0SAndroid Build Coastguard Worker result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
344*bebae9c0SAndroid Build Coastguard Worker assert(SL_RESULT_SUCCESS == result);
345*bebae9c0SAndroid Build Coastguard Worker result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
346*bebae9c0SAndroid Build Coastguard Worker assert(SL_RESULT_SUCCESS == result);
347*bebae9c0SAndroid Build Coastguard Worker
348*bebae9c0SAndroid Build Coastguard Worker // create output mix
349*bebae9c0SAndroid Build Coastguard Worker SLObjectItf outputMixObject;
350*bebae9c0SAndroid Build Coastguard Worker SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};
351*bebae9c0SAndroid Build Coastguard Worker SLboolean req[1] = {SL_BOOLEAN_TRUE};
352*bebae9c0SAndroid Build Coastguard Worker result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, enableReverb ? 1 : 0,
353*bebae9c0SAndroid Build Coastguard Worker ids, req);
354*bebae9c0SAndroid Build Coastguard Worker assert(SL_RESULT_SUCCESS == result);
355*bebae9c0SAndroid Build Coastguard Worker result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
356*bebae9c0SAndroid Build Coastguard Worker assert(SL_RESULT_SUCCESS == result);
357*bebae9c0SAndroid Build Coastguard Worker
358*bebae9c0SAndroid Build Coastguard Worker // configure environmental reverb on output mix
359*bebae9c0SAndroid Build Coastguard Worker SLEnvironmentalReverbItf mixEnvironmentalReverb = NULL;
360*bebae9c0SAndroid Build Coastguard Worker if (enableReverb) {
361*bebae9c0SAndroid Build Coastguard Worker result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB,
362*bebae9c0SAndroid Build Coastguard Worker &mixEnvironmentalReverb);
363*bebae9c0SAndroid Build Coastguard Worker assert(SL_RESULT_SUCCESS == result);
364*bebae9c0SAndroid Build Coastguard Worker SLEnvironmentalReverbSettings settings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR;
365*bebae9c0SAndroid Build Coastguard Worker result = (*mixEnvironmentalReverb)->SetEnvironmentalReverbProperties(mixEnvironmentalReverb,
366*bebae9c0SAndroid Build Coastguard Worker &settings);
367*bebae9c0SAndroid Build Coastguard Worker assert(SL_RESULT_SUCCESS == result);
368*bebae9c0SAndroid Build Coastguard Worker }
369*bebae9c0SAndroid Build Coastguard Worker
370*bebae9c0SAndroid Build Coastguard Worker // configure audio source
371*bebae9c0SAndroid Build Coastguard Worker SLDataLocator_BufferQueue loc_bufq;
372*bebae9c0SAndroid Build Coastguard Worker loc_bufq.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
373*bebae9c0SAndroid Build Coastguard Worker loc_bufq.numBuffers = numBuffers;
374*bebae9c0SAndroid Build Coastguard Worker SLAndroidDataFormat_PCM_EX format_pcm;
375*bebae9c0SAndroid Build Coastguard Worker format_pcm.formatType = transferFormat == AUDIO_FORMAT_PCM_FLOAT
376*bebae9c0SAndroid Build Coastguard Worker ? SL_ANDROID_DATAFORMAT_PCM_EX : SL_DATAFORMAT_PCM;
377*bebae9c0SAndroid Build Coastguard Worker format_pcm.numChannels = sfinfo.channels;
378*bebae9c0SAndroid Build Coastguard Worker format_pcm.sampleRate = sfinfo.samplerate * 1000;
379*bebae9c0SAndroid Build Coastguard Worker format_pcm.bitsPerSample = bitsPerSample;
380*bebae9c0SAndroid Build Coastguard Worker format_pcm.containerSize = format_pcm.bitsPerSample;
381*bebae9c0SAndroid Build Coastguard Worker format_pcm.channelMask = 1 == format_pcm.numChannels ? SL_SPEAKER_FRONT_CENTER :
382*bebae9c0SAndroid Build Coastguard Worker SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
383*bebae9c0SAndroid Build Coastguard Worker format_pcm.endianness = byteOrder;
384*bebae9c0SAndroid Build Coastguard Worker format_pcm.representation = transferFormat == AUDIO_FORMAT_PCM_FLOAT
385*bebae9c0SAndroid Build Coastguard Worker ? SL_ANDROID_PCM_REPRESENTATION_FLOAT : transferFormat == AUDIO_FORMAT_PCM_8_BIT
386*bebae9c0SAndroid Build Coastguard Worker ? SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT
387*bebae9c0SAndroid Build Coastguard Worker : SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT;
388*bebae9c0SAndroid Build Coastguard Worker SLDataSource audioSrc;
389*bebae9c0SAndroid Build Coastguard Worker audioSrc.pLocator = &loc_bufq;
390*bebae9c0SAndroid Build Coastguard Worker audioSrc.pFormat = &format_pcm;
391*bebae9c0SAndroid Build Coastguard Worker
392*bebae9c0SAndroid Build Coastguard Worker // configure audio sink
393*bebae9c0SAndroid Build Coastguard Worker SLDataLocator_OutputMix loc_outmix;
394*bebae9c0SAndroid Build Coastguard Worker loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
395*bebae9c0SAndroid Build Coastguard Worker loc_outmix.outputMix = outputMixObject;
396*bebae9c0SAndroid Build Coastguard Worker SLDataSink audioSnk;
397*bebae9c0SAndroid Build Coastguard Worker audioSnk.pLocator = &loc_outmix;
398*bebae9c0SAndroid Build Coastguard Worker audioSnk.pFormat = NULL;
399*bebae9c0SAndroid Build Coastguard Worker
400*bebae9c0SAndroid Build Coastguard Worker // create audio player
401*bebae9c0SAndroid Build Coastguard Worker SLInterfaceID ids2[3] = {SL_IID_BUFFERQUEUE, SL_IID_PLAYBACKRATE, SL_IID_EFFECTSEND};
402*bebae9c0SAndroid Build Coastguard Worker SLboolean req2[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
403*bebae9c0SAndroid Build Coastguard Worker SLObjectItf playerObject;
404*bebae9c0SAndroid Build Coastguard Worker result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audioSrc,
405*bebae9c0SAndroid Build Coastguard Worker &audioSnk, enableReverb ? 3 : (enablePlaybackRate ? 2 : 1), ids2, req2);
406*bebae9c0SAndroid Build Coastguard Worker if (SL_RESULT_SUCCESS != result) {
407*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "can't create audio player\n");
408*bebae9c0SAndroid Build Coastguard Worker goto no_player;
409*bebae9c0SAndroid Build Coastguard Worker }
410*bebae9c0SAndroid Build Coastguard Worker
411*bebae9c0SAndroid Build Coastguard Worker {
412*bebae9c0SAndroid Build Coastguard Worker
413*bebae9c0SAndroid Build Coastguard Worker // realize the player
414*bebae9c0SAndroid Build Coastguard Worker result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
415*bebae9c0SAndroid Build Coastguard Worker assert(SL_RESULT_SUCCESS == result);
416*bebae9c0SAndroid Build Coastguard Worker
417*bebae9c0SAndroid Build Coastguard Worker // get the effect send interface and enable effect send reverb for this player
418*bebae9c0SAndroid Build Coastguard Worker if (enableReverb) {
419*bebae9c0SAndroid Build Coastguard Worker SLEffectSendItf playerEffectSend;
420*bebae9c0SAndroid Build Coastguard Worker result = (*playerObject)->GetInterface(playerObject, SL_IID_EFFECTSEND, &playerEffectSend);
421*bebae9c0SAndroid Build Coastguard Worker assert(SL_RESULT_SUCCESS == result);
422*bebae9c0SAndroid Build Coastguard Worker result = (*playerEffectSend)->EnableEffectSend(playerEffectSend, mixEnvironmentalReverb,
423*bebae9c0SAndroid Build Coastguard Worker SL_BOOLEAN_TRUE, (SLmillibel) 0);
424*bebae9c0SAndroid Build Coastguard Worker assert(SL_RESULT_SUCCESS == result);
425*bebae9c0SAndroid Build Coastguard Worker }
426*bebae9c0SAndroid Build Coastguard Worker
427*bebae9c0SAndroid Build Coastguard Worker // get the playback rate interface and configure the rate
428*bebae9c0SAndroid Build Coastguard Worker SLPlaybackRateItf playerPlaybackRate;
429*bebae9c0SAndroid Build Coastguard Worker SLpermille currentRate = 0;
430*bebae9c0SAndroid Build Coastguard Worker if (enablePlaybackRate) {
431*bebae9c0SAndroid Build Coastguard Worker result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAYBACKRATE,
432*bebae9c0SAndroid Build Coastguard Worker &playerPlaybackRate);
433*bebae9c0SAndroid Build Coastguard Worker assert(SL_RESULT_SUCCESS == result);
434*bebae9c0SAndroid Build Coastguard Worker SLpermille defaultRate;
435*bebae9c0SAndroid Build Coastguard Worker result = (*playerPlaybackRate)->GetRate(playerPlaybackRate, &defaultRate);
436*bebae9c0SAndroid Build Coastguard Worker assert(SL_RESULT_SUCCESS == result);
437*bebae9c0SAndroid Build Coastguard Worker SLuint32 defaultProperties;
438*bebae9c0SAndroid Build Coastguard Worker result = (*playerPlaybackRate)->GetProperties(playerPlaybackRate, &defaultProperties);
439*bebae9c0SAndroid Build Coastguard Worker assert(SL_RESULT_SUCCESS == result);
440*bebae9c0SAndroid Build Coastguard Worker printf("default playback rate %d per mille, properties 0x%x\n", defaultRate,
441*bebae9c0SAndroid Build Coastguard Worker defaultProperties);
442*bebae9c0SAndroid Build Coastguard Worker if (initialRate <= 0) {
443*bebae9c0SAndroid Build Coastguard Worker initialRate = defaultRate;
444*bebae9c0SAndroid Build Coastguard Worker }
445*bebae9c0SAndroid Build Coastguard Worker if (finalRate <= 0) {
446*bebae9c0SAndroid Build Coastguard Worker finalRate = initialRate;
447*bebae9c0SAndroid Build Coastguard Worker }
448*bebae9c0SAndroid Build Coastguard Worker currentRate = defaultRate;
449*bebae9c0SAndroid Build Coastguard Worker if (finalRate == initialRate) {
450*bebae9c0SAndroid Build Coastguard Worker deltaRate = 0;
451*bebae9c0SAndroid Build Coastguard Worker } else if (finalRate < initialRate) {
452*bebae9c0SAndroid Build Coastguard Worker deltaRate = -deltaRate;
453*bebae9c0SAndroid Build Coastguard Worker }
454*bebae9c0SAndroid Build Coastguard Worker if (initialRate != defaultRate) {
455*bebae9c0SAndroid Build Coastguard Worker result = (*playerPlaybackRate)->SetRate(playerPlaybackRate, initialRate);
456*bebae9c0SAndroid Build Coastguard Worker if (SL_RESULT_FEATURE_UNSUPPORTED == result) {
457*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "initial playback rate %d is unsupported\n", initialRate);
458*bebae9c0SAndroid Build Coastguard Worker deltaRate = 0;
459*bebae9c0SAndroid Build Coastguard Worker } else if (SL_RESULT_PARAMETER_INVALID == result) {
460*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "initial playback rate %d is invalid\n", initialRate);
461*bebae9c0SAndroid Build Coastguard Worker deltaRate = 0;
462*bebae9c0SAndroid Build Coastguard Worker } else {
463*bebae9c0SAndroid Build Coastguard Worker assert(SL_RESULT_SUCCESS == result);
464*bebae9c0SAndroid Build Coastguard Worker currentRate = initialRate;
465*bebae9c0SAndroid Build Coastguard Worker }
466*bebae9c0SAndroid Build Coastguard Worker }
467*bebae9c0SAndroid Build Coastguard Worker }
468*bebae9c0SAndroid Build Coastguard Worker
469*bebae9c0SAndroid Build Coastguard Worker // get the play interface
470*bebae9c0SAndroid Build Coastguard Worker SLPlayItf playerPlay;
471*bebae9c0SAndroid Build Coastguard Worker result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay);
472*bebae9c0SAndroid Build Coastguard Worker assert(SL_RESULT_SUCCESS == result);
473*bebae9c0SAndroid Build Coastguard Worker
474*bebae9c0SAndroid Build Coastguard Worker // get the buffer queue interface
475*bebae9c0SAndroid Build Coastguard Worker SLBufferQueueItf playerBufferQueue;
476*bebae9c0SAndroid Build Coastguard Worker result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE,
477*bebae9c0SAndroid Build Coastguard Worker &playerBufferQueue);
478*bebae9c0SAndroid Build Coastguard Worker assert(SL_RESULT_SUCCESS == result);
479*bebae9c0SAndroid Build Coastguard Worker
480*bebae9c0SAndroid Build Coastguard Worker // loop until EOF or no more buffers
481*bebae9c0SAndroid Build Coastguard Worker for (which = 0; which < numBuffers; ++which) {
482*bebae9c0SAndroid Build Coastguard Worker void *buffer = (char *)buffers + framesPerBuffer * sfframesize * which;
483*bebae9c0SAndroid Build Coastguard Worker sf_count_t frames = framesPerBuffer;
484*bebae9c0SAndroid Build Coastguard Worker sf_count_t count;
485*bebae9c0SAndroid Build Coastguard Worker switch (transferFormat) {
486*bebae9c0SAndroid Build Coastguard Worker case AUDIO_FORMAT_PCM_FLOAT:
487*bebae9c0SAndroid Build Coastguard Worker count = sf_readf_float(sndfile, (float *) buffer, frames);
488*bebae9c0SAndroid Build Coastguard Worker break;
489*bebae9c0SAndroid Build Coastguard Worker case AUDIO_FORMAT_PCM_32_BIT:
490*bebae9c0SAndroid Build Coastguard Worker count = sf_readf_int(sndfile, (int *) buffer, frames);
491*bebae9c0SAndroid Build Coastguard Worker break;
492*bebae9c0SAndroid Build Coastguard Worker case AUDIO_FORMAT_PCM_24_BIT_PACKED:
493*bebae9c0SAndroid Build Coastguard Worker count = sf_readf_int(sndfile, (int *) buffer, frames);
494*bebae9c0SAndroid Build Coastguard Worker break;
495*bebae9c0SAndroid Build Coastguard Worker case AUDIO_FORMAT_PCM_16_BIT:
496*bebae9c0SAndroid Build Coastguard Worker case AUDIO_FORMAT_PCM_8_BIT:
497*bebae9c0SAndroid Build Coastguard Worker count = sf_readf_short(sndfile, (short *) buffer, frames);
498*bebae9c0SAndroid Build Coastguard Worker break;
499*bebae9c0SAndroid Build Coastguard Worker default:
500*bebae9c0SAndroid Build Coastguard Worker count = 0;
501*bebae9c0SAndroid Build Coastguard Worker break;
502*bebae9c0SAndroid Build Coastguard Worker }
503*bebae9c0SAndroid Build Coastguard Worker if (0 >= count) {
504*bebae9c0SAndroid Build Coastguard Worker eof = SL_BOOLEAN_TRUE;
505*bebae9c0SAndroid Build Coastguard Worker break;
506*bebae9c0SAndroid Build Coastguard Worker }
507*bebae9c0SAndroid Build Coastguard Worker
508*bebae9c0SAndroid Build Coastguard Worker // enqueue a buffer
509*bebae9c0SAndroid Build Coastguard Worker SLuint32 nbytes = count * sfframesize;
510*bebae9c0SAndroid Build Coastguard Worker nbytes = squeeze(buffer, nbytes);
511*bebae9c0SAndroid Build Coastguard Worker result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, nbytes);
512*bebae9c0SAndroid Build Coastguard Worker assert(SL_RESULT_SUCCESS == result);
513*bebae9c0SAndroid Build Coastguard Worker }
514*bebae9c0SAndroid Build Coastguard Worker if (which >= numBuffers) {
515*bebae9c0SAndroid Build Coastguard Worker which = 0;
516*bebae9c0SAndroid Build Coastguard Worker }
517*bebae9c0SAndroid Build Coastguard Worker
518*bebae9c0SAndroid Build Coastguard Worker // register a callback on the buffer queue
519*bebae9c0SAndroid Build Coastguard Worker result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, callback, NULL);
520*bebae9c0SAndroid Build Coastguard Worker assert(SL_RESULT_SUCCESS == result);
521*bebae9c0SAndroid Build Coastguard Worker
522*bebae9c0SAndroid Build Coastguard Worker #define FIFO_FRAMES 16384
523*bebae9c0SAndroid Build Coastguard Worker void *fifoBuffer = malloc(FIFO_FRAMES * sfframesize);
524*bebae9c0SAndroid Build Coastguard Worker fifo = new audio_utils_fifo(FIFO_FRAMES, sfframesize, fifoBuffer);
525*bebae9c0SAndroid Build Coastguard Worker fifoReader = new audio_utils_fifo_reader(*fifo, true /*throttlesWriter*/);
526*bebae9c0SAndroid Build Coastguard Worker fifoWriter = new audio_utils_fifo_writer(*fifo);
527*bebae9c0SAndroid Build Coastguard Worker
528*bebae9c0SAndroid Build Coastguard Worker // create thread to read from file
529*bebae9c0SAndroid Build Coastguard Worker pthread_t thread;
530*bebae9c0SAndroid Build Coastguard Worker int ok = pthread_create(&thread, (const pthread_attr_t *) NULL, file_reader_loop, NULL);
531*bebae9c0SAndroid Build Coastguard Worker assert(0 == ok);
532*bebae9c0SAndroid Build Coastguard Worker
533*bebae9c0SAndroid Build Coastguard Worker // give thread a head start so that the pipe is initially filled
534*bebae9c0SAndroid Build Coastguard Worker sleep(1);
535*bebae9c0SAndroid Build Coastguard Worker
536*bebae9c0SAndroid Build Coastguard Worker // set the player's state to playing
537*bebae9c0SAndroid Build Coastguard Worker result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
538*bebae9c0SAndroid Build Coastguard Worker assert(SL_RESULT_SUCCESS == result);
539*bebae9c0SAndroid Build Coastguard Worker
540*bebae9c0SAndroid Build Coastguard Worker // get the initial time
541*bebae9c0SAndroid Build Coastguard Worker struct timespec prevTs;
542*bebae9c0SAndroid Build Coastguard Worker clock_gettime(CLOCK_MONOTONIC, &prevTs);
543*bebae9c0SAndroid Build Coastguard Worker long elapsedNs = 0;
544*bebae9c0SAndroid Build Coastguard Worker long deltaRateNs = deltaRateMs * 1000000;
545*bebae9c0SAndroid Build Coastguard Worker
546*bebae9c0SAndroid Build Coastguard Worker // wait until the buffer queue is empty
547*bebae9c0SAndroid Build Coastguard Worker SLBufferQueueState bufqstate;
548*bebae9c0SAndroid Build Coastguard Worker for (;;) {
549*bebae9c0SAndroid Build Coastguard Worker result = (*playerBufferQueue)->GetState(playerBufferQueue, &bufqstate);
550*bebae9c0SAndroid Build Coastguard Worker assert(SL_RESULT_SUCCESS == result);
551*bebae9c0SAndroid Build Coastguard Worker if (0 >= bufqstate.count) {
552*bebae9c0SAndroid Build Coastguard Worker break;
553*bebae9c0SAndroid Build Coastguard Worker }
554*bebae9c0SAndroid Build Coastguard Worker if (!enablePlaybackRate || deltaRate == 0) {
555*bebae9c0SAndroid Build Coastguard Worker sleep(1);
556*bebae9c0SAndroid Build Coastguard Worker } else {
557*bebae9c0SAndroid Build Coastguard Worker struct timespec curTs;
558*bebae9c0SAndroid Build Coastguard Worker clock_gettime(CLOCK_MONOTONIC, &curTs);
559*bebae9c0SAndroid Build Coastguard Worker elapsedNs += (curTs.tv_sec - prevTs.tv_sec) * 1000000000 +
560*bebae9c0SAndroid Build Coastguard Worker // this term can be negative
561*bebae9c0SAndroid Build Coastguard Worker (curTs.tv_nsec - prevTs.tv_nsec);
562*bebae9c0SAndroid Build Coastguard Worker prevTs = curTs;
563*bebae9c0SAndroid Build Coastguard Worker if (elapsedNs < deltaRateNs) {
564*bebae9c0SAndroid Build Coastguard Worker usleep((deltaRateNs - elapsedNs) / 1000);
565*bebae9c0SAndroid Build Coastguard Worker continue;
566*bebae9c0SAndroid Build Coastguard Worker }
567*bebae9c0SAndroid Build Coastguard Worker elapsedNs -= deltaRateNs;
568*bebae9c0SAndroid Build Coastguard Worker SLpermille nextRate = currentRate + deltaRate;
569*bebae9c0SAndroid Build Coastguard Worker result = (*playerPlaybackRate)->SetRate(playerPlaybackRate, nextRate);
570*bebae9c0SAndroid Build Coastguard Worker if (SL_RESULT_SUCCESS != result) {
571*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "next playback rate %d is unsupported\n", nextRate);
572*bebae9c0SAndroid Build Coastguard Worker } else if (SL_RESULT_PARAMETER_INVALID == result) {
573*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "next playback rate %d is invalid\n", nextRate);
574*bebae9c0SAndroid Build Coastguard Worker } else {
575*bebae9c0SAndroid Build Coastguard Worker assert(SL_RESULT_SUCCESS == result);
576*bebae9c0SAndroid Build Coastguard Worker }
577*bebae9c0SAndroid Build Coastguard Worker currentRate = nextRate;
578*bebae9c0SAndroid Build Coastguard Worker if (currentRate >= max(initialRate, finalRate)) {
579*bebae9c0SAndroid Build Coastguard Worker currentRate = max(initialRate, finalRate);
580*bebae9c0SAndroid Build Coastguard Worker deltaRate = -abs(deltaRate);
581*bebae9c0SAndroid Build Coastguard Worker } else if (currentRate <= min(initialRate, finalRate)) {
582*bebae9c0SAndroid Build Coastguard Worker currentRate = min(initialRate, finalRate);
583*bebae9c0SAndroid Build Coastguard Worker deltaRate = abs(deltaRate);
584*bebae9c0SAndroid Build Coastguard Worker }
585*bebae9c0SAndroid Build Coastguard Worker }
586*bebae9c0SAndroid Build Coastguard Worker
587*bebae9c0SAndroid Build Coastguard Worker }
588*bebae9c0SAndroid Build Coastguard Worker
589*bebae9c0SAndroid Build Coastguard Worker // wait for reader thread to exit
590*bebae9c0SAndroid Build Coastguard Worker ok = pthread_join(thread, (void **) NULL);
591*bebae9c0SAndroid Build Coastguard Worker assert(0 == ok);
592*bebae9c0SAndroid Build Coastguard Worker
593*bebae9c0SAndroid Build Coastguard Worker // set the player's state to stopped
594*bebae9c0SAndroid Build Coastguard Worker result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_STOPPED);
595*bebae9c0SAndroid Build Coastguard Worker assert(SL_RESULT_SUCCESS == result);
596*bebae9c0SAndroid Build Coastguard Worker
597*bebae9c0SAndroid Build Coastguard Worker // destroy audio player
598*bebae9c0SAndroid Build Coastguard Worker (*playerObject)->Destroy(playerObject);
599*bebae9c0SAndroid Build Coastguard Worker
600*bebae9c0SAndroid Build Coastguard Worker delete fifoWriter;
601*bebae9c0SAndroid Build Coastguard Worker fifoWriter = NULL;
602*bebae9c0SAndroid Build Coastguard Worker delete fifoReader;
603*bebae9c0SAndroid Build Coastguard Worker fifoReader = NULL;
604*bebae9c0SAndroid Build Coastguard Worker delete fifo;
605*bebae9c0SAndroid Build Coastguard Worker fifo = NULL;
606*bebae9c0SAndroid Build Coastguard Worker free(fifoBuffer);
607*bebae9c0SAndroid Build Coastguard Worker fifoBuffer = NULL;
608*bebae9c0SAndroid Build Coastguard Worker
609*bebae9c0SAndroid Build Coastguard Worker }
610*bebae9c0SAndroid Build Coastguard Worker
611*bebae9c0SAndroid Build Coastguard Worker no_player:
612*bebae9c0SAndroid Build Coastguard Worker
613*bebae9c0SAndroid Build Coastguard Worker // destroy output mix
614*bebae9c0SAndroid Build Coastguard Worker (*outputMixObject)->Destroy(outputMixObject);
615*bebae9c0SAndroid Build Coastguard Worker
616*bebae9c0SAndroid Build Coastguard Worker // destroy engine
617*bebae9c0SAndroid Build Coastguard Worker (*engineObject)->Destroy(engineObject);
618*bebae9c0SAndroid Build Coastguard Worker
619*bebae9c0SAndroid Build Coastguard Worker }
620*bebae9c0SAndroid Build Coastguard Worker
621*bebae9c0SAndroid Build Coastguard Worker close_sndfile:
622*bebae9c0SAndroid Build Coastguard Worker
623*bebae9c0SAndroid Build Coastguard Worker (void) sf_close(sndfile);
624*bebae9c0SAndroid Build Coastguard Worker
625*bebae9c0SAndroid Build Coastguard Worker return EXIT_SUCCESS;
626*bebae9c0SAndroid Build Coastguard Worker }
627