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