playbq.c revision c323fec2a2639c0cf7463016d592d0eb0539657c
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#ifdef ANDROID
30#include <audio_utils/sndfile.h>
31#else
32#include <sndfile.h>
33#endif
34
35#include <media/nbaio/MonoPipe.h>
36#include <media/nbaio/MonoPipeReader.h>
37
38#define max(a, b) ((a) > (b) ? (a) : (b))
39#define min(a, b) ((a) < (b) ? (a) : (b))
40
41unsigned numBuffers = 2;
42int framesPerBuffer = 512;
43SNDFILE *sndfile;
44SF_INFO sfinfo;
45unsigned which; // which buffer to use next
46SLboolean eof;  // whether we have hit EOF on input yet
47void *buffers;
48SLuint32 byteOrder; // desired to use for PCM buffers
49SLuint32 nativeByteOrder;   // of platform
50audio_format_t transferFormat = AUDIO_FORMAT_PCM_16_BIT;
51size_t sfframesize = 0;
52
53// swap adjacent bytes; this would normally be in <unistd.h> but is missing here
54static void swab(const void *from, void *to, ssize_t n)
55{
56    // from and to as char pointers
57    const char *from_ch = (const char *) from;
58    char *to_ch = (char *) to;
59    // note that we don't swap the last odd byte
60    while (n >= 2) {
61        to_ch[0] = from_ch[1];
62        to_ch[1] = from_ch[0];
63        to_ch += 2;
64        from_ch += 2;
65        n -= 2;
66    }
67}
68
69// squeeze 16-bit signed PCM samples down to 8-bit unsigned PCM samples by truncation; no dithering
70static void squeeze(const short *from, unsigned char *to, ssize_t n)
71{
72    // note that we don't squeeze the last odd byte
73    while (n >= 2) {
74        *to++ = (*from++ + 32768) >> 8;
75        n -= 2;
76    }
77}
78
79// squeeze 32-bit signed PCM samples down to 24-bit unsigned PCM samples by truncation
80static void squeeze24(const unsigned char *from, unsigned char *to, ssize_t n)
81{
82    // note that we don't squeeze the last odd bytes
83    while (n >= 3) {
84        ++from;
85        *to++ = *from++;
86        *to++ = *from++;
87        *to++ = *from++;
88        n -= 4;
89    }
90}
91
92static android::MonoPipeReader *pipeReader;
93static android::MonoPipe *pipeWriter;
94static unsigned underruns = 0;
95
96// This callback is called each time a buffer finishes playing
97
98static void callback(SLBufferQueueItf bufq, void *param)
99{
100    assert(NULL == param);
101    if (!eof) {
102        void *buffer = (char *)buffers + framesPerBuffer * sfframesize * which;
103        ssize_t count = pipeReader->read(buffer, framesPerBuffer, (int64_t) -1);
104        // on underrun from pipe, substitute silence
105        if (0 >= count) {
106            memset(buffer, 0, framesPerBuffer * sfframesize);
107            count = framesPerBuffer;
108            ++underruns;
109        }
110        if (count > 0) {
111            SLuint32 nbytes = count * sfframesize;
112            if (byteOrder != nativeByteOrder) {
113                swab(buffer, buffer, nbytes);
114            }
115            if (transferFormat == AUDIO_FORMAT_PCM_8_BIT) {
116                squeeze((short *) buffer, (unsigned char *) buffer, nbytes);
117                nbytes /= 2;
118            } else if (transferFormat == AUDIO_FORMAT_PCM_24_BIT_PACKED) {
119                squeeze24((unsigned char *) buffer, (unsigned char *) buffer, nbytes);
120                nbytes = nbytes * 3 / 4;
121            }
122            SLresult result = (*bufq)->Enqueue(bufq, buffer, nbytes);
123            assert(SL_RESULT_SUCCESS == result);
124            if (++which >= numBuffers)
125                which = 0;
126        }
127    }
128}
129
130// This thread reads from a (slow) filesystem with unpredictable latency and writes to pipe
131
132static void *file_reader_loop(void *arg __unused)
133{
134#define READ_FRAMES 256
135    void *temp = malloc(READ_FRAMES * sfframesize);
136    sf_count_t total = 0;
137    sf_count_t count;
138    for (;;) {
139        switch (transferFormat) {
140        case AUDIO_FORMAT_PCM_FLOAT:
141            count = sf_readf_float(sndfile, (float *) temp, READ_FRAMES);
142            break;
143        case AUDIO_FORMAT_PCM_32_BIT:
144        case AUDIO_FORMAT_PCM_24_BIT_PACKED:
145            count = sf_readf_int(sndfile, (int *) temp, READ_FRAMES);
146            break;
147        case AUDIO_FORMAT_PCM_16_BIT:
148        case AUDIO_FORMAT_PCM_8_BIT:
149            count = sf_readf_short(sndfile, (short *) temp, READ_FRAMES);
150            break;
151        default:
152            count = 0;
153            break;
154        }
155        if (0 >= count) {
156            eof = SL_BOOLEAN_TRUE;
157            break;
158        }
159        const unsigned char *ptr = (unsigned char *) temp;
160        while (count > 0) {
161            ssize_t actual = pipeWriter->write(ptr, (size_t) count);
162            if (actual < 0) {
163                break;
164            }
165            if ((sf_count_t) actual < count) {
166                usleep(10000);
167            }
168            ptr += actual * sfframesize;
169            count -= actual;
170            total += actual;
171        }
172        // simulate occasional filesystem latency
173        if ((total & 0xFF00) == 0xFF00) {
174            usleep(100000);
175        }
176    }
177    free(temp);
178    return NULL;
179}
180
181// Main program
182
183int main(int argc, char **argv)
184{
185    // Determine the native byte order (SL_BYTEORDER_NATIVE not available until 1.1)
186    union {
187        short s;
188        char c[2];
189    } u;
190    u.s = 0x1234;
191    if (u.c[0] == 0x34) {
192        nativeByteOrder = SL_BYTEORDER_LITTLEENDIAN;
193    } else if (u.c[0] == 0x12) {
194        nativeByteOrder = SL_BYTEORDER_BIGENDIAN;
195    } else {
196        fprintf(stderr, "Unable to determine native byte order\n");
197        return EXIT_FAILURE;
198    }
199    byteOrder = nativeByteOrder;
200
201    SLboolean enableReverb = SL_BOOLEAN_FALSE;
202    SLboolean enablePlaybackRate = SL_BOOLEAN_FALSE;
203    SLpermille initialRate = 0;
204    SLpermille finalRate = 0;
205    SLpermille deltaRate = 1;
206    SLmillisecond deltaRateMs = 0;
207
208    // process command-line options
209    int i;
210    for (i = 1; i < argc; ++i) {
211        char *arg = argv[i];
212        if (arg[0] != '-') {
213            break;
214        }
215        if (!strcmp(arg, "-b")) {
216            byteOrder = SL_BYTEORDER_BIGENDIAN;
217        } else if (!strcmp(arg, "-l")) {
218            byteOrder = SL_BYTEORDER_LITTLEENDIAN;
219        } else if (!strcmp(arg, "-8")) {
220            transferFormat = AUDIO_FORMAT_PCM_8_BIT;
221        } else if (!strcmp(arg, "-24")) {
222            transferFormat = AUDIO_FORMAT_PCM_24_BIT_PACKED;
223        } else if (!strcmp(arg, "-32")) {
224            transferFormat = AUDIO_FORMAT_PCM_32_BIT;
225        } else if (!strncmp(arg, "-f", 2)) {
226            framesPerBuffer = atoi(&arg[2]);
227        } else if (!strncmp(arg, "-n", 2)) {
228            numBuffers = atoi(&arg[2]);
229        } else if (!strncmp(arg, "-p", 2)) {
230            initialRate = atoi(&arg[2]);
231            enablePlaybackRate = SL_BOOLEAN_TRUE;
232        } else if (!strncmp(arg, "-P", 2)) {
233            finalRate = atoi(&arg[2]);
234            enablePlaybackRate = SL_BOOLEAN_TRUE;
235        } else if (!strncmp(arg, "-q", 2)) {
236            deltaRate = atoi(&arg[2]);
237            // deltaRate is a magnitude, so take absolute value
238            if (deltaRate < 0) {
239                deltaRate = -deltaRate;
240            }
241            enablePlaybackRate = SL_BOOLEAN_TRUE;
242        } else if (!strncmp(arg, "-Q", 2)) {
243            deltaRateMs = atoi(&arg[2]);
244            enablePlaybackRate = SL_BOOLEAN_TRUE;
245        } else if (!strcmp(arg, "-r")) {
246            enableReverb = SL_BOOLEAN_TRUE;
247        } else {
248            fprintf(stderr, "option %s ignored\n", arg);
249        }
250    }
251
252    if (argc - i != 1) {
253        fprintf(stderr, "usage: [-b/l] [-8 | -24 | -32] [-f#] [-n#] [-p#] [-r]"
254                " %s filename\n", argv[0]);
255        fprintf(stderr, "    -b  force big-endian byte order (default is native byte order)\n");
256        fprintf(stderr, "    -l  force little-endian byte order (default is native byte order)\n");
257        fprintf(stderr, "    -8  output 8-bits per sample (default is 16-bits per sample)\n");
258        fprintf(stderr, "    -24 output 24-bits per sample\n");
259        fprintf(stderr, "    -32 output 32-bits per sample\n");
260        fprintf(stderr, "    -f# frames per buffer (default 512)\n");
261        fprintf(stderr, "    -n# number of buffers (default 2)\n");
262        fprintf(stderr, "    -p# initial playback rate in per mille (default 1000)\n");
263        fprintf(stderr, "    -P# final playback rate in per mille (default same as -p#)\n");
264        fprintf(stderr, "    -q# magnitude of playback rate changes in per mille (default 1)\n");
265        fprintf(stderr, "    -Q# period between playback rate changes in ms (default 50)\n");
266        fprintf(stderr, "    -r  enable reverb (default disabled)\n");
267        return EXIT_FAILURE;
268    }
269
270    const char *filename = argv[i];
271    //memset(&sfinfo, 0, sizeof(SF_INFO));
272    sfinfo.format = 0;
273    sndfile = sf_open(filename, SFM_READ, &sfinfo);
274    if (NULL == sndfile) {
275        perror(filename);
276        return EXIT_FAILURE;
277    }
278
279    // verify the file format
280    switch (sfinfo.channels) {
281    case 1:
282    case 2:
283        break;
284    default:
285        fprintf(stderr, "unsupported channel count %d\n", sfinfo.channels);
286        goto close_sndfile;
287    }
288
289    switch (sfinfo.samplerate) {
290    case  8000:
291    case 11025:
292    case 12000:
293    case 16000:
294    case 22050:
295    case 24000:
296    case 32000:
297    case 44100:
298    case 48000:
299        break;
300    default:
301        fprintf(stderr, "unsupported sample rate %d\n", sfinfo.samplerate);
302        goto close_sndfile;
303    }
304
305    switch (sfinfo.format & SF_FORMAT_TYPEMASK) {
306    case SF_FORMAT_WAV:
307        break;
308    default:
309        fprintf(stderr, "unsupported format type 0x%x\n", sfinfo.format & SF_FORMAT_TYPEMASK);
310        goto close_sndfile;
311    }
312
313    switch (sfinfo.format & SF_FORMAT_SUBMASK) {
314    case SF_FORMAT_FLOAT:
315    case SF_FORMAT_PCM_32:
316    case SF_FORMAT_PCM_16:
317    case SF_FORMAT_PCM_U8:
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    SLDataFormat_PCM format_pcm;
392    format_pcm.formatType = SL_DATAFORMAT_PCM;
393    format_pcm.numChannels = sfinfo.channels;
394    format_pcm.samplesPerSec = sfinfo.samplerate * 1000;
395    format_pcm.bitsPerSample = bitsPerSample;
396    format_pcm.containerSize = format_pcm.bitsPerSample;
397    format_pcm.channelMask = 1 == format_pcm.numChannels ? SL_SPEAKER_FRONT_CENTER :
398            SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
399    format_pcm.endianness = byteOrder;
400    SLDataSource audioSrc;
401    audioSrc.pLocator = &loc_bufq;
402    audioSrc.pFormat = &format_pcm;
403
404    // configure audio sink
405    SLDataLocator_OutputMix loc_outmix;
406    loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
407    loc_outmix.outputMix = outputMixObject;
408    SLDataSink audioSnk;
409    audioSnk.pLocator = &loc_outmix;
410    audioSnk.pFormat = NULL;
411
412    // create audio player
413    SLInterfaceID ids2[3] = {SL_IID_BUFFERQUEUE, SL_IID_PLAYBACKRATE, SL_IID_EFFECTSEND};
414    SLboolean req2[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
415    SLObjectItf playerObject;
416    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audioSrc,
417            &audioSnk, enableReverb ? 3 : (enablePlaybackRate ? 2 : 1), ids2, req2);
418    if (SL_RESULT_SUCCESS != result) {
419        fprintf(stderr, "can't create audio player\n");
420        goto no_player;
421    }
422
423    {
424
425    // realize the player
426    result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
427    assert(SL_RESULT_SUCCESS == result);
428
429    // get the effect send interface and enable effect send reverb for this player
430    if (enableReverb) {
431        SLEffectSendItf playerEffectSend;
432        result = (*playerObject)->GetInterface(playerObject, SL_IID_EFFECTSEND, &playerEffectSend);
433        assert(SL_RESULT_SUCCESS == result);
434        result = (*playerEffectSend)->EnableEffectSend(playerEffectSend, mixEnvironmentalReverb,
435                SL_BOOLEAN_TRUE, (SLmillibel) 0);
436        assert(SL_RESULT_SUCCESS == result);
437    }
438
439    // get the playback rate interface and configure the rate
440    SLPlaybackRateItf playerPlaybackRate;
441    SLpermille currentRate = 0;
442    if (enablePlaybackRate) {
443        result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAYBACKRATE,
444                &playerPlaybackRate);
445        assert(SL_RESULT_SUCCESS == result);
446        SLpermille defaultRate;
447        result = (*playerPlaybackRate)->GetRate(playerPlaybackRate, &defaultRate);
448        assert(SL_RESULT_SUCCESS == result);
449        SLuint32 defaultProperties;
450        result = (*playerPlaybackRate)->GetProperties(playerPlaybackRate, &defaultProperties);
451        assert(SL_RESULT_SUCCESS == result);
452        printf("default playback rate %d per mille, properties 0x%x\n", defaultRate,
453                defaultProperties);
454        if (initialRate <= 0) {
455            initialRate = defaultRate;
456        }
457        if (finalRate <= 0) {
458            finalRate = initialRate;
459        }
460        currentRate = defaultRate;
461        if (finalRate == initialRate) {
462            deltaRate = 0;
463        } else if (finalRate < initialRate) {
464            deltaRate = -deltaRate;
465        }
466        if (initialRate != defaultRate) {
467            result = (*playerPlaybackRate)->SetRate(playerPlaybackRate, initialRate);
468            if (SL_RESULT_FEATURE_UNSUPPORTED == result) {
469                fprintf(stderr, "initial playback rate %d is unsupported\n", initialRate);
470                deltaRate = 0;
471            } else if (SL_RESULT_PARAMETER_INVALID == result) {
472                fprintf(stderr, "initial playback rate %d is invalid\n", initialRate);
473                deltaRate = 0;
474            } else {
475                assert(SL_RESULT_SUCCESS == result);
476                currentRate = initialRate;
477            }
478        }
479    }
480
481    // get the play interface
482    SLPlayItf playerPlay;
483    result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay);
484    assert(SL_RESULT_SUCCESS == result);
485
486    // get the buffer queue interface
487    SLBufferQueueItf playerBufferQueue;
488    result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE,
489            &playerBufferQueue);
490    assert(SL_RESULT_SUCCESS == result);
491
492    // loop until EOF or no more buffers
493    for (which = 0; which < numBuffers; ++which) {
494        void *buffer = (char *)buffers + framesPerBuffer * sfframesize * which;
495        sf_count_t frames = framesPerBuffer;
496        sf_count_t count;
497        switch (transferFormat) {
498        case AUDIO_FORMAT_PCM_FLOAT:
499            count = sf_readf_float(sndfile, (float *) buffer, frames);
500            break;
501        case AUDIO_FORMAT_PCM_32_BIT:
502            count = sf_readf_int(sndfile, (int *) buffer, frames);
503            break;
504        case AUDIO_FORMAT_PCM_24_BIT_PACKED:
505            count = sf_readf_int(sndfile, (int *) buffer, frames);
506            break;
507        case AUDIO_FORMAT_PCM_16_BIT:
508        case AUDIO_FORMAT_PCM_8_BIT:
509            count = sf_readf_short(sndfile, (short *) buffer, frames);
510            break;
511        default:
512            count = 0;
513            break;
514        }
515        if (0 >= count) {
516            eof = SL_BOOLEAN_TRUE;
517            break;
518        }
519
520        // enqueue a buffer
521        SLuint32 nbytes = count * sfframesize;
522        if (byteOrder != nativeByteOrder) {
523            swab(buffer, buffer, nbytes);
524        }
525        if (transferFormat == AUDIO_FORMAT_PCM_8_BIT) {
526            squeeze((short *) buffer, (unsigned char *) buffer, nbytes);
527            nbytes /= 2;
528        } else if (transferFormat == AUDIO_FORMAT_PCM_24_BIT_PACKED) {
529            squeeze24((unsigned char *) buffer, (unsigned char *) buffer, nbytes);
530            nbytes = nbytes * 3 / 4;
531        }
532        result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, nbytes);
533        assert(SL_RESULT_SUCCESS == result);
534    }
535    if (which >= numBuffers) {
536        which = 0;
537    }
538
539    // register a callback on the buffer queue
540    result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, callback, NULL);
541    assert(SL_RESULT_SUCCESS == result);
542
543    // Create a NBAIO pipe for asynchronous data handling.  In this case,
544    // sample rate doesn't matter and audio_format just sets the transfer frame size.
545    const android::NBAIO_Format nbaio_format = android::Format_from_SR_C(
546            sfinfo.samplerate, sfinfo.channels,
547            transferFormat == AUDIO_FORMAT_PCM_8_BIT ? AUDIO_FORMAT_PCM_16_BIT :
548                    transferFormat == AUDIO_FORMAT_PCM_24_BIT_PACKED ?
549                            AUDIO_FORMAT_PCM_32_BIT : transferFormat);
550    pipeWriter = new android::MonoPipe(16384, nbaio_format, false /*writeCanBlock*/);
551    android::NBAIO_Format offer = nbaio_format;
552    size_t numCounterOffers = 0;
553    ssize_t neg = pipeWriter->negotiate(&offer, 1, NULL, numCounterOffers);
554    assert(0 == neg);
555    pipeReader = new android::MonoPipeReader(pipeWriter);
556    numCounterOffers = 0;
557    neg = pipeReader->negotiate(&offer, 1, NULL, numCounterOffers);
558    assert(0 == neg);
559
560    // create thread to read from file
561    pthread_t thread;
562    int ok = pthread_create(&thread, (const pthread_attr_t *) NULL, file_reader_loop, NULL);
563    assert(0 == ok);
564
565    // give thread a head start so that the pipe is initially filled
566    sleep(1);
567
568    // set the player's state to playing
569    result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
570    assert(SL_RESULT_SUCCESS == result);
571
572    // get the initial time
573    struct timespec prevTs;
574    clock_gettime(CLOCK_MONOTONIC, &prevTs);
575    long elapsedNs = 0;
576    long deltaRateNs = deltaRateMs * 1000000;
577
578    // wait until the buffer queue is empty
579    SLBufferQueueState bufqstate;
580    for (;;) {
581        result = (*playerBufferQueue)->GetState(playerBufferQueue, &bufqstate);
582        assert(SL_RESULT_SUCCESS == result);
583        if (0 >= bufqstate.count) {
584            break;
585        }
586        if (!enablePlaybackRate || deltaRate == 0) {
587            sleep(1);
588        } else {
589            struct timespec curTs;
590            clock_gettime(CLOCK_MONOTONIC, &curTs);
591            elapsedNs += (curTs.tv_sec - prevTs.tv_sec) * 1000000000 +
592                    // this term can be negative
593                    (curTs.tv_nsec - prevTs.tv_nsec);
594            prevTs = curTs;
595            if (elapsedNs < deltaRateNs) {
596                usleep((deltaRateNs - elapsedNs) / 1000);
597                continue;
598            }
599            elapsedNs -= deltaRateNs;
600            SLpermille nextRate = currentRate + deltaRate;
601            result = (*playerPlaybackRate)->SetRate(playerPlaybackRate, nextRate);
602            if (SL_RESULT_SUCCESS != result) {
603                fprintf(stderr, "next playback rate %d is unsupported\n", nextRate);
604            } else if (SL_RESULT_PARAMETER_INVALID == result) {
605                fprintf(stderr, "next playback rate %d is invalid\n", nextRate);
606            } else {
607                assert(SL_RESULT_SUCCESS == result);
608            }
609            currentRate = nextRate;
610            if (currentRate >= max(initialRate, finalRate)) {
611                currentRate = max(initialRate, finalRate);
612                deltaRate = -abs(deltaRate);
613            } else if (currentRate <= min(initialRate, finalRate)) {
614                currentRate = min(initialRate, finalRate);
615                deltaRate = abs(deltaRate);
616            }
617        }
618    }
619
620    // destroy audio player
621    (*playerObject)->Destroy(playerObject);
622
623    }
624
625no_player:
626
627    // destroy output mix
628    (*outputMixObject)->Destroy(outputMixObject);
629
630    // destroy engine
631    (*engineObject)->Destroy(engineObject);
632
633    }
634
635close_sndfile:
636
637    (void) sf_close(sndfile);
638
639    return EXIT_SUCCESS;
640}
641