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