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
38unsigned numBuffers = 2;
39int framesPerBuffer = 512;
40SNDFILE *sndfile;
41SF_INFO sfinfo;
42unsigned which; // which buffer to use next
43SLboolean eof;  // whether we have hit EOF on input yet
44void *buffers;
45SLuint32 byteOrder; // desired to use for PCM buffers
46SLuint32 nativeByteOrder;   // of platform
47audio_format_t transferFormat = AUDIO_FORMAT_DEFAULT;
48size_t sfframesize = 0;
49
50static audio_utils_fifo *fifo;
51static audio_utils_fifo_reader *fifoReader;
52static audio_utils_fifo_writer *fifoWriter;
53static unsigned underruns = 0;
54
55static 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
75static 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
100static 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
151int 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
611no_player:
612
613    // destroy output mix
614    (*outputMixObject)->Destroy(outputMixObject);
615
616    // destroy engine
617    (*engineObject)->Destroy(engineObject);
618
619    }
620
621close_sndfile:
622
623    (void) sf_close(sndfile);
624
625    return EXIT_SUCCESS;
626}
627