playbq.c revision ebca1a420c4ada9eff2e82f0100abaea95b48f24
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> 240a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <unistd.h> 250a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 26c6853892c94800e72c0bd676d5d2136d48cea76eGlenn Kasten#include <SLES/OpenSLES.h> 270a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#ifdef ANDROID 280a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include "sndfile.h" 290a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#else 300a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <sndfile.h> 310a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#endif 320a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 330a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenunsigned numBuffers = 2; 340a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenint framesPerBuffer = 512; 350a058cc3d720cdf3f0f8222472a862258482f34fGlenn KastenSNDFILE *sndfile; 360a058cc3d720cdf3f0f8222472a862258482f34fGlenn KastenSF_INFO sfinfo; 370a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenunsigned which; // which buffer to use next 380a058cc3d720cdf3f0f8222472a862258482f34fGlenn KastenSLboolean eof; // whether we have hit EOF on input yet 390a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenshort *buffers; 40ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn KastenSLuint32 byteOrder; // desired to use for PCM buffers 41ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn KastenSLuint32 nativeByteOrder; // of platform 42ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn KastenSLuint32 bitsPerSample = 16; 43ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten 44ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten// swap adjacent bytes; this would normally be in <unistd.h> but is missing here 45ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kastenstatic void swab(const void *from, void *to, ssize_t n) 46ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten{ 47ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten // from and to as char pointers 48ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten const char *from_ch = (const char *) from; 49ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten char *to_ch = (char *) to; 50ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten // note that we don't swap the last odd byte 51ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten while (n >= 2) { 52ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten to_ch[0] = from_ch[1]; 53ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten to_ch[1] = from_ch[0]; 54ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten to_ch += 2; 55ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten from_ch += 2; 56ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten n -= 2; 57ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } 58ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten} 59ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten 60ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten// squeeze 16-bit signed PCM samples down to 8-bit unsigned PCM samples by truncation; no dithering 61ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kastenstatic void squeeze(const short *from, unsigned char *to, ssize_t n) 62ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten{ 63ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten // note that we don't squeeze the last odd byte 64ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten while (n >= 2) { 65ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten *to++ = (*from++ + 32768) >> 8; 66ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten n -= 2; 67ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } 68ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten} 690a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 700a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten// This callback is called each time a buffer finishes playing 710a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 720a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenstatic void callback(SLBufferQueueItf bufq, void *param) 730a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten{ 749a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten assert(NULL == param); 750a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (!eof) { 760a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten short *buffer = &buffers[framesPerBuffer * sfinfo.channels * which]; 770a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten sf_count_t count; 780a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten count = sf_readf_short(sndfile, buffer, (sf_count_t) framesPerBuffer); 790a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (0 >= count) { 800a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten eof = SL_BOOLEAN_TRUE; 810a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } else { 82ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten SLuint32 nbytes = count * sfinfo.channels * sizeof(short); 83ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten if (byteOrder != nativeByteOrder) { 84ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten swab(buffer, buffer, nbytes); 85ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } 86ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten if (bitsPerSample == 8) { 87ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten squeeze(buffer, (unsigned char *) buffer, nbytes); 88ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten nbytes /= 2; 89ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } 90ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten SLresult result = (*bufq)->Enqueue(bufq, buffer, nbytes); 910a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 920a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (++which >= numBuffers) 930a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten which = 0; 940a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 950a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 960a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten} 970a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 980a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenint main(int argc, char **argv) 990a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten{ 100ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten // Determine the native byte order (SL_BYTEORDER_NATIVE not available until 1.1) 101ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten union { 102ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten short s; 103ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten char c[2]; 104ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } u; 105ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten u.s = 0x1234; 106ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten if (u.c[0] == 0x34) { 107ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten nativeByteOrder = SL_BYTEORDER_LITTLEENDIAN; 108ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } else if (u.c[0] == 0x12) { 109ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten nativeByteOrder = SL_BYTEORDER_BIGENDIAN; 110ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } else { 111ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten fprintf(stderr, "Unable to determine native byte order\n"); 112ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten return EXIT_FAILURE; 113ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } 114ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten byteOrder = nativeByteOrder; 115ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten 1160a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLboolean enableReverb = SL_BOOLEAN_FALSE; 1179a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten SLpermille rate = 1000; 1180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 1190a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // process command-line options 1200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten int i; 1210a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten for (i = 1; i < argc; ++i) { 1220a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten char *arg = argv[i]; 1230a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (arg[0] != '-') 1240a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 125ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten if (!strcmp(arg, "-b")) { 126ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten byteOrder = SL_BYTEORDER_BIGENDIAN; 127ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } else if (!strcmp(arg, "-l")) { 128ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten byteOrder = SL_BYTEORDER_LITTLEENDIAN; 129ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } else if (!strcmp(arg, "-8")) { 130ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten bitsPerSample = 8; 131ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } else if (!strncmp(arg, "-f", 2)) { 1320a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten framesPerBuffer = atoi(&arg[2]); 1330a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } else if (!strncmp(arg, "-n", 2)) { 1340a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten numBuffers = atoi(&arg[2]); 1359a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten } else if (!strncmp(arg, "-p", 2)) { 1369a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten rate = atoi(&arg[2]); 1370a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } else if (!strcmp(arg, "-r")) { 1380a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten enableReverb = SL_BOOLEAN_TRUE; 1390a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } else { 1400a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten fprintf(stderr, "option %s ignored\n", arg); 1410a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 1420a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 1430a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 1440a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (argc - i != 1) { 145ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten fprintf(stderr, "usage: [-b/l] [-8] [-f#] [-n#] [-p#] [-r] %s filename\n", argv[0]); 1460a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten return EXIT_FAILURE; 1470a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 1480a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 1490a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten const char *filename = argv[i]; 1500a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten //memset(&sfinfo, 0, sizeof(SF_INFO)); 1510a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten sfinfo.format = 0; 1520a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten sndfile = sf_open(filename, SFM_READ, &sfinfo); 1530a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (NULL == sndfile) { 1540a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten perror(filename); 1550a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten return EXIT_FAILURE; 1560a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 1570a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 1580a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // verify the file format 1590a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten switch (sfinfo.channels) { 1600a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 1: 1610a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 2: 1620a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 1630a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten default: 1640a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten fprintf(stderr, "unsupported channel count %d\n", sfinfo.channels); 1650a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 1660a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 1670a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten switch (sfinfo.samplerate) { 1680a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 8000: 1690a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 11025: 1700a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 12000: 1710a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 16000: 1720a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 22050: 1730a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 24000: 1740a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 32000: 1750a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 44100: 1760a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 48000: 1770a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 1780a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten default: 1790a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten fprintf(stderr, "unsupported sample rate %d\n", sfinfo.samplerate); 1800a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 1810a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 1820a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten switch (sfinfo.format & SF_FORMAT_TYPEMASK) { 1830a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case SF_FORMAT_WAV: 1840a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 1850a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten default: 1860a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten fprintf(stderr, "unsupported format type 0x%x\n", sfinfo.format & SF_FORMAT_TYPEMASK); 1870a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 1880a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 1890a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten switch (sfinfo.format & SF_FORMAT_SUBMASK) { 1900a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case SF_FORMAT_PCM_16: 1910a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case SF_FORMAT_PCM_U8: 1920a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case SF_FORMAT_ULAW: 1930a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case SF_FORMAT_ALAW: 1940a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case SF_FORMAT_IMA_ADPCM: 1950a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 1960a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten default: 1970a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten fprintf(stderr, "unsupported sub-format 0x%x\n", sfinfo.format & SF_FORMAT_SUBMASK); 1980a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 1990a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 2000a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 2010a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten buffers = (short *) malloc(framesPerBuffer * sfinfo.channels * sizeof(short) * numBuffers); 2020a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 2030a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // create engine 2040a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLresult result; 2050a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLObjectItf engineObject; 2060a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); 2070a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 2080a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLEngineItf engineEngine; 2090a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); 2100a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 2110a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); 2120a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 2130a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 2140a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // create output mix 2150a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLObjectItf outputMixObject; 2160a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB}; 2170a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLboolean req[1] = {SL_BOOLEAN_TRUE}; 2180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, enableReverb ? 1 : 0, 2190a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten ids, req); 2200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 2210a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); 2220a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 2230a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 2240a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // configure environmental reverb on output mix 2250a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLEnvironmentalReverbItf mixEnvironmentalReverb = NULL; 2260a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (enableReverb) { 2270a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB, 2280a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten &mixEnvironmentalReverb); 2290a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 2300a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLEnvironmentalReverbSettings settings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR; 2310a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*mixEnvironmentalReverb)->SetEnvironmentalReverbProperties(mixEnvironmentalReverb, 2320a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten &settings); 2330a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 2340a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 2350a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 2360a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // configure audio source 2370a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLDataLocator_BufferQueue loc_bufq; 2380a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten loc_bufq.locatorType = SL_DATALOCATOR_BUFFERQUEUE; 2390a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten loc_bufq.numBuffers = numBuffers; 2400a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLDataFormat_PCM format_pcm; 2410a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten format_pcm.formatType = SL_DATAFORMAT_PCM; 2420a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten format_pcm.numChannels = sfinfo.channels; 2430a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten format_pcm.samplesPerSec = sfinfo.samplerate * 1000; 244ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten format_pcm.bitsPerSample = bitsPerSample; 2450a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten format_pcm.containerSize = format_pcm.bitsPerSample; 2460a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten format_pcm.channelMask = 1 == format_pcm.numChannels ? SL_SPEAKER_FRONT_CENTER : 2470a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; 248ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten format_pcm.endianness = byteOrder; 2490a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLDataSource audioSrc; 2500a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten audioSrc.pLocator = &loc_bufq; 2510a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten audioSrc.pFormat = &format_pcm; 2520a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 2530a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // configure audio sink 2540a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLDataLocator_OutputMix loc_outmix; 2550a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; 2560a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten loc_outmix.outputMix = outputMixObject; 2570a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLDataSink audioSnk; 2580a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten audioSnk.pLocator = &loc_outmix; 2590a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten audioSnk.pFormat = NULL; 2600a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 2610a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // create audio player 2629a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten SLInterfaceID ids2[3] = {SL_IID_BUFFERQUEUE, SL_IID_PLAYBACKRATE, SL_IID_EFFECTSEND}; 2639a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten SLboolean req2[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; 2640a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLObjectItf playerObject; 2650a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audioSrc, 2669a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten &audioSnk, enableReverb ? 3 : 2, ids2, req2); 2670a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 2680a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 2690a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // realize the player 2700a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE); 2710a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 2720a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 2730a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // get the effect send interface and enable effect send reverb for this player 2740a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (enableReverb) { 2750a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLEffectSendItf playerEffectSend; 2760a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerObject)->GetInterface(playerObject, SL_IID_EFFECTSEND, &playerEffectSend); 2770a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 2780a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerEffectSend)->EnableEffectSend(playerEffectSend, mixEnvironmentalReverb, 2790a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SL_BOOLEAN_TRUE, (SLmillibel) 0); 2800a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 2810a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 2820a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 2839a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten // get the playback rate interface and configure the rate 2849a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten SLPlaybackRateItf playerPlaybackRate; 2859a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAYBACKRATE, &playerPlaybackRate); 2869a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten assert(SL_RESULT_SUCCESS == result); 2879a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten SLpermille defaultRate; 2889a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten result = (*playerPlaybackRate)->GetRate(playerPlaybackRate, &defaultRate); 2899a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten assert(SL_RESULT_SUCCESS == result); 2909a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten SLuint32 defaultProperties; 2919a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten result = (*playerPlaybackRate)->GetProperties(playerPlaybackRate, &defaultProperties); 2929a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten assert(SL_RESULT_SUCCESS == result); 2939a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten printf("default playback rate %d per mille, properties 0x%x\n", defaultRate, defaultProperties); 2949a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten if (rate != defaultRate) { 2959a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten result = (*playerPlaybackRate)->SetRate(playerPlaybackRate, rate); 2969a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten if (SL_RESULT_FEATURE_UNSUPPORTED == result) { 2979a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten fprintf(stderr, "playback rate %d is unsupported\n", rate); 2989a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten } else if (SL_RESULT_PARAMETER_INVALID == result) { 2999a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten fprintf(stderr, "playback rate %d is invalid", rate); 3009a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten } else { 3019a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3029a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten } 3039a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten } 3049a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten 3050a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // get the play interface 3060a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLPlayItf playerPlay; 3070a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay); 3080a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3090a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 3100a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // get the buffer queue interface 3110a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLBufferQueueItf playerBufferQueue; 3120a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE, 3130a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten &playerBufferQueue); 3140a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3150a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 3160a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // loop until EOF or no more buffers 3170a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten for (which = 0; which < numBuffers; ++which) { 3180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten short *buffer = &buffers[framesPerBuffer * sfinfo.channels * which]; 3190a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten sf_count_t frames = framesPerBuffer; 3200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten sf_count_t count; 3210a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten count = sf_readf_short(sndfile, buffer, frames); 3220a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (0 >= count) { 3230a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten eof = SL_BOOLEAN_TRUE; 3240a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 3250a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 3260a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 3270a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // enqueue a buffer 328ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten SLuint32 nbytes = count * sfinfo.channels * sizeof(short); 329ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten if (byteOrder != nativeByteOrder) { 330ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten swab(buffer, buffer, nbytes); 331ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } 332ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten if (bitsPerSample == 8) { 333ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten squeeze(buffer, (unsigned char *) buffer, nbytes); 334ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten nbytes /= 2; 335ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } 336ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, nbytes); 3370a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3380a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 3390a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (which >= numBuffers) 3400a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten which = 0; 3410a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 3420a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // register a callback on the buffer queue 3430a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, callback, NULL); 3440a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3450a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 3460a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // set the player's state to playing 3470a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING); 3480a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3490a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 3500a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // wait until the buffer queue is empty 3510a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLBufferQueueState bufqstate; 3520a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten for (;;) { 3530a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerBufferQueue)->GetState(playerBufferQueue, &bufqstate); 3540a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3550a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (0 >= bufqstate.count) { 3560a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 3570a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 3580a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten sleep(1); 3590a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 3600a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 3610a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // destroy audio player 3620a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten (*playerObject)->Destroy(playerObject); 3630a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 3640a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // destroy output mix 3650a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten (*outputMixObject)->Destroy(outputMixObject); 3660a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 3670a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // destroy engine 3680a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten (*engineObject)->Destroy(engineObject); 3690a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 3700a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten return EXIT_SUCCESS; 3710a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten} 372