playbq.c revision f8d147df8f6dba1bb5bb0ea4c09795ee827569ca
10a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten/* 20a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * Copyright (C) 2010 The Android Open Source Project 30a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * 40a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * Licensed under the Apache License, Version 2.0 (the "License"); 50a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * you may not use this file except in compliance with the License. 60a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * You may obtain a copy of the License at 70a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * 80a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * http://www.apache.org/licenses/LICENSE-2.0 90a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * 100a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * Unless required by applicable law or agreed to in writing, software 110a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * distributed under the License is distributed on an "AS IS" BASIS, 120a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * See the License for the specific language governing permissions and 140a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * limitations under the License. 150a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten */ 160a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 170a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten// Play an audio file using buffer queue 180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 190a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <assert.h> 200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <math.h> 210a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <stdio.h> 220a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <stdlib.h> 230a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <string.h> 24701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten#include <time.h> 250a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <unistd.h> 260a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 27c6853892c94800e72c0bd676d5d2136d48cea76eGlenn Kasten#include <SLES/OpenSLES.h> 280a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#ifdef ANDROID 290a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include "sndfile.h" 300a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#else 310a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <sndfile.h> 320a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#endif 330a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 34701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten#define max(a, b) ((a) > (b) ? (a) : (b)) 35701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten#define min(a, b) ((a) < (b) ? (a) : (b)) 36701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten 370a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenunsigned numBuffers = 2; 380a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenint framesPerBuffer = 512; 390a058cc3d720cdf3f0f8222472a862258482f34fGlenn KastenSNDFILE *sndfile; 400a058cc3d720cdf3f0f8222472a862258482f34fGlenn KastenSF_INFO sfinfo; 410a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenunsigned which; // which buffer to use next 420a058cc3d720cdf3f0f8222472a862258482f34fGlenn KastenSLboolean eof; // whether we have hit EOF on input yet 430a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenshort *buffers; 44ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn KastenSLuint32 byteOrder; // desired to use for PCM buffers 45ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn KastenSLuint32 nativeByteOrder; // of platform 46ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn KastenSLuint32 bitsPerSample = 16; 47ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten 48ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten// swap adjacent bytes; this would normally be in <unistd.h> but is missing here 49ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kastenstatic void swab(const void *from, void *to, ssize_t n) 50ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten{ 51ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten // from and to as char pointers 52ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten const char *from_ch = (const char *) from; 53ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten char *to_ch = (char *) to; 54ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten // note that we don't swap the last odd byte 55ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten while (n >= 2) { 56ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten to_ch[0] = from_ch[1]; 57ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten to_ch[1] = from_ch[0]; 58ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten to_ch += 2; 59ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten from_ch += 2; 60ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten n -= 2; 61ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } 62ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten} 63ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten 64ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten// squeeze 16-bit signed PCM samples down to 8-bit unsigned PCM samples by truncation; no dithering 65ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kastenstatic void squeeze(const short *from, unsigned char *to, ssize_t n) 66ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten{ 67ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten // note that we don't squeeze the last odd byte 68ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten while (n >= 2) { 69ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten *to++ = (*from++ + 32768) >> 8; 70ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten n -= 2; 71ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } 72ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten} 730a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 740a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten// This callback is called each time a buffer finishes playing 750a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 760a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenstatic void callback(SLBufferQueueItf bufq, void *param) 770a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten{ 789a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten assert(NULL == param); 790a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (!eof) { 800a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten short *buffer = &buffers[framesPerBuffer * sfinfo.channels * which]; 810a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten sf_count_t count; 820a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten count = sf_readf_short(sndfile, buffer, (sf_count_t) framesPerBuffer); 830a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (0 >= count) { 840a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten eof = SL_BOOLEAN_TRUE; 850a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } else { 86ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten SLuint32 nbytes = count * sfinfo.channels * sizeof(short); 87ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten if (byteOrder != nativeByteOrder) { 88ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten swab(buffer, buffer, nbytes); 89ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } 90ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten if (bitsPerSample == 8) { 91ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten squeeze(buffer, (unsigned char *) buffer, nbytes); 92ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten nbytes /= 2; 93ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } 94ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten SLresult result = (*bufq)->Enqueue(bufq, buffer, nbytes); 950a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 960a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (++which >= numBuffers) 970a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten which = 0; 980a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 990a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 1000a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten} 1010a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 1020a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenint main(int argc, char **argv) 1030a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten{ 104ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten // Determine the native byte order (SL_BYTEORDER_NATIVE not available until 1.1) 105ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten union { 106ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten short s; 107ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten char c[2]; 108ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } u; 109ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten u.s = 0x1234; 110ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten if (u.c[0] == 0x34) { 111ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten nativeByteOrder = SL_BYTEORDER_LITTLEENDIAN; 112ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } else if (u.c[0] == 0x12) { 113ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten nativeByteOrder = SL_BYTEORDER_BIGENDIAN; 114ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } else { 115ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten fprintf(stderr, "Unable to determine native byte order\n"); 116ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten return EXIT_FAILURE; 117ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } 118ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten byteOrder = nativeByteOrder; 119ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten 1200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLboolean enableReverb = SL_BOOLEAN_FALSE; 121f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten SLboolean enablePlaybackRate = SL_BOOLEAN_FALSE; 122701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten SLpermille initialRate = 0; 123701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten SLpermille finalRate = 0; 124701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten SLpermille deltaRate = 1; 125701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten SLmillisecond deltaRateMs = 0; 1260a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 1270a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // process command-line options 1280a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten int i; 1290a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten for (i = 1; i < argc; ++i) { 1300a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten char *arg = argv[i]; 131701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten if (arg[0] != '-') { 1320a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 133701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } 134ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten if (!strcmp(arg, "-b")) { 135ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten byteOrder = SL_BYTEORDER_BIGENDIAN; 136ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } else if (!strcmp(arg, "-l")) { 137ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten byteOrder = SL_BYTEORDER_LITTLEENDIAN; 138ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } else if (!strcmp(arg, "-8")) { 139ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten bitsPerSample = 8; 140ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } else if (!strncmp(arg, "-f", 2)) { 1410a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten framesPerBuffer = atoi(&arg[2]); 1420a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } else if (!strncmp(arg, "-n", 2)) { 1430a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten numBuffers = atoi(&arg[2]); 1449a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten } else if (!strncmp(arg, "-p", 2)) { 145701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten initialRate = atoi(&arg[2]); 146f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten enablePlaybackRate = SL_BOOLEAN_TRUE; 147701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } else if (!strncmp(arg, "-P", 2)) { 148701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten finalRate = atoi(&arg[2]); 149f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten enablePlaybackRate = SL_BOOLEAN_TRUE; 150701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } else if (!strncmp(arg, "-q", 2)) { 151701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten deltaRate = atoi(&arg[2]); 152701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten // deltaRate is a magnitude, so take absolute value 153701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten if (deltaRate < 0) { 154701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten deltaRate = -deltaRate; 155701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } 156f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten enablePlaybackRate = SL_BOOLEAN_TRUE; 157701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } else if (!strncmp(arg, "-Q", 2)) { 158701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten deltaRateMs = atoi(&arg[2]); 159f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten enablePlaybackRate = SL_BOOLEAN_TRUE; 1600a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } else if (!strcmp(arg, "-r")) { 1610a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten enableReverb = SL_BOOLEAN_TRUE; 1620a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } else { 1630a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten fprintf(stderr, "option %s ignored\n", arg); 1640a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 1650a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 1660a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 1670a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (argc - i != 1) { 168ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten fprintf(stderr, "usage: [-b/l] [-8] [-f#] [-n#] [-p#] [-r] %s filename\n", argv[0]); 169701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -b force big-endian byte order (default is native byte order)\n"); 170701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -l force little-endian byte order (default is native byte order)\n"); 171701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -8 output 8-bits per sample (default is 16-bits per sample)\n"); 172701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -f# frames per buffer (default 512)\n"); 173701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -n# number of buffers (default 2)\n"); 174701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -p# initial playback rate in per mille (default 1000)\n"); 175701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -P# final playback rate in per mille (default same as -p#)\n"); 176701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -q# magnitude of playback rate changes in per mille (default 1)\n"); 177701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -Q# period between playback rate changes in ms (default 50)\n"); 178701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -r enable reverb (default disabled)\n"); 1790a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten return EXIT_FAILURE; 1800a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 1810a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 1820a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten const char *filename = argv[i]; 1830a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten //memset(&sfinfo, 0, sizeof(SF_INFO)); 1840a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten sfinfo.format = 0; 1850a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten sndfile = sf_open(filename, SFM_READ, &sfinfo); 1860a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (NULL == sndfile) { 1870a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten perror(filename); 1880a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten return EXIT_FAILURE; 1890a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 1900a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 1910a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // verify the file format 1920a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten switch (sfinfo.channels) { 1930a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 1: 1940a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 2: 1950a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 1960a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten default: 1970a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten fprintf(stderr, "unsupported channel count %d\n", sfinfo.channels); 198701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten goto close_sndfile; 1990a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 200701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten 2010a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten switch (sfinfo.samplerate) { 2020a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 8000: 2030a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 11025: 2040a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 12000: 2050a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 16000: 2060a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 22050: 2070a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 24000: 2080a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 32000: 2090a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 44100: 2100a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 48000: 2110a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 2120a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten default: 2130a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten fprintf(stderr, "unsupported sample rate %d\n", sfinfo.samplerate); 214701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten goto close_sndfile; 2150a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 216701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten 2170a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten switch (sfinfo.format & SF_FORMAT_TYPEMASK) { 2180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case SF_FORMAT_WAV: 2190a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 2200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten default: 2210a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten fprintf(stderr, "unsupported format type 0x%x\n", sfinfo.format & SF_FORMAT_TYPEMASK); 222701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten goto close_sndfile; 2230a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 224701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten 2250a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten switch (sfinfo.format & SF_FORMAT_SUBMASK) { 2260a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case SF_FORMAT_PCM_16: 2270a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case SF_FORMAT_PCM_U8: 2280a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case SF_FORMAT_ULAW: 2290a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case SF_FORMAT_ALAW: 2300a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case SF_FORMAT_IMA_ADPCM: 2310a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 2320a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten default: 2330a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten fprintf(stderr, "unsupported sub-format 0x%x\n", sfinfo.format & SF_FORMAT_SUBMASK); 234701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten goto close_sndfile; 2350a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 2360a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 2370a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten buffers = (short *) malloc(framesPerBuffer * sfinfo.channels * sizeof(short) * numBuffers); 2380a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 2390a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // create engine 2400a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLresult result; 2410a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLObjectItf engineObject; 2420a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); 2430a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 2440a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLEngineItf engineEngine; 2450a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); 2460a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 2470a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); 2480a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 2490a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 2500a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // create output mix 2510a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLObjectItf outputMixObject; 2520a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB}; 2530a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLboolean req[1] = {SL_BOOLEAN_TRUE}; 2540a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, enableReverb ? 1 : 0, 2550a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten ids, req); 2560a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 2570a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); 2580a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 2590a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 2600a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // configure environmental reverb on output mix 2610a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLEnvironmentalReverbItf mixEnvironmentalReverb = NULL; 2620a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (enableReverb) { 2630a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB, 2640a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten &mixEnvironmentalReverb); 2650a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 2660a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLEnvironmentalReverbSettings settings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR; 2670a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*mixEnvironmentalReverb)->SetEnvironmentalReverbProperties(mixEnvironmentalReverb, 2680a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten &settings); 2690a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 2700a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 2710a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 2720a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // configure audio source 2730a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLDataLocator_BufferQueue loc_bufq; 2740a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten loc_bufq.locatorType = SL_DATALOCATOR_BUFFERQUEUE; 2750a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten loc_bufq.numBuffers = numBuffers; 2760a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLDataFormat_PCM format_pcm; 2770a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten format_pcm.formatType = SL_DATAFORMAT_PCM; 2780a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten format_pcm.numChannels = sfinfo.channels; 2790a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten format_pcm.samplesPerSec = sfinfo.samplerate * 1000; 280ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten format_pcm.bitsPerSample = bitsPerSample; 2810a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten format_pcm.containerSize = format_pcm.bitsPerSample; 2820a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten format_pcm.channelMask = 1 == format_pcm.numChannels ? SL_SPEAKER_FRONT_CENTER : 2830a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; 284ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten format_pcm.endianness = byteOrder; 2850a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLDataSource audioSrc; 2860a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten audioSrc.pLocator = &loc_bufq; 2870a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten audioSrc.pFormat = &format_pcm; 2880a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 2890a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // configure audio sink 2900a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLDataLocator_OutputMix loc_outmix; 2910a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; 2920a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten loc_outmix.outputMix = outputMixObject; 2930a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLDataSink audioSnk; 2940a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten audioSnk.pLocator = &loc_outmix; 2950a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten audioSnk.pFormat = NULL; 2960a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 2970a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // create audio player 2989a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten SLInterfaceID ids2[3] = {SL_IID_BUFFERQUEUE, SL_IID_PLAYBACKRATE, SL_IID_EFFECTSEND}; 2999a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten SLboolean req2[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; 3000a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLObjectItf playerObject; 3010a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audioSrc, 302f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten &audioSnk, enableReverb ? 3 : (enablePlaybackRate ? 2 : 1), ids2, req2); 303701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten if (SL_RESULT_SUCCESS != result) { 304701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, "can't create audio player\n"); 305701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten goto no_player; 306701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } 3070a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 3080a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // realize the player 3090a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE); 3100a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3110a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 3120a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // get the effect send interface and enable effect send reverb for this player 3130a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (enableReverb) { 3140a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLEffectSendItf playerEffectSend; 3150a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerObject)->GetInterface(playerObject, SL_IID_EFFECTSEND, &playerEffectSend); 3160a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3170a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerEffectSend)->EnableEffectSend(playerEffectSend, mixEnvironmentalReverb, 3180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SL_BOOLEAN_TRUE, (SLmillibel) 0); 3190a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 3210a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 3229a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten // get the playback rate interface and configure the rate 3239a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten SLPlaybackRateItf playerPlaybackRate; 324f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten SLpermille currentRate; 325f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten if (enablePlaybackRate) { 326f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAYBACKRATE, 327f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten &playerPlaybackRate); 328f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten assert(SL_RESULT_SUCCESS == result); 329f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten SLpermille defaultRate; 330f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten result = (*playerPlaybackRate)->GetRate(playerPlaybackRate, &defaultRate); 331f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten assert(SL_RESULT_SUCCESS == result); 332f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten SLuint32 defaultProperties; 333f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten result = (*playerPlaybackRate)->GetProperties(playerPlaybackRate, &defaultProperties); 334f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten assert(SL_RESULT_SUCCESS == result); 335f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten printf("default playback rate %d per mille, properties 0x%x\n", defaultRate, 336f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten defaultProperties); 337f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten if (initialRate <= 0) { 338f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten initialRate = defaultRate; 339f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten } 340f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten if (finalRate <= 0) { 341f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten finalRate = initialRate; 342f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten } 343f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten currentRate = defaultRate; 344f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten if (finalRate == initialRate) { 345701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten deltaRate = 0; 346f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten } else if (finalRate < initialRate) { 347f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten deltaRate = -deltaRate; 348f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten } 349f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten if (initialRate != defaultRate) { 350f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten result = (*playerPlaybackRate)->SetRate(playerPlaybackRate, initialRate); 351f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten if (SL_RESULT_FEATURE_UNSUPPORTED == result) { 352f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten fprintf(stderr, "initial playback rate %d is unsupported\n", initialRate); 353f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten deltaRate = 0; 354f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten } else if (SL_RESULT_PARAMETER_INVALID == result) { 355f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten fprintf(stderr, "initial playback rate %d is invalid\n", initialRate); 356f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten deltaRate = 0; 357f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten } else { 358f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten assert(SL_RESULT_SUCCESS == result); 359f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten currentRate = initialRate; 360f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten } 3619a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten } 3629a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten } 3639a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten 3640a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // get the play interface 3650a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLPlayItf playerPlay; 3660a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay); 3670a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3680a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 3690a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // get the buffer queue interface 3700a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLBufferQueueItf playerBufferQueue; 3710a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE, 3720a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten &playerBufferQueue); 3730a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3740a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 3750a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // loop until EOF or no more buffers 3760a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten for (which = 0; which < numBuffers; ++which) { 3770a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten short *buffer = &buffers[framesPerBuffer * sfinfo.channels * which]; 3780a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten sf_count_t frames = framesPerBuffer; 3790a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten sf_count_t count; 3800a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten count = sf_readf_short(sndfile, buffer, frames); 3810a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (0 >= count) { 3820a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten eof = SL_BOOLEAN_TRUE; 3830a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 3840a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 3850a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 3860a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // enqueue a buffer 387ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten SLuint32 nbytes = count * sfinfo.channels * sizeof(short); 388ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten if (byteOrder != nativeByteOrder) { 389ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten swab(buffer, buffer, nbytes); 390ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } 391ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten if (bitsPerSample == 8) { 392ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten squeeze(buffer, (unsigned char *) buffer, nbytes); 393ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten nbytes /= 2; 394ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } 395ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, nbytes); 3960a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3970a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 398701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten if (which >= numBuffers) { 3990a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten which = 0; 400701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } 4010a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 4020a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // register a callback on the buffer queue 4030a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, callback, NULL); 4040a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 4050a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 4060a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // set the player's state to playing 4070a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING); 4080a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 4090a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 410701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten // get the initial time 411701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten struct timespec prevTs; 412701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten clock_gettime(CLOCK_MONOTONIC, &prevTs); 413701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten long elapsedNs = 0; 414701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten long deltaRateNs = deltaRateMs * 1000000; 415701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten 4160a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // wait until the buffer queue is empty 4170a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLBufferQueueState bufqstate; 4180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten for (;;) { 4190a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerBufferQueue)->GetState(playerBufferQueue, &bufqstate); 4200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 4210a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (0 >= bufqstate.count) { 4220a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 4230a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 424f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten if (!enablePlaybackRate || deltaRate == 0) { 425701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten sleep(1); 426701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } else { 427701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten struct timespec curTs; 428701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten clock_gettime(CLOCK_MONOTONIC, &curTs); 429701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten elapsedNs += (curTs.tv_sec - prevTs.tv_sec) * 1000000000 + 430701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten // this term can be negative 431701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten (curTs.tv_nsec - prevTs.tv_nsec); 432701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten prevTs = curTs; 433701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten if (elapsedNs < deltaRateNs) { 434701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten usleep((deltaRateNs - elapsedNs) / 1000); 435701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten continue; 436701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } 437701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten elapsedNs -= deltaRateNs; 438701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten SLpermille nextRate = currentRate + deltaRate; 439701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten result = (*playerPlaybackRate)->SetRate(playerPlaybackRate, nextRate); 440701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten if (SL_RESULT_SUCCESS != result) { 441701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, "next playback rate %d is unsupported\n", nextRate); 442701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } else if (SL_RESULT_PARAMETER_INVALID == result) { 443701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, "next playback rate %d is invalid\n", nextRate); 444701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } else { 445701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten assert(SL_RESULT_SUCCESS == result); 446701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } 447701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten currentRate = nextRate; 448701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten if (currentRate >= max(initialRate, finalRate)) { 449701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten currentRate = max(initialRate, finalRate); 450701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten deltaRate = -abs(deltaRate); 451701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } else if (currentRate <= min(initialRate, finalRate)) { 452701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten currentRate = min(initialRate, finalRate); 453701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten deltaRate = abs(deltaRate); 454701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } 455701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } 4560a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 4570a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 4580a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // destroy audio player 4590a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten (*playerObject)->Destroy(playerObject); 4600a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 461701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kastenno_player: 462701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten 4630a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // destroy output mix 4640a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten (*outputMixObject)->Destroy(outputMixObject); 4650a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 4660a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // destroy engine 4670a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten (*engineObject)->Destroy(engineObject); 4680a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 469701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kastenclose_sndfile: 470701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten 471701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten (void) sf_close(sndfile); 472701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten 4730a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten return EXIT_SUCCESS; 4740a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten} 475