15bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten/* 25bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten * Copyright (C) 2010 The Android Open Source Project 35bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten * 45bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten * Licensed under the Apache License, Version 2.0 (the "License"); 55bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten * you may not use this file except in compliance with the License. 65bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten * You may obtain a copy of the License at 75bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten * 85bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten * http://www.apache.org/licenses/LICENSE-2.0 95bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten * 105bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten * Unless required by applicable law or agreed to in writing, software 115bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten * distributed under the License is distributed on an "AS IS" BASIS, 125bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten * See the License for the specific language governing permissions and 145bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten * limitations under the License. 155bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten */ 165bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 175bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten// Play an audio file using buffer queue 185bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 195bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <assert.h> 205bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <math.h> 215bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <pthread.h> 225bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <stdio.h> 235bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <stdlib.h> 245bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <string.h> 255bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <time.h> 265bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <unistd.h> 275bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 285bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <SLES/OpenSLES.h> 295bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <SLES/OpenSLES_Android.h> 305bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <system/audio.h> 315bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <audio_utils/fifo.h> 325bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <audio_utils/primitives.h> 335bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#include <audio_utils/sndfile.h> 345bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 355bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#define max(a, b) ((a) > (b) ? (a) : (b)) 365bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#define min(a, b) ((a) < (b) ? (a) : (b)) 375bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 385bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastenunsigned numBuffers = 2; 395bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastenint framesPerBuffer = 512; 405bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn KastenSNDFILE *sndfile; 415bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn KastenSF_INFO sfinfo; 425bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastenunsigned which; // which buffer to use next 435bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn KastenSLboolean eof; // whether we have hit EOF on input yet 445bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastenvoid *buffers; 455bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn KastenSLuint32 byteOrder; // desired to use for PCM buffers 465bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn KastenSLuint32 nativeByteOrder; // of platform 475bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastenaudio_format_t transferFormat = AUDIO_FORMAT_DEFAULT; 485bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastensize_t sfframesize = 0; 495bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 50add2a2112de08f840459de78e8f8eb16d8c888c3Glenn Kastenstatic audio_utils_fifo *fifo; 5113e4fe3294ea101738253c72a3382101918d5682Glenn Kastenstatic audio_utils_fifo_reader *fifoReader; 5213e4fe3294ea101738253c72a3382101918d5682Glenn Kastenstatic audio_utils_fifo_writer *fifoWriter; 535bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastenstatic unsigned underruns = 0; 545bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 555bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastenstatic SLuint32 squeeze(void *buffer, SLuint32 nbytes) 565bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten{ 575bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (byteOrder != nativeByteOrder) { 585bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // FIXME does not work for non 16-bit 595bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten swab(buffer, buffer, nbytes); 605bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 615bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (transferFormat == AUDIO_FORMAT_PCM_8_BIT) { 625bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten memcpy_to_u8_from_i16((uint8_t *) buffer, (const int16_t *) buffer, 635bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten nbytes / sizeof(int16_t)); 645bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten nbytes /= 2; 655bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } else if (transferFormat == AUDIO_FORMAT_PCM_24_BIT_PACKED) { 665bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten memcpy_to_p24_from_i32((uint8_t *) buffer, (const int32_t *) buffer, 675bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten nbytes / sizeof(int32_t)); 685bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten nbytes = nbytes * 3 / 4; 695bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 705bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten return nbytes; 715bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten} 725bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 735bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten// This callback is called each time a buffer finishes playing 745bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 755bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastenstatic void callback(SLBufferQueueItf bufq, void *param) 765bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten{ 775bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(NULL == param); 785bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (!eof) { 795bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten void *buffer = (char *)buffers + framesPerBuffer * sfframesize * which; 8013e4fe3294ea101738253c72a3382101918d5682Glenn Kasten ssize_t count = fifoReader->read(buffer, framesPerBuffer); 815bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // on underrun from pipe, substitute silence 825bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (0 >= count) { 835bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten memset(buffer, 0, framesPerBuffer * sfframesize); 845bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten count = framesPerBuffer; 855bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten ++underruns; 865bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 875bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (count > 0) { 885bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLuint32 nbytes = count * sfframesize; 895bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten nbytes = squeeze(buffer, nbytes); 905bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLresult result = (*bufq)->Enqueue(bufq, buffer, nbytes); 915bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(SL_RESULT_SUCCESS == result); 925bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (++which >= numBuffers) 935bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten which = 0; 945bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 955bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 965bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten} 975bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 985bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten// This thread reads from a (slow) filesystem with unpredictable latency and writes to pipe 995bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 1005bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastenstatic void *file_reader_loop(void *arg __unused) 1015bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten{ 1025bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#define READ_FRAMES 256 1035bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten void *temp = malloc(READ_FRAMES * sfframesize); 1045bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten sf_count_t total = 0; 1055bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten sf_count_t count; 1065bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten for (;;) { 1075bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten switch (transferFormat) { 1085bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten case AUDIO_FORMAT_PCM_FLOAT: 1095bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten count = sf_readf_float(sndfile, (float *) temp, READ_FRAMES); 1105bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 1115bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten case AUDIO_FORMAT_PCM_32_BIT: 1125bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten case AUDIO_FORMAT_PCM_24_BIT_PACKED: 1135bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten count = sf_readf_int(sndfile, (int *) temp, READ_FRAMES); 1145bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 1155bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten case AUDIO_FORMAT_PCM_16_BIT: 1165bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten case AUDIO_FORMAT_PCM_8_BIT: 1175bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten count = sf_readf_short(sndfile, (short *) temp, READ_FRAMES); 1185bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 1195bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten default: 1205bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten count = 0; 1215bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 1225bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 1235bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (0 >= count) { 1245bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten eof = SL_BOOLEAN_TRUE; 1255bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 1265bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 1275bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten const unsigned char *ptr = (unsigned char *) temp; 1285bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten while (count > 0) { 12913e4fe3294ea101738253c72a3382101918d5682Glenn Kasten ssize_t actual = fifoWriter->write(ptr, (size_t) count); 1305bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (actual < 0) { 1315bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 1325bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 1335bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if ((sf_count_t) actual < count) { 1345bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten usleep(10000); 1355bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 1365bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten ptr += actual * sfframesize; 1375bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten count -= actual; 1385bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten total += actual; 1395bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 1405bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // simulate occasional filesystem latency 1415bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if ((total & 0xFF00) == 0xFF00) { 1425bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten usleep(100000); 1435bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 1445bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 1455bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten free(temp); 1465bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten return NULL; 1475bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten} 1485bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 1495bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten// Main program 1505bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 1515bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastenint main(int argc, char **argv) 1525bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten{ 1535bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // Determine the native byte order (SL_BYTEORDER_NATIVE not available until 1.1) 1545bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten union { 1555bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten short s; 1565bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten char c[2]; 1575bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } u; 1585bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten u.s = 0x1234; 1595bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (u.c[0] == 0x34) { 1605bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten nativeByteOrder = SL_BYTEORDER_LITTLEENDIAN; 1615bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } else if (u.c[0] == 0x12) { 1625bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten nativeByteOrder = SL_BYTEORDER_BIGENDIAN; 1635bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } else { 1645bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, "Unable to determine native byte order\n"); 1655bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten return EXIT_FAILURE; 1665bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 1675bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten byteOrder = nativeByteOrder; 1685bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 1695bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLboolean enableReverb = SL_BOOLEAN_FALSE; 1705bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLboolean enablePlaybackRate = SL_BOOLEAN_FALSE; 1715bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLpermille initialRate = 0; 1725bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLpermille finalRate = 0; 1735bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLpermille deltaRate = 1; 1745bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLmillisecond deltaRateMs = 0; 1755bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 1765bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // process command-line options 1775bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten int i; 1785bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten for (i = 1; i < argc; ++i) { 1795bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten char *arg = argv[i]; 1805bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (arg[0] != '-') { 1815bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 1825bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 1835bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (!strcmp(arg, "-b")) { 1845bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten byteOrder = SL_BYTEORDER_BIGENDIAN; 1855bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } else if (!strcmp(arg, "-l")) { 1865bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten byteOrder = SL_BYTEORDER_LITTLEENDIAN; 1875bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } else if (!strcmp(arg, "-8")) { 1885bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten transferFormat = AUDIO_FORMAT_PCM_8_BIT; 1895bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } else if (!strcmp(arg, "-16")) { 1905bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten transferFormat = AUDIO_FORMAT_PCM_16_BIT; 1915bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } else if (!strcmp(arg, "-24")) { 1925bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten transferFormat = AUDIO_FORMAT_PCM_24_BIT_PACKED; 1935bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } else if (!strcmp(arg, "-32")) { 1945bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten transferFormat = AUDIO_FORMAT_PCM_32_BIT; 1955bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } else if (!strcmp(arg, "-32f")) { 1965bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten transferFormat = AUDIO_FORMAT_PCM_FLOAT; 1975bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } else if (!strncmp(arg, "-f", 2)) { 1985bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten framesPerBuffer = atoi(&arg[2]); 1995bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } else if (!strncmp(arg, "-n", 2)) { 2005bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten numBuffers = atoi(&arg[2]); 2015bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } else if (!strncmp(arg, "-p", 2)) { 2025bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten initialRate = atoi(&arg[2]); 2035bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten enablePlaybackRate = SL_BOOLEAN_TRUE; 2045bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } else if (!strncmp(arg, "-P", 2)) { 2055bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten finalRate = atoi(&arg[2]); 2065bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten enablePlaybackRate = SL_BOOLEAN_TRUE; 2075bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } else if (!strncmp(arg, "-q", 2)) { 2085bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten deltaRate = atoi(&arg[2]); 2095bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // deltaRate is a magnitude, so take absolute value 2105bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (deltaRate < 0) { 2115bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten deltaRate = -deltaRate; 2125bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 2135bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten enablePlaybackRate = SL_BOOLEAN_TRUE; 2145bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } else if (!strncmp(arg, "-Q", 2)) { 2155bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten deltaRateMs = atoi(&arg[2]); 2165bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten enablePlaybackRate = SL_BOOLEAN_TRUE; 2175bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } else if (!strcmp(arg, "-r")) { 2185bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten enableReverb = SL_BOOLEAN_TRUE; 2195bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } else { 2205bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, "option %s ignored\n", arg); 2215bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 2225bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 2235bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 2245bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (argc - i != 1) { 2255bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, "usage: [-b/l] [-8 | | -16 | -24 | -32 | -32f] [-f#] [-n#] [-p#] [-r]" 2265bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten " %s filename\n", argv[0]); 2275bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, " -b force big-endian byte order (default is native byte order)\n"); 2285bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, " -l force little-endian byte order (default is native byte order)\n"); 2295bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, " -8 output 8-bits per sample (default is that of input file)\n"); 2305bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, " -16 output 16-bits per sample\n"); 2315bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, " -24 output 24-bits per sample\n"); 2325bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, " -32 output 32-bits per sample\n"); 2335bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, " -32f output float 32-bits per sample\n"); 2345bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, " -f# frames per buffer (default 512)\n"); 2355bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, " -n# number of buffers (default 2)\n"); 2365bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, " -p# initial playback rate in per mille (default 1000)\n"); 2375bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, " -P# final playback rate in per mille (default same as -p#)\n"); 2385bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, " -q# magnitude of playback rate changes in per mille (default 1)\n"); 2395bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, " -Q# period between playback rate changes in ms (default 50)\n"); 2405bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, " -r enable reverb (default disabled)\n"); 2415bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten return EXIT_FAILURE; 2425bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 2435bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 2445bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten const char *filename = argv[i]; 2455bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten //memset(&sfinfo, 0, sizeof(SF_INFO)); 2465bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten sfinfo.format = 0; 2475bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten sndfile = sf_open(filename, SFM_READ, &sfinfo); 2485bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (NULL == sndfile) { 2495bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten perror(filename); 2505bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten return EXIT_FAILURE; 2515bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 2525bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 2535bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // verify the file format 2545bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten switch (sfinfo.channels) { 2555bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten case 1: 2565bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten case 2: 2575bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 2585bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten default: 2595bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, "unsupported channel count %d\n", sfinfo.channels); 2605bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten goto close_sndfile; 2615bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 2625bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 2635bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (sfinfo.samplerate < 8000 || sfinfo.samplerate > 192000) { 2645bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, "unsupported sample rate %d\n", sfinfo.samplerate); 2655bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten goto close_sndfile; 2665bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 2675bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 2685bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten switch (sfinfo.format & SF_FORMAT_TYPEMASK) { 2695bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten case SF_FORMAT_WAV: 2705bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 2715bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten default: 2725bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, "unsupported format type 0x%x\n", sfinfo.format & SF_FORMAT_TYPEMASK); 2735bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten goto close_sndfile; 2745bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 2755bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 2765bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten switch (sfinfo.format & SF_FORMAT_SUBMASK) { 2775bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten case SF_FORMAT_FLOAT: 2785bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (transferFormat == AUDIO_FORMAT_DEFAULT) { 2795bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten transferFormat = AUDIO_FORMAT_PCM_FLOAT; 2805bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 2815bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 2825bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten case SF_FORMAT_PCM_32: 2835bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (transferFormat == AUDIO_FORMAT_DEFAULT) { 2845bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten transferFormat = AUDIO_FORMAT_PCM_32_BIT; 2855bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 2865bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 2875bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten case SF_FORMAT_PCM_16: 2885bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (transferFormat == AUDIO_FORMAT_DEFAULT) { 2895bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten transferFormat = AUDIO_FORMAT_PCM_16_BIT; 2905bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 2915bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 2925bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten case SF_FORMAT_PCM_U8: 2935bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (transferFormat == AUDIO_FORMAT_DEFAULT) { 2945bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten transferFormat = AUDIO_FORMAT_PCM_8_BIT; 2955bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 2965bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 2975bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten case SF_FORMAT_PCM_24: 2985bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (transferFormat == AUDIO_FORMAT_DEFAULT) { 2995bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten transferFormat = AUDIO_FORMAT_PCM_24_BIT_PACKED; 3005bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 3015bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 3025bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten default: 3035bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, "unsupported sub-format 0x%x\n", sfinfo.format & SF_FORMAT_SUBMASK); 3045bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten goto close_sndfile; 3055bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 3065bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 3075bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLuint32 bitsPerSample; 3085bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten switch (transferFormat) { 3095bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten case AUDIO_FORMAT_PCM_FLOAT: 3105bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten bitsPerSample = 32; 3115bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten sfframesize = sfinfo.channels * sizeof(float); 3125bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 3135bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten case AUDIO_FORMAT_PCM_32_BIT: 3145bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten bitsPerSample = 32; 3155bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten sfframesize = sfinfo.channels * sizeof(int); 3165bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 3175bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten case AUDIO_FORMAT_PCM_24_BIT_PACKED: 3185bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten bitsPerSample = 24; 3195bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten sfframesize = sfinfo.channels * sizeof(int); // use int size 3205bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 3215bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten case AUDIO_FORMAT_PCM_16_BIT: 3225bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten bitsPerSample = 16; 3235bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten sfframesize = sfinfo.channels * sizeof(short); 3245bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 3255bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten case AUDIO_FORMAT_PCM_8_BIT: 3265bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten bitsPerSample = 8; 3275bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten sfframesize = sfinfo.channels * sizeof(short); // use short size 3285bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 3295bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten default: 3305bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, "unsupported transfer format %#x\n", transferFormat); 3315bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten goto close_sndfile; 3325bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 3335bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 3345bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten { 3355bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten buffers = malloc(framesPerBuffer * sfframesize * numBuffers); 3365bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 3375bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // create engine 3385bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLresult result; 3395bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLObjectItf engineObject; 3405bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); 3415bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3425bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLEngineItf engineEngine; 3435bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); 3445bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3455bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); 3465bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3475bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 3485bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // create output mix 3495bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLObjectItf outputMixObject; 3505bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB}; 3515bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLboolean req[1] = {SL_BOOLEAN_TRUE}; 3525bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, enableReverb ? 1 : 0, 3535bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten ids, req); 3545bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3555bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); 3565bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3575bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 3585bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // configure environmental reverb on output mix 3595bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLEnvironmentalReverbItf mixEnvironmentalReverb = NULL; 3605bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (enableReverb) { 3615bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB, 3625bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten &mixEnvironmentalReverb); 3635bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3645bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLEnvironmentalReverbSettings settings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR; 3655bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten result = (*mixEnvironmentalReverb)->SetEnvironmentalReverbProperties(mixEnvironmentalReverb, 3665bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten &settings); 3675bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3685bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 3695bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 3705bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // configure audio source 3715bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLDataLocator_BufferQueue loc_bufq; 3725bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten loc_bufq.locatorType = SL_DATALOCATOR_BUFFERQUEUE; 3735bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten loc_bufq.numBuffers = numBuffers; 3745bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLAndroidDataFormat_PCM_EX format_pcm; 3755bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten format_pcm.formatType = transferFormat == AUDIO_FORMAT_PCM_FLOAT 3765bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten ? SL_ANDROID_DATAFORMAT_PCM_EX : SL_DATAFORMAT_PCM; 3775bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten format_pcm.numChannels = sfinfo.channels; 3785bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten format_pcm.sampleRate = sfinfo.samplerate * 1000; 3795bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten format_pcm.bitsPerSample = bitsPerSample; 3805bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten format_pcm.containerSize = format_pcm.bitsPerSample; 3815bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten format_pcm.channelMask = 1 == format_pcm.numChannels ? SL_SPEAKER_FRONT_CENTER : 3825bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; 3835bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten format_pcm.endianness = byteOrder; 3845bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten format_pcm.representation = transferFormat == AUDIO_FORMAT_PCM_FLOAT 3855bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten ? SL_ANDROID_PCM_REPRESENTATION_FLOAT : transferFormat == AUDIO_FORMAT_PCM_8_BIT 3865bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten ? SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT 3875bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten : SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT; 3885bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLDataSource audioSrc; 3895bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten audioSrc.pLocator = &loc_bufq; 3905bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten audioSrc.pFormat = &format_pcm; 3915bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 3925bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // configure audio sink 3935bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLDataLocator_OutputMix loc_outmix; 3945bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; 3955bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten loc_outmix.outputMix = outputMixObject; 3965bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLDataSink audioSnk; 3975bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten audioSnk.pLocator = &loc_outmix; 3985bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten audioSnk.pFormat = NULL; 3995bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 4005bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // create audio player 4015bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLInterfaceID ids2[3] = {SL_IID_BUFFERQUEUE, SL_IID_PLAYBACKRATE, SL_IID_EFFECTSEND}; 4025bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLboolean req2[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; 4035bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLObjectItf playerObject; 4045bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audioSrc, 4055bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten &audioSnk, enableReverb ? 3 : (enablePlaybackRate ? 2 : 1), ids2, req2); 4065bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (SL_RESULT_SUCCESS != result) { 4075bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, "can't create audio player\n"); 4085bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten goto no_player; 4095bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 4105bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 4115bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten { 4125bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 4135bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // realize the player 4145bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE); 4155bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(SL_RESULT_SUCCESS == result); 4165bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 4175bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // get the effect send interface and enable effect send reverb for this player 4185bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (enableReverb) { 4195bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLEffectSendItf playerEffectSend; 4205bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten result = (*playerObject)->GetInterface(playerObject, SL_IID_EFFECTSEND, &playerEffectSend); 4215bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(SL_RESULT_SUCCESS == result); 4225bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten result = (*playerEffectSend)->EnableEffectSend(playerEffectSend, mixEnvironmentalReverb, 4235bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SL_BOOLEAN_TRUE, (SLmillibel) 0); 4245bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(SL_RESULT_SUCCESS == result); 4255bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 4265bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 4275bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // get the playback rate interface and configure the rate 4285bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLPlaybackRateItf playerPlaybackRate; 4295bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLpermille currentRate = 0; 4305bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (enablePlaybackRate) { 4315bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAYBACKRATE, 4325bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten &playerPlaybackRate); 4335bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(SL_RESULT_SUCCESS == result); 4345bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLpermille defaultRate; 4355bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten result = (*playerPlaybackRate)->GetRate(playerPlaybackRate, &defaultRate); 4365bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(SL_RESULT_SUCCESS == result); 4375bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLuint32 defaultProperties; 4385bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten result = (*playerPlaybackRate)->GetProperties(playerPlaybackRate, &defaultProperties); 4395bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(SL_RESULT_SUCCESS == result); 4405bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten printf("default playback rate %d per mille, properties 0x%x\n", defaultRate, 4415bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten defaultProperties); 4425bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (initialRate <= 0) { 4435bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten initialRate = defaultRate; 4445bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 4455bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (finalRate <= 0) { 4465bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten finalRate = initialRate; 4475bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 4485bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten currentRate = defaultRate; 4495bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (finalRate == initialRate) { 4505bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten deltaRate = 0; 4515bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } else if (finalRate < initialRate) { 4525bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten deltaRate = -deltaRate; 4535bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 4545bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (initialRate != defaultRate) { 4555bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten result = (*playerPlaybackRate)->SetRate(playerPlaybackRate, initialRate); 4565bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (SL_RESULT_FEATURE_UNSUPPORTED == result) { 4575bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, "initial playback rate %d is unsupported\n", initialRate); 4585bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten deltaRate = 0; 4595bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } else if (SL_RESULT_PARAMETER_INVALID == result) { 4605bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, "initial playback rate %d is invalid\n", initialRate); 4615bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten deltaRate = 0; 4625bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } else { 4635bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(SL_RESULT_SUCCESS == result); 4645bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten currentRate = initialRate; 4655bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 4665bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 4675bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 4685bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 4695bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // get the play interface 4705bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLPlayItf playerPlay; 4715bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay); 4725bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(SL_RESULT_SUCCESS == result); 4735bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 4745bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // get the buffer queue interface 4755bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLBufferQueueItf playerBufferQueue; 4765bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE, 4775bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten &playerBufferQueue); 4785bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(SL_RESULT_SUCCESS == result); 4795bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 4805bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // loop until EOF or no more buffers 4815bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten for (which = 0; which < numBuffers; ++which) { 4825bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten void *buffer = (char *)buffers + framesPerBuffer * sfframesize * which; 4835bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten sf_count_t frames = framesPerBuffer; 4845bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten sf_count_t count; 4855bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten switch (transferFormat) { 4865bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten case AUDIO_FORMAT_PCM_FLOAT: 4875bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten count = sf_readf_float(sndfile, (float *) buffer, frames); 4885bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 4895bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten case AUDIO_FORMAT_PCM_32_BIT: 4905bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten count = sf_readf_int(sndfile, (int *) buffer, frames); 4915bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 4925bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten case AUDIO_FORMAT_PCM_24_BIT_PACKED: 4935bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten count = sf_readf_int(sndfile, (int *) buffer, frames); 4945bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 4955bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten case AUDIO_FORMAT_PCM_16_BIT: 4965bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten case AUDIO_FORMAT_PCM_8_BIT: 4975bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten count = sf_readf_short(sndfile, (short *) buffer, frames); 4985bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 4995bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten default: 5005bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten count = 0; 5015bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 5025bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 5035bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (0 >= count) { 5045bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten eof = SL_BOOLEAN_TRUE; 5055bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 5065bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 5075bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 5085bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // enqueue a buffer 5095bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLuint32 nbytes = count * sfframesize; 5105bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten nbytes = squeeze(buffer, nbytes); 5115bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, nbytes); 5125bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(SL_RESULT_SUCCESS == result); 5135bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 5145bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (which >= numBuffers) { 5155bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten which = 0; 5165bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 5175bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 5185bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // register a callback on the buffer queue 5195bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, callback, NULL); 5205bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(SL_RESULT_SUCCESS == result); 5215bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 5225bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten#define FIFO_FRAMES 16384 5235bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten void *fifoBuffer = malloc(FIFO_FRAMES * sfframesize); 524add2a2112de08f840459de78e8f8eb16d8c888c3Glenn Kasten fifo = new audio_utils_fifo(FIFO_FRAMES, sfframesize, fifoBuffer); 52513e4fe3294ea101738253c72a3382101918d5682Glenn Kasten fifoReader = new audio_utils_fifo_reader(*fifo, true /*throttlesWriter*/); 52613e4fe3294ea101738253c72a3382101918d5682Glenn Kasten fifoWriter = new audio_utils_fifo_writer(*fifo); 5275bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 5285bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // create thread to read from file 5295bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten pthread_t thread; 5305bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten int ok = pthread_create(&thread, (const pthread_attr_t *) NULL, file_reader_loop, NULL); 5315bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(0 == ok); 5325bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 5335bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // give thread a head start so that the pipe is initially filled 5345bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten sleep(1); 5355bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 5365bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // set the player's state to playing 5375bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING); 5385bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(SL_RESULT_SUCCESS == result); 5395bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 5405bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // get the initial time 5415bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten struct timespec prevTs; 5425bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten clock_gettime(CLOCK_MONOTONIC, &prevTs); 5435bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten long elapsedNs = 0; 5445bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten long deltaRateNs = deltaRateMs * 1000000; 5455bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 5465bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // wait until the buffer queue is empty 5475bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLBufferQueueState bufqstate; 5485bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten for (;;) { 5495bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten result = (*playerBufferQueue)->GetState(playerBufferQueue, &bufqstate); 5505bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(SL_RESULT_SUCCESS == result); 5515bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (0 >= bufqstate.count) { 5525bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten break; 5535bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 5545bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (!enablePlaybackRate || deltaRate == 0) { 5555bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten sleep(1); 5565bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } else { 5575bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten struct timespec curTs; 5585bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten clock_gettime(CLOCK_MONOTONIC, &curTs); 5595bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten elapsedNs += (curTs.tv_sec - prevTs.tv_sec) * 1000000000 + 5605bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // this term can be negative 5615bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten (curTs.tv_nsec - prevTs.tv_nsec); 5625bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten prevTs = curTs; 5635bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (elapsedNs < deltaRateNs) { 5645bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten usleep((deltaRateNs - elapsedNs) / 1000); 5655bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten continue; 5665bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 5675bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten elapsedNs -= deltaRateNs; 5685bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten SLpermille nextRate = currentRate + deltaRate; 5695bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten result = (*playerPlaybackRate)->SetRate(playerPlaybackRate, nextRate); 5705bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (SL_RESULT_SUCCESS != result) { 5715bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, "next playback rate %d is unsupported\n", nextRate); 5725bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } else if (SL_RESULT_PARAMETER_INVALID == result) { 5735bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten fprintf(stderr, "next playback rate %d is invalid\n", nextRate); 5745bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } else { 5755bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(SL_RESULT_SUCCESS == result); 5765bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 5775bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten currentRate = nextRate; 5785bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten if (currentRate >= max(initialRate, finalRate)) { 5795bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten currentRate = max(initialRate, finalRate); 5805bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten deltaRate = -abs(deltaRate); 5815bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } else if (currentRate <= min(initialRate, finalRate)) { 5825bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten currentRate = min(initialRate, finalRate); 5835bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten deltaRate = abs(deltaRate); 5845bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 5855bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 5865bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 5875bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 5885bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 5895bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // wait for reader thread to exit 5905bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten ok = pthread_join(thread, (void **) NULL); 5915bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(0 == ok); 5925bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 5935bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // set the player's state to stopped 5945bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_STOPPED); 5955bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten assert(SL_RESULT_SUCCESS == result); 5965bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 5975bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // destroy audio player 5985bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten (*playerObject)->Destroy(playerObject); 5995bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 60013e4fe3294ea101738253c72a3382101918d5682Glenn Kasten delete fifoWriter; 60113e4fe3294ea101738253c72a3382101918d5682Glenn Kasten fifoWriter = NULL; 60213e4fe3294ea101738253c72a3382101918d5682Glenn Kasten delete fifoReader; 60313e4fe3294ea101738253c72a3382101918d5682Glenn Kasten fifoReader = NULL; 604add2a2112de08f840459de78e8f8eb16d8c888c3Glenn Kasten delete fifo; 605add2a2112de08f840459de78e8f8eb16d8c888c3Glenn Kasten fifo = NULL; 6065bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten free(fifoBuffer); 607add2a2112de08f840459de78e8f8eb16d8c888c3Glenn Kasten fifoBuffer = NULL; 6085bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 6095bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 6105bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 6115bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastenno_player: 6125bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 6135bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // destroy output mix 6145bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten (*outputMixObject)->Destroy(outputMixObject); 6155bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 6165bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten // destroy engine 6175bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten (*engineObject)->Destroy(engineObject); 6185bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 6195bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten } 6205bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 6215bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kastenclose_sndfile: 6225bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 6235bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten (void) sf_close(sndfile); 6245bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten 6255bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten return EXIT_SUCCESS; 6265bc530791ddcb9e6f49787b26d5f275482b1e0efGlenn Kasten} 627