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