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