slesTestFeedback.cpp revision 01e9f5fa4698856f92bcfd88188ee4c8397b22db
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17// Test program to record from default audio input and playback to default audio output 18 19#undef NDEBUG 20 21#include "SLES/OpenSLES.h" 22#include "SLES/OpenSLES_Android.h" 23#include <assert.h> 24#include <stdio.h> 25#include <stdlib.h> 26#include <string.h> 27#include <unistd.h> 28 29#define ASSERT_EQ(x, y) do { if ((x) == (y)) ; else { fprintf(stderr, "0x%x != 0x%x\n", \ 30 (unsigned) (x), (unsigned) (y)); assert((x) == (y)); } } while (0) 31 32// default values 33static SLuint32 rxBufCount = 1; // -r# 34static SLuint32 txBufCount = 2; // -t# 35static SLuint32 bufSizeInFrames = 512; // -f# 36static SLuint32 channels = 2; // -c# 37static SLuint32 sampleRate = 44100; // -s# 38static SLuint32 appBufCount = 0; // -n# 39static SLuint32 bufSizeInBytes = 0; // calculated 40static SLboolean verbose = SL_BOOLEAN_FALSE; 41 42// Storage area for the buffers 43static char *buffers = NULL; 44 45// Index of which buffer to enqueue next 46static SLuint32 whichRecord; 47static SLuint32 whichPlay; 48 49SLAndroidSimpleBufferQueueItf recorderBufferQueue; 50SLBufferQueueItf playerBufferQueue; 51 52// Compute maximum of two values 53static SLuint32 max(SLuint32 a, SLuint32 b) 54{ 55 return a >= b ? a : b; 56} 57 58// Compute minimum of two values 59static SLuint32 min(SLuint32 a, SLuint32 b) 60{ 61 return a <= b ? a : b; 62} 63 64// Called after audio recorder fills a buffer with data 65static void recorderCallback(SLAndroidSimpleBufferQueueItf caller, void *context) 66{ 67 SLresult result; 68 if (verbose) { 69 putchar('*'); 70 fflush(stdout); 71 } 72 73 // Enqueue the next empty buffer for the recorder to fill 74 assert(whichRecord < appBufCount); 75 void *buffer = &buffers[bufSizeInBytes * whichRecord]; 76 result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, buffer, bufSizeInBytes); 77 ASSERT_EQ(SL_RESULT_SUCCESS, result); 78 if (++whichRecord >= appBufCount) 79 whichRecord = 0; 80 81 // Enqueue the just-filled buffer for the player to empty 82 assert(whichPlay < appBufCount); // sic not tx 83 buffer = &buffers[bufSizeInBytes * whichPlay]; 84 result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, bufSizeInBytes); 85 // FIXME not sure yet why this is overflowing 86 if (SL_RESULT_SUCCESS == result) { 87 if (++whichPlay >= appBufCount) 88 whichPlay = 0; 89 } else { 90 ASSERT_EQ(SL_RESULT_BUFFER_INSUFFICIENT, result); 91 } 92 93} 94 95int main(int argc, char **argv) 96{ 97 // process command-line options 98 int i; 99 for (i = 1; i < argc; ++i) { 100 char *arg = argv[i]; 101 if (arg[0] != '-') 102 break; 103 // -r# number of receive buffers 104 if (!strncmp(arg, "-r", 2)) { 105 rxBufCount = atoi(&arg[2]); 106 if (rxBufCount < 1 || rxBufCount > 8) 107 fprintf(stderr, "%s: unusual receive buffer queue size (%u buffers)", argv[0], 108 (unsigned) rxBufCount); 109 // -t# number of receive buffers 110 } else if (!strncmp(arg, "-t", 2)) { 111 txBufCount = atoi(&arg[2]); 112 if (txBufCount < 1 || txBufCount > 8) 113 fprintf(stderr, "%s: unusual transmit buffer queue size (%u buffers)", argv[0], 114 (unsigned) txBufCount); 115 // -n# number of application buffers 116 } else if (!strncmp(arg, "-n", 2)) { 117 appBufCount = atoi(&arg[2]); 118 // -f# size of each buffer in frames 119 } else if (!strncmp(arg, "-f", 2)) { 120 bufSizeInFrames = atoi(&arg[2]); 121 if (bufSizeInFrames == 0) { 122 fprintf(stderr, "%s: unusual buffer size (%u frames)\n", argv[0], 123 (unsigned) bufSizeInFrames); 124 } 125 // -c1 mono or -c2 stereo 126 } else if (!strncmp(arg, "-c", 2)) { 127 channels = atoi(&arg[2]); 128 if (channels < 1 || channels > 2) { 129 fprintf(stderr, "%s: unusual channel count ignored (%u)\n", argv[0], 130 (unsigned) channels); 131 channels = 2; 132 } 133 // -s# sample rate in Hz 134 } else if (!strncmp(arg, "-s", 2)) { 135 sampleRate = atoi(&arg[2]); 136 switch (sampleRate) { 137 case 8000: 138 case 11025: 139 case 16000: 140 case 22050: 141 case 32000: 142 case 44100: 143 break; 144 default: 145 fprintf(stderr, "%s: unusual sample rate (%u Hz)\n", argv[0], 146 (unsigned) sampleRate); 147 break; 148 } 149 // -v verbose 150 } else if (!strcmp(arg, "-v")) { 151 verbose = SL_BOOLEAN_TRUE; 152 } else 153 fprintf(stderr, "%s: unknown option %s\n", argv[0], arg); 154 } 155 if (i < argc) { 156 fprintf(stderr, "usage: %s -r# -t# -f# -r# -m/-s\n", argv[0]); 157 fprintf(stderr, " -r# receive buffer queue count for microphone input, default 1\n"); 158 fprintf(stderr, " -t# transmit buffer queue count for speaker output, default 2\n"); 159 fprintf(stderr, " -f# number of frames per buffer, default 512\n"); 160 fprintf(stderr, " -s# sample rate in Hz, default 44100\n"); 161 fprintf(stderr, " -n# number of application-allocated buffers, default max(-r#,-t#)\n"); 162 fprintf(stderr, " -c1 mono\n"); 163 fprintf(stderr, " -c2 stereo, default\n"); 164 } 165 if (appBufCount == 0) 166 appBufCount = max(rxBufCount, txBufCount); 167 if (appBufCount == 0) 168 appBufCount = 1; 169 if (appBufCount < max(rxBufCount, txBufCount)) 170 fprintf(stderr, "%s: unusual application buffer count (%u buffers)", argv[0], 171 (unsigned) appBufCount); 172 bufSizeInBytes = channels * bufSizeInFrames * sizeof(short); 173 buffers = (char *) malloc(bufSizeInBytes * appBufCount); 174 SLresult result; 175 176 // create engine 177 SLObjectItf engineObject; 178 result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); 179 ASSERT_EQ(SL_RESULT_SUCCESS, result); 180 result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); 181 ASSERT_EQ(SL_RESULT_SUCCESS, result); 182 SLEngineItf engineEngine; 183 result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); 184 ASSERT_EQ(SL_RESULT_SUCCESS, result); 185 186 // create output mix 187 SLObjectItf outputmixObject; 188 result = (*engineEngine)->CreateOutputMix(engineEngine, &outputmixObject, 0, NULL, NULL); 189 ASSERT_EQ(SL_RESULT_SUCCESS, result); 190 result = (*outputmixObject)->Realize(outputmixObject, SL_BOOLEAN_FALSE); 191 ASSERT_EQ(SL_RESULT_SUCCESS, result); 192 193 // create an audio player with buffer queue source and output mix sink 194 SLDataSource audiosrc; 195 SLDataSink audiosnk; 196 SLDataFormat_PCM pcm; 197 SLDataLocator_OutputMix locator_outputmix; 198 SLDataLocator_BufferQueue locator_bufferqueue_tx; 199 locator_bufferqueue_tx.locatorType = SL_DATALOCATOR_BUFFERQUEUE; 200 locator_bufferqueue_tx.numBuffers = txBufCount; 201 locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; 202 locator_outputmix.outputMix = outputmixObject; 203 pcm.formatType = SL_DATAFORMAT_PCM; 204 pcm.numChannels = channels; 205 pcm.samplesPerSec = sampleRate * 1000; 206 pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; 207 pcm.containerSize = 16; 208 pcm.channelMask = channels == 1 ? SL_SPEAKER_FRONT_CENTER : 209 (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT); 210 pcm.endianness = SL_BYTEORDER_LITTLEENDIAN; 211 audiosrc.pLocator = &locator_bufferqueue_tx; 212 audiosrc.pFormat = &pcm; 213 audiosnk.pLocator = &locator_outputmix; 214 audiosnk.pFormat = NULL; 215 SLObjectItf playerObject; 216 SLInterfaceID ids_tx[1] = {SL_IID_BUFFERQUEUE}; 217 SLboolean flags_tx[1] = {SL_BOOLEAN_TRUE}; 218 result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audiosrc, &audiosnk, 219 1, ids_tx, flags_tx); 220 ASSERT_EQ(SL_RESULT_SUCCESS, result); 221 result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE); 222 ASSERT_EQ(SL_RESULT_SUCCESS, result); 223 SLPlayItf playerPlay; 224 result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay); 225 ASSERT_EQ(SL_RESULT_SUCCESS, result); 226 result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE, &playerBufferQueue); 227 ASSERT_EQ(SL_RESULT_SUCCESS, result); 228 result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING); 229 ASSERT_EQ(SL_RESULT_SUCCESS, result); 230 231 // Create an audio recorder with microphone device source and buffer queue sink. 232 // The buffer queue as sink is an Android-specific extension. 233 234 SLDataLocator_IODevice locator_iodevice; 235 SLDataLocator_AndroidSimpleBufferQueue locator_bufferqueue_rx; 236 locator_iodevice.locatorType = SL_DATALOCATOR_IODEVICE; 237 locator_iodevice.deviceType = SL_IODEVICE_AUDIOINPUT; 238 locator_iodevice.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT; 239 locator_iodevice.device = NULL; 240 audiosrc.pLocator = &locator_iodevice; 241 audiosrc.pFormat = &pcm; 242 locator_bufferqueue_rx.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; 243 locator_bufferqueue_rx.numBuffers = rxBufCount; 244 audiosnk.pLocator = &locator_bufferqueue_rx; 245 audiosnk.pFormat = &pcm; 246 SLObjectItf recorderObject; 247 SLInterfaceID ids_rx[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE}; 248 SLboolean flags_rx[1] = {SL_BOOLEAN_TRUE}; 249 result = (*engineEngine)->CreateAudioRecorder(engineEngine, &recorderObject, &audiosrc, 250 &audiosnk, 1, ids_rx, flags_rx); 251 ASSERT_EQ(SL_RESULT_SUCCESS, result); 252 result = (*recorderObject)->Realize(recorderObject, SL_BOOLEAN_FALSE); 253 ASSERT_EQ(SL_RESULT_SUCCESS, result); 254 SLRecordItf recorderRecord; 255 result = (*recorderObject)->GetInterface(recorderObject, SL_IID_RECORD, &recorderRecord); 256 ASSERT_EQ(SL_RESULT_SUCCESS, result); 257 result = (*recorderObject)->GetInterface(recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, 258 &recorderBufferQueue); 259 ASSERT_EQ(SL_RESULT_SUCCESS, result); 260 result = (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, recorderCallback, NULL); 261 ASSERT_EQ(SL_RESULT_SUCCESS, result); 262 263 // Enqueue some empty buffers for the recorder 264 SLuint32 temp = min(rxBufCount, appBufCount); 265 for (whichRecord = 0; whichRecord < (temp <= 1 ? 1 : temp - 1); ++whichRecord) { 266 result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, 267 &buffers[bufSizeInBytes * whichRecord], bufSizeInBytes); 268 ASSERT_EQ(SL_RESULT_SUCCESS, result); 269 } 270 if (whichRecord >= appBufCount) 271 whichRecord = 0; 272 273 // Kick off the recorder 274 whichPlay = 0; 275 result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING); 276 ASSERT_EQ(SL_RESULT_SUCCESS, result); 277 278 // Wait patiently 279 for (;;) { 280 usleep(1000000); 281 putchar('.'); 282 SLBufferQueueState playerBQState; 283 result = (*playerBufferQueue)->GetState(playerBufferQueue, &playerBQState); 284 ASSERT_EQ(SL_RESULT_SUCCESS, result); 285 SLAndroidSimpleBufferQueueState recorderBQState; 286 result = (*recorderBufferQueue)->GetState(recorderBufferQueue, &recorderBQState); 287 ASSERT_EQ(SL_RESULT_SUCCESS, result); 288 if (verbose) { 289 printf("pC%u pI%u rC%u rI%u\n", (unsigned) playerBQState.count, 290 (unsigned) playerBQState.playIndex, (unsigned) recorderBQState.count, 291 (unsigned) recorderBQState.index); 292 fflush(stdout); 293 } 294 } 295 296 //return EXIT_SUCCESS; 297} 298