playbq.c revision bf76782721537b71e404bd5c6350e91dfda74487
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> 21ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten#include <pthread.h> 220a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <stdio.h> 230a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <stdlib.h> 240a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <string.h> 25701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten#include <time.h> 260a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <unistd.h> 270a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 28c6853892c94800e72c0bd676d5d2136d48cea76eGlenn Kasten#include <SLES/OpenSLES.h> 29e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung#include <SLES/OpenSLES_Android.h> 30208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten#include <system/audio.h> 31208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten#include <audio_utils/fifo.h> 32bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten#include <audio_utils/primitives.h> 3356847632bc2fd39a8fff68fa1e883f06310c876aGlenn Kasten#include <audio_utils/sndfile.h> 34ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten 35701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten#define max(a, b) ((a) > (b) ? (a) : (b)) 36701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten#define min(a, b) ((a) < (b) ? (a) : (b)) 37701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten 380a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenunsigned numBuffers = 2; 390a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenint framesPerBuffer = 512; 400a058cc3d720cdf3f0f8222472a862258482f34fGlenn KastenSNDFILE *sndfile; 410a058cc3d720cdf3f0f8222472a862258482f34fGlenn KastenSF_INFO sfinfo; 420a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenunsigned which; // which buffer to use next 430a058cc3d720cdf3f0f8222472a862258482f34fGlenn KastenSLboolean eof; // whether we have hit EOF on input yet 44c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hungvoid *buffers; 45ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn KastenSLuint32 byteOrder; // desired to use for PCM buffers 46ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn KastenSLuint32 nativeByteOrder; // of platform 47bf76782721537b71e404bd5c6350e91dfda74487Glenn Kastenaudio_format_t transferFormat = AUDIO_FORMAT_DEFAULT; 48c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hungsize_t sfframesize = 0; 49ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten 50bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten// FIXME move to audio_utils 51ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten// swap adjacent bytes; this would normally be in <unistd.h> but is missing here 52ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kastenstatic void swab(const void *from, void *to, ssize_t n) 53ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten{ 54ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten // from and to as char pointers 55ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten const char *from_ch = (const char *) from; 56ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten char *to_ch = (char *) to; 57ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten // note that we don't swap the last odd byte 58ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten while (n >= 2) { 59ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten to_ch[0] = from_ch[1]; 60ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten to_ch[1] = from_ch[0]; 61ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten to_ch += 2; 62ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten from_ch += 2; 63ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten n -= 2; 64ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } 65ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten} 66ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten 67bf76782721537b71e404bd5c6350e91dfda74487Glenn Kastenstatic audio_utils_fifo fifo; 68bf76782721537b71e404bd5c6350e91dfda74487Glenn Kastenstatic unsigned underruns = 0; 690a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 70bf76782721537b71e404bd5c6350e91dfda74487Glenn Kastenstatic SLuint32 squeeze(void *buffer, SLuint32 nbytes) 71c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung{ 72bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten if (byteOrder != nativeByteOrder) { 73bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten // FIXME does not work for non 16-bit 74bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten swab(buffer, buffer, nbytes); 75bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten } 76bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten if (transferFormat == AUDIO_FORMAT_PCM_8_BIT) { 77bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten memcpy_to_u8_from_i16((uint8_t *) buffer, (const int16_t *) buffer, 78bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten nbytes / sizeof(int16_t)); 79bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten nbytes /= 2; 80bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten } else if (transferFormat == AUDIO_FORMAT_PCM_24_BIT_PACKED) { 81bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten memcpy_to_p24_from_i32((uint8_t *) buffer, (const int32_t *) buffer, 82bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten nbytes / sizeof(int32_t)); 83bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten nbytes = nbytes * 3 / 4; 84c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung } 85bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten return nbytes; 86c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung} 87c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung 880a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten// This callback is called each time a buffer finishes playing 890a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 900a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenstatic void callback(SLBufferQueueItf bufq, void *param) 910a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten{ 929a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten assert(NULL == param); 930a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (!eof) { 94c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung void *buffer = (char *)buffers + framesPerBuffer * sfframesize * which; 95208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten ssize_t count = audio_utils_fifo_read(&fifo, buffer, framesPerBuffer); 96ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten // on underrun from pipe, substitute silence 970a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (0 >= count) { 98c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung memset(buffer, 0, framesPerBuffer * sfframesize); 99ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten count = framesPerBuffer; 100ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten ++underruns; 101ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten } 102ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten if (count > 0) { 103c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung SLuint32 nbytes = count * sfframesize; 104bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten nbytes = squeeze(buffer, nbytes); 105ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten SLresult result = (*bufq)->Enqueue(bufq, buffer, nbytes); 1060a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 1070a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (++which >= numBuffers) 1080a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten which = 0; 1090a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 1100a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 1110a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten} 1120a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 113ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten// This thread reads from a (slow) filesystem with unpredictable latency and writes to pipe 114ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten 115c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hungstatic void *file_reader_loop(void *arg __unused) 116ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten{ 117ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten#define READ_FRAMES 256 118c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung void *temp = malloc(READ_FRAMES * sfframesize); 119ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten sf_count_t total = 0; 120c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung sf_count_t count; 121ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten for (;;) { 122c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung switch (transferFormat) { 123c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_FLOAT: 124c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung count = sf_readf_float(sndfile, (float *) temp, READ_FRAMES); 125c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 126c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_32_BIT: 127c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_24_BIT_PACKED: 128c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung count = sf_readf_int(sndfile, (int *) temp, READ_FRAMES); 129c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 130c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_16_BIT: 131c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_8_BIT: 132c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung count = sf_readf_short(sndfile, (short *) temp, READ_FRAMES); 133c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 134c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung default: 135c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung count = 0; 136c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 137c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung } 138ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten if (0 >= count) { 139ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten eof = SL_BOOLEAN_TRUE; 140ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten break; 141ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten } 142c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung const unsigned char *ptr = (unsigned char *) temp; 143ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten while (count > 0) { 144208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten ssize_t actual = audio_utils_fifo_write(&fifo, ptr, (size_t) count); 145ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten if (actual < 0) { 146ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten break; 147ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten } 148ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten if ((sf_count_t) actual < count) { 149ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten usleep(10000); 150ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten } 151c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung ptr += actual * sfframesize; 152ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten count -= actual; 153ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten total += actual; 154ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten } 155ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten // simulate occasional filesystem latency 156ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten if ((total & 0xFF00) == 0xFF00) { 157ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten usleep(100000); 158ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten } 159ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten } 160ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten free(temp); 161ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten return NULL; 162ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten} 163ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten 164ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten// Main program 165ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten 1660a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenint main(int argc, char **argv) 1670a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten{ 168ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten // Determine the native byte order (SL_BYTEORDER_NATIVE not available until 1.1) 169ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten union { 170ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten short s; 171ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten char c[2]; 172ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } u; 173ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten u.s = 0x1234; 174ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten if (u.c[0] == 0x34) { 175ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten nativeByteOrder = SL_BYTEORDER_LITTLEENDIAN; 176ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } else if (u.c[0] == 0x12) { 177ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten nativeByteOrder = SL_BYTEORDER_BIGENDIAN; 178ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } else { 179ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten fprintf(stderr, "Unable to determine native byte order\n"); 180ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten return EXIT_FAILURE; 181ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } 182ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten byteOrder = nativeByteOrder; 183ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten 1840a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLboolean enableReverb = SL_BOOLEAN_FALSE; 185f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten SLboolean enablePlaybackRate = SL_BOOLEAN_FALSE; 186701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten SLpermille initialRate = 0; 187701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten SLpermille finalRate = 0; 188701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten SLpermille deltaRate = 1; 189701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten SLmillisecond deltaRateMs = 0; 1900a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 1910a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // process command-line options 1920a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten int i; 1930a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten for (i = 1; i < argc; ++i) { 1940a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten char *arg = argv[i]; 195701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten if (arg[0] != '-') { 1960a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 197701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } 198ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten if (!strcmp(arg, "-b")) { 199ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten byteOrder = SL_BYTEORDER_BIGENDIAN; 200ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } else if (!strcmp(arg, "-l")) { 201ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten byteOrder = SL_BYTEORDER_LITTLEENDIAN; 202ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } else if (!strcmp(arg, "-8")) { 203c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung transferFormat = AUDIO_FORMAT_PCM_8_BIT; 204bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten } else if (!strcmp(arg, "-16")) { 205bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten transferFormat = AUDIO_FORMAT_PCM_16_BIT; 206c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung } else if (!strcmp(arg, "-24")) { 207c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung transferFormat = AUDIO_FORMAT_PCM_24_BIT_PACKED; 208c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung } else if (!strcmp(arg, "-32")) { 209c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung transferFormat = AUDIO_FORMAT_PCM_32_BIT; 210e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung } else if (!strcmp(arg, "-32f")) { 211e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung transferFormat = AUDIO_FORMAT_PCM_FLOAT; 212ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } else if (!strncmp(arg, "-f", 2)) { 2130a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten framesPerBuffer = atoi(&arg[2]); 2140a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } else if (!strncmp(arg, "-n", 2)) { 2150a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten numBuffers = atoi(&arg[2]); 2169a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten } else if (!strncmp(arg, "-p", 2)) { 217701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten initialRate = atoi(&arg[2]); 218f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten enablePlaybackRate = SL_BOOLEAN_TRUE; 219701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } else if (!strncmp(arg, "-P", 2)) { 220701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten finalRate = atoi(&arg[2]); 221f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten enablePlaybackRate = SL_BOOLEAN_TRUE; 222701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } else if (!strncmp(arg, "-q", 2)) { 223701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten deltaRate = atoi(&arg[2]); 224701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten // deltaRate is a magnitude, so take absolute value 225701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten if (deltaRate < 0) { 226701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten deltaRate = -deltaRate; 227701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } 228f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten enablePlaybackRate = SL_BOOLEAN_TRUE; 229701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } else if (!strncmp(arg, "-Q", 2)) { 230701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten deltaRateMs = atoi(&arg[2]); 231f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten enablePlaybackRate = SL_BOOLEAN_TRUE; 2320a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } else if (!strcmp(arg, "-r")) { 2330a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten enableReverb = SL_BOOLEAN_TRUE; 2340a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } else { 2350a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten fprintf(stderr, "option %s ignored\n", arg); 2360a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 2370a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 2380a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 2390a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (argc - i != 1) { 240bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten fprintf(stderr, "usage: [-b/l] [-8 | | -16 | -24 | -32 | -32f] [-f#] [-n#] [-p#] [-r]" 241c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung " %s filename\n", argv[0]); 242701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -b force big-endian byte order (default is native byte order)\n"); 243701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -l force little-endian byte order (default is native byte order)\n"); 244bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten fprintf(stderr, " -8 output 8-bits per sample (default is that of input file)\n"); 245bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten fprintf(stderr, " -16 output 16-bits per sample\n"); 246c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung fprintf(stderr, " -24 output 24-bits per sample\n"); 247c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung fprintf(stderr, " -32 output 32-bits per sample\n"); 248e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung fprintf(stderr, " -32f output float 32-bits per sample\n"); 249701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -f# frames per buffer (default 512)\n"); 250701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -n# number of buffers (default 2)\n"); 251701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -p# initial playback rate in per mille (default 1000)\n"); 252701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -P# final playback rate in per mille (default same as -p#)\n"); 253701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -q# magnitude of playback rate changes in per mille (default 1)\n"); 254701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -Q# period between playback rate changes in ms (default 50)\n"); 255701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -r enable reverb (default disabled)\n"); 2560a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten return EXIT_FAILURE; 2570a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 2580a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 2590a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten const char *filename = argv[i]; 2600a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten //memset(&sfinfo, 0, sizeof(SF_INFO)); 2610a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten sfinfo.format = 0; 2620a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten sndfile = sf_open(filename, SFM_READ, &sfinfo); 2630a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (NULL == sndfile) { 2640a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten perror(filename); 2650a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten return EXIT_FAILURE; 2660a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 2670a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 2680a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // verify the file format 2690a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten switch (sfinfo.channels) { 2700a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 1: 2710a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 2: 2720a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 2730a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten default: 2740a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten fprintf(stderr, "unsupported channel count %d\n", sfinfo.channels); 275701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten goto close_sndfile; 2760a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 277701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten 278bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten if (sfinfo.samplerate < 8000 || sfinfo.samplerate > 192000) { 2790a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten fprintf(stderr, "unsupported sample rate %d\n", sfinfo.samplerate); 280701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten goto close_sndfile; 2810a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 282701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten 2830a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten switch (sfinfo.format & SF_FORMAT_TYPEMASK) { 2840a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case SF_FORMAT_WAV: 2850a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 2860a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten default: 2870a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten fprintf(stderr, "unsupported format type 0x%x\n", sfinfo.format & SF_FORMAT_TYPEMASK); 288701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten goto close_sndfile; 2890a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 290701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten 2910a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten switch (sfinfo.format & SF_FORMAT_SUBMASK) { 292c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case SF_FORMAT_FLOAT: 293bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten if (transferFormat == AUDIO_FORMAT_DEFAULT) { 294bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten transferFormat = AUDIO_FORMAT_PCM_FLOAT; 295bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten } 296bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten break; 297c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case SF_FORMAT_PCM_32: 298bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten if (transferFormat == AUDIO_FORMAT_DEFAULT) { 299bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten transferFormat = AUDIO_FORMAT_PCM_32_BIT; 300bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten } 301bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten break; 3020a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case SF_FORMAT_PCM_16: 303bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten if (transferFormat == AUDIO_FORMAT_DEFAULT) { 304bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten transferFormat = AUDIO_FORMAT_PCM_16_BIT; 305bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten } 306bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten break; 3070a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case SF_FORMAT_PCM_U8: 308bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten if (transferFormat == AUDIO_FORMAT_DEFAULT) { 309bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten transferFormat = AUDIO_FORMAT_PCM_8_BIT; 310bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten } 311bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten break; 312bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten case SF_FORMAT_PCM_24: 313bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten if (transferFormat == AUDIO_FORMAT_DEFAULT) { 314bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten transferFormat = AUDIO_FORMAT_PCM_24_BIT_PACKED; 315bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten } 3160a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 3170a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten default: 3180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten fprintf(stderr, "unsupported sub-format 0x%x\n", sfinfo.format & SF_FORMAT_SUBMASK); 319701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten goto close_sndfile; 3200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 3210a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 322c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung SLuint32 bitsPerSample; 323c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung switch (transferFormat) { 324c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_FLOAT: 325c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung bitsPerSample = 32; 326c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung sfframesize = sfinfo.channels * sizeof(float); 327c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 328c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_32_BIT: 329c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung bitsPerSample = 32; 330c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung sfframesize = sfinfo.channels * sizeof(int); 331c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 332c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_24_BIT_PACKED: 333c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung bitsPerSample = 24; 334c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung sfframesize = sfinfo.channels * sizeof(int); // use int size 335c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 336c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_16_BIT: 337c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung bitsPerSample = 16; 338c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung sfframesize = sfinfo.channels * sizeof(short); 339c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 340c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_8_BIT: 341c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung bitsPerSample = 8; 342c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung sfframesize = sfinfo.channels * sizeof(short); // use short size 343c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 344c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung default: 345c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung fprintf(stderr, "unsupported transfer format %#x\n", transferFormat); 346c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung goto close_sndfile; 347c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung } 348ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten 349c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung { 350c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung buffers = malloc(framesPerBuffer * sfframesize * numBuffers); 3510a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 3520a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // create engine 3530a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLresult result; 3540a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLObjectItf engineObject; 3550a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); 3560a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3570a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLEngineItf engineEngine; 3580a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); 3590a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3600a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); 3610a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3620a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 3630a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // create output mix 3640a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLObjectItf outputMixObject; 3650a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB}; 3660a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLboolean req[1] = {SL_BOOLEAN_TRUE}; 3670a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, enableReverb ? 1 : 0, 3680a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten ids, req); 3690a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3700a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); 3710a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3720a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 3730a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // configure environmental reverb on output mix 3740a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLEnvironmentalReverbItf mixEnvironmentalReverb = NULL; 3750a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (enableReverb) { 3760a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB, 3770a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten &mixEnvironmentalReverb); 3780a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3790a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLEnvironmentalReverbSettings settings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR; 3800a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*mixEnvironmentalReverb)->SetEnvironmentalReverbProperties(mixEnvironmentalReverb, 3810a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten &settings); 3820a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3830a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 3840a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 3850a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // configure audio source 3860a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLDataLocator_BufferQueue loc_bufq; 3870a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten loc_bufq.locatorType = SL_DATALOCATOR_BUFFERQUEUE; 3880a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten loc_bufq.numBuffers = numBuffers; 389e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung SLAndroidDataFormat_PCM_EX format_pcm; 390e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung format_pcm.formatType = transferFormat == AUDIO_FORMAT_PCM_FLOAT 391e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung ? SL_ANDROID_DATAFORMAT_PCM_EX : SL_DATAFORMAT_PCM; 3920a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten format_pcm.numChannels = sfinfo.channels; 393e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung format_pcm.sampleRate = sfinfo.samplerate * 1000; 394ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten format_pcm.bitsPerSample = bitsPerSample; 3950a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten format_pcm.containerSize = format_pcm.bitsPerSample; 3960a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten format_pcm.channelMask = 1 == format_pcm.numChannels ? SL_SPEAKER_FRONT_CENTER : 3970a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; 398ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten format_pcm.endianness = byteOrder; 399e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung format_pcm.representation = transferFormat == AUDIO_FORMAT_PCM_FLOAT 400e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung ? SL_ANDROID_PCM_REPRESENTATION_FLOAT : transferFormat == AUDIO_FORMAT_PCM_8_BIT 401e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung ? SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT 402e57c13397185f9ad0f162855e9a8ebeb0c94bfc4Andy Hung : SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT; 4030a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLDataSource audioSrc; 4040a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten audioSrc.pLocator = &loc_bufq; 4050a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten audioSrc.pFormat = &format_pcm; 4060a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 4070a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // configure audio sink 4080a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLDataLocator_OutputMix loc_outmix; 4090a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; 4100a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten loc_outmix.outputMix = outputMixObject; 4110a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLDataSink audioSnk; 4120a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten audioSnk.pLocator = &loc_outmix; 4130a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten audioSnk.pFormat = NULL; 4140a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 4150a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // create audio player 4169a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten SLInterfaceID ids2[3] = {SL_IID_BUFFERQUEUE, SL_IID_PLAYBACKRATE, SL_IID_EFFECTSEND}; 4179a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten SLboolean req2[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; 4180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLObjectItf playerObject; 4190a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audioSrc, 420f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten &audioSnk, enableReverb ? 3 : (enablePlaybackRate ? 2 : 1), ids2, req2); 421701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten if (SL_RESULT_SUCCESS != result) { 422701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, "can't create audio player\n"); 423701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten goto no_player; 424701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } 4250a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 426ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten { 427ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten 4280a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // realize the player 4290a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE); 4300a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 4310a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 4320a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // get the effect send interface and enable effect send reverb for this player 4330a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (enableReverb) { 4340a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLEffectSendItf playerEffectSend; 4350a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerObject)->GetInterface(playerObject, SL_IID_EFFECTSEND, &playerEffectSend); 4360a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 4370a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerEffectSend)->EnableEffectSend(playerEffectSend, mixEnvironmentalReverb, 4380a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SL_BOOLEAN_TRUE, (SLmillibel) 0); 4390a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 4400a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 4410a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 4429a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten // get the playback rate interface and configure the rate 4439a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten SLPlaybackRateItf playerPlaybackRate; 4443eaa329775fc522d8ea4acd4edc379eabf9ac332Glenn Kasten SLpermille currentRate = 0; 445f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten if (enablePlaybackRate) { 446f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAYBACKRATE, 447f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten &playerPlaybackRate); 448f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten assert(SL_RESULT_SUCCESS == result); 449f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten SLpermille defaultRate; 450f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten result = (*playerPlaybackRate)->GetRate(playerPlaybackRate, &defaultRate); 451f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten assert(SL_RESULT_SUCCESS == result); 452f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten SLuint32 defaultProperties; 453f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten result = (*playerPlaybackRate)->GetProperties(playerPlaybackRate, &defaultProperties); 454f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten assert(SL_RESULT_SUCCESS == result); 455f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten printf("default playback rate %d per mille, properties 0x%x\n", defaultRate, 456f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten defaultProperties); 457f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten if (initialRate <= 0) { 458f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten initialRate = defaultRate; 459f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten } 460f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten if (finalRate <= 0) { 461f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten finalRate = initialRate; 462f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten } 463f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten currentRate = defaultRate; 464f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten if (finalRate == initialRate) { 465701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten deltaRate = 0; 466f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten } else if (finalRate < initialRate) { 467f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten deltaRate = -deltaRate; 468f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten } 469f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten if (initialRate != defaultRate) { 470f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten result = (*playerPlaybackRate)->SetRate(playerPlaybackRate, initialRate); 471f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten if (SL_RESULT_FEATURE_UNSUPPORTED == result) { 472f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten fprintf(stderr, "initial playback rate %d is unsupported\n", initialRate); 473f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten deltaRate = 0; 474f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten } else if (SL_RESULT_PARAMETER_INVALID == result) { 475f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten fprintf(stderr, "initial playback rate %d is invalid\n", initialRate); 476f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten deltaRate = 0; 477f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten } else { 478f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten assert(SL_RESULT_SUCCESS == result); 479f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten currentRate = initialRate; 480f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten } 4819a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten } 4829a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten } 4839a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten 4840a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // get the play interface 4850a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLPlayItf playerPlay; 4860a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay); 4870a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 4880a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 4890a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // get the buffer queue interface 4900a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLBufferQueueItf playerBufferQueue; 4910a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE, 4920a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten &playerBufferQueue); 4930a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 4940a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 4950a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // loop until EOF or no more buffers 4960a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten for (which = 0; which < numBuffers; ++which) { 497c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung void *buffer = (char *)buffers + framesPerBuffer * sfframesize * which; 4980a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten sf_count_t frames = framesPerBuffer; 4990a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten sf_count_t count; 500c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung switch (transferFormat) { 501c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_FLOAT: 502c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung count = sf_readf_float(sndfile, (float *) buffer, frames); 503c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 504c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_32_BIT: 505c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung count = sf_readf_int(sndfile, (int *) buffer, frames); 506c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 507c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_24_BIT_PACKED: 508c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung count = sf_readf_int(sndfile, (int *) buffer, frames); 509c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 510c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_16_BIT: 511c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_8_BIT: 512c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung count = sf_readf_short(sndfile, (short *) buffer, frames); 513c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 514c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung default: 515c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung count = 0; 516c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 517c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung } 5180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (0 >= count) { 5190a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten eof = SL_BOOLEAN_TRUE; 5200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 5210a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 5220a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 5230a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // enqueue a buffer 524c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung SLuint32 nbytes = count * sfframesize; 525bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten nbytes = squeeze(buffer, nbytes); 526ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, nbytes); 5270a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 5280a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 529701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten if (which >= numBuffers) { 5300a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten which = 0; 531701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } 5320a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 5330a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // register a callback on the buffer queue 5340a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, callback, NULL); 5350a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 5360a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 537208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten#define FIFO_FRAMES 16384 538bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten void *fifoBuffer = malloc(FIFO_FRAMES * sfframesize); 539bf76782721537b71e404bd5c6350e91dfda74487Glenn Kasten audio_utils_fifo_init(&fifo, FIFO_FRAMES, sfframesize, fifoBuffer); 540ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten 541ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten // create thread to read from file 542ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten pthread_t thread; 543ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten int ok = pthread_create(&thread, (const pthread_attr_t *) NULL, file_reader_loop, NULL); 544ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten assert(0 == ok); 545ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten 546ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten // give thread a head start so that the pipe is initially filled 547ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten sleep(1); 548ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten 5490a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // set the player's state to playing 5500a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING); 5510a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 5520a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 553701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten // get the initial time 554701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten struct timespec prevTs; 555701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten clock_gettime(CLOCK_MONOTONIC, &prevTs); 556701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten long elapsedNs = 0; 557701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten long deltaRateNs = deltaRateMs * 1000000; 558701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten 5590a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // wait until the buffer queue is empty 5600a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLBufferQueueState bufqstate; 5610a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten for (;;) { 5620a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerBufferQueue)->GetState(playerBufferQueue, &bufqstate); 5630a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 5640a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (0 >= bufqstate.count) { 5650a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 5660a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 567f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten if (!enablePlaybackRate || deltaRate == 0) { 568701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten sleep(1); 569701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } else { 570701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten struct timespec curTs; 571701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten clock_gettime(CLOCK_MONOTONIC, &curTs); 572701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten elapsedNs += (curTs.tv_sec - prevTs.tv_sec) * 1000000000 + 573701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten // this term can be negative 574701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten (curTs.tv_nsec - prevTs.tv_nsec); 575701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten prevTs = curTs; 576701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten if (elapsedNs < deltaRateNs) { 577701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten usleep((deltaRateNs - elapsedNs) / 1000); 578701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten continue; 579701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } 580701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten elapsedNs -= deltaRateNs; 581701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten SLpermille nextRate = currentRate + deltaRate; 582701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten result = (*playerPlaybackRate)->SetRate(playerPlaybackRate, nextRate); 583701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten if (SL_RESULT_SUCCESS != result) { 584701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, "next playback rate %d is unsupported\n", nextRate); 585701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } else if (SL_RESULT_PARAMETER_INVALID == result) { 586701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, "next playback rate %d is invalid\n", nextRate); 587701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } else { 588701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten assert(SL_RESULT_SUCCESS == result); 589701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } 590701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten currentRate = nextRate; 591701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten if (currentRate >= max(initialRate, finalRate)) { 592701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten currentRate = max(initialRate, finalRate); 593701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten deltaRate = -abs(deltaRate); 594701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } else if (currentRate <= min(initialRate, finalRate)) { 595701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten currentRate = min(initialRate, finalRate); 596701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten deltaRate = abs(deltaRate); 597701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } 598701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } 599208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten 6000a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 6010a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 602208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten // wait for reader thread to exit 603208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten ok = pthread_join(thread, (void **) NULL); 604208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten assert(0 == ok); 605208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten 606208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten // set the player's state to stopped 607208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_STOPPED); 608208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten assert(SL_RESULT_SUCCESS == result); 609208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten 6100a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // destroy audio player 6110a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten (*playerObject)->Destroy(playerObject); 6120a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 613208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten audio_utils_fifo_deinit(&fifo); 614208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten free(fifoBuffer); 615208a2dae4b1bc98de4282f08c5b5acad0d797eb0Glenn Kasten 616ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten } 617ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten 618701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kastenno_player: 619701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten 6200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // destroy output mix 6210a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten (*outputMixObject)->Destroy(outputMixObject); 6220a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 6230a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // destroy engine 6240a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten (*engineObject)->Destroy(engineObject); 6250a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 626ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten } 627ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten 628701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kastenclose_sndfile: 629701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten 630701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten (void) sf_close(sndfile); 631701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten 6320a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten return EXIT_SUCCESS; 6330a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten} 634