| /* |
| * Copyright (C) 2010 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* interactive buffer queue test program */ |
| |
| #ifdef ANDROID |
| #define USE_ANDROID_SIMPLE_BUFFER_QUEUE // change to #undef for compatibility testing |
| #endif |
| |
| #include <assert.h> |
| #include <math.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <SLES/OpenSLES.h> |
| #ifdef USE_ANDROID_SIMPLE_BUFFER_QUEUE |
| #include <SLES/OpenSLES_Android.h> |
| #endif |
| #include "getch.h" |
| |
| #ifdef USE_ANDROID_SIMPLE_BUFFER_QUEUE |
| #define DATALOCATOR_BUFFERQUEUE SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE |
| #define IID_BUFFERQUEUE SL_IID_ANDROIDSIMPLEBUFFERQUEUE |
| #define BufferQueueItf SLAndroidSimpleBufferQueueItf |
| #define BufferQueueState SLAndroidSimpleBufferQueueState |
| #define INDEX index |
| #else |
| #define DATALOCATOR_BUFFERQUEUE SL_DATALOCATOR_BUFFERQUEUE |
| #define IID_BUFFERQUEUE SL_IID_BUFFERQUEUE |
| #define BufferQueueItf SLBufferQueueItf |
| #define BufferQueueState SLBufferQueueState |
| #define INDEX playIndex |
| #endif |
| |
| #define checkResult(r) do { if ((r) != SL_RESULT_SUCCESS) fprintf(stderr, "error %d at %s:%d\n", \ |
| (int) r, __FILE__, __LINE__); } while (0) |
| |
| typedef struct { |
| short left; |
| short right; |
| } frame_t; |
| |
| #define SINE_FRAMES (44100*5) |
| frame_t sine[SINE_FRAMES]; |
| |
| #define SQUARE_FRAMES (44100*5) |
| frame_t square[SQUARE_FRAMES]; |
| |
| #define SAWTOOTH_FRAMES (44100*5) |
| frame_t sawtooth[SAWTOOTH_FRAMES]; |
| |
| #define HALF_FRAMES (44100*5) |
| frame_t half[HALF_FRAMES]; |
| |
| BufferQueueItf expectedCaller = NULL; |
| void *expectedContext = NULL; |
| |
| static void callback(BufferQueueItf caller, void *context) |
| { |
| putchar('.'); |
| if (caller != expectedCaller) |
| printf("caller %p expected %p\r\n", caller, expectedCaller); |
| if (context != expectedContext) |
| printf("context %p expected %p\r\n", context, expectedContext); |
| fflush(stdout); |
| } |
| |
| int main(int argc, char **argv) |
| { |
| SLresult result; |
| |
| // create engine |
| SLObjectItf engineObject; |
| result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); |
| checkResult(result); |
| result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); |
| checkResult(result); |
| SLEngineItf engineEngine; |
| result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); |
| checkResult(result); |
| |
| // create output mix |
| SLObjectItf outputmixObject; |
| result = (*engineEngine)->CreateOutputMix(engineEngine, &outputmixObject, 0, NULL, NULL); |
| checkResult(result); |
| result = (*outputmixObject)->Realize(outputmixObject, SL_BOOLEAN_FALSE); |
| checkResult(result); |
| |
| // create audio player |
| SLDataSource audiosrc; |
| SLDataSink audiosnk; |
| SLDataFormat_PCM pcm; |
| SLDataLocator_OutputMix locator_outputmix; |
| SLDataLocator_BufferQueue locator_bufferqueue; |
| locator_bufferqueue.locatorType = DATALOCATOR_BUFFERQUEUE; |
| locator_bufferqueue.numBuffers = 255; |
| locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; |
| locator_outputmix.outputMix = outputmixObject; |
| pcm.formatType = SL_DATAFORMAT_PCM; |
| pcm.numChannels = 2; |
| pcm.samplesPerSec = SL_SAMPLINGRATE_44_1; |
| pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; |
| pcm.containerSize = 16; |
| pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; |
| pcm.endianness = SL_BYTEORDER_LITTLEENDIAN; |
| audiosrc.pLocator = &locator_bufferqueue; |
| audiosrc.pFormat = &pcm; |
| audiosnk.pLocator = &locator_outputmix; |
| audiosnk.pFormat = NULL; |
| SLObjectItf playerObject; |
| SLInterfaceID ids[2] = {IID_BUFFERQUEUE, SL_IID_MUTESOLO}; |
| SLboolean flags[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; |
| result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audiosrc, &audiosnk, |
| 2, ids, flags); |
| checkResult(result); |
| result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE); |
| checkResult(result); |
| SLPlayItf playerPlay; |
| result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay); |
| checkResult(result); |
| BufferQueueItf playerBufferqueue; |
| result = (*playerObject)->GetInterface(playerObject, IID_BUFFERQUEUE, &playerBufferqueue); |
| checkResult(result); |
| SLMuteSoloItf playerMuteSolo; |
| result = (*playerObject)->GetInterface(playerObject, SL_IID_MUTESOLO, &playerMuteSolo); |
| checkResult(result); |
| SLuint8 numChannels = 123; |
| result = (*playerMuteSolo)->GetNumChannels(playerMuteSolo, &numChannels); |
| assert(2 == numChannels); |
| SLuint32 state; |
| state = SL_PLAYSTATE_PLAYING; |
| result = (*playerPlay)->SetPlayState(playerPlay, state); |
| checkResult(result); |
| |
| unsigned i; |
| float pi2 = 3.14*2; |
| float hz = 441; |
| float sr = 44100; |
| for (i = 0; i < SINE_FRAMES; ++i) { |
| sine[i].left = sin((float) (i / (sr / hz)) * pi2 ) * 32000.0; |
| sine[i].right = sine[i].left; |
| } |
| for (i = 0; i < SQUARE_FRAMES; ++i) { |
| square[i].left = (i % (unsigned) (sr / hz)) < 50 ? 32767 : -32768; |
| square[i].right = square[i].left; |
| } |
| for (i = 0; i < SAWTOOTH_FRAMES; ++i) { |
| sawtooth[i].left = ((((int) (i % (unsigned) (sr / hz))) - 50) / 100.0) * 60000.0 - 30000.0; |
| sawtooth[i].right = sawtooth[i].left; |
| } |
| for (i = 0; i < HALF_FRAMES; ++i) { |
| half[i].left = sine[i].left; |
| half[i].right = sawtooth[i].right / 2; |
| } |
| |
| set_conio_terminal_mode(); |
| int in_count = 0; |
| unsigned count = 0; |
| for (;;) { |
| usleep(10000); |
| if (kbhit()) { |
| frame_t *buffer; |
| unsigned size; |
| BufferQueueState bufqstate; |
| int ch = getch(); |
| switch (ch) { |
| case '0' ... '9': |
| if (in_count) { |
| count = count * 10 + (ch - '0'); |
| } else { |
| count = ch - '0'; |
| in_count = 1; |
| } |
| continue; |
| case 'i': |
| buffer = sine; |
| size = sizeof(sine); |
| goto enqueue; |
| case 'q': |
| buffer = square; |
| size = sizeof(square); |
| goto enqueue; |
| case 'h': |
| buffer = half; |
| size = sizeof(half); |
| goto enqueue; |
| case 'r': |
| if (in_count) { |
| expectedCaller = playerBufferqueue; |
| expectedContext = (void *) count; |
| } else { |
| expectedCaller = NULL; |
| expectedContext = (void *) NULL; |
| } |
| result = (*playerBufferqueue)->RegisterCallback(playerBufferqueue, in_count ? |
| callback : NULL, expectedContext); |
| checkResult(result); |
| break; |
| case 'a': |
| buffer = sawtooth; |
| size = sizeof(sawtooth); |
| enqueue: |
| for (i = 0; i < (in_count ? count : 1); ++i) { |
| result = (*playerBufferqueue)->Enqueue(playerBufferqueue, buffer, size); |
| checkResult(result); |
| } |
| break; |
| case 'c': |
| result = (*playerBufferqueue)->Clear(playerBufferqueue); |
| checkResult(result); |
| putchar('\r'); |
| result = (*playerBufferqueue)->GetState(playerBufferqueue, &bufqstate); |
| checkResult(result); |
| if (bufqstate.count != 0) |
| printf("\rcount=%u\r\n", (unsigned) bufqstate.count); |
| #if 0 |
| putchar('\r'); |
| putchar('\n'); |
| #endif |
| fflush(stdout); |
| break; |
| case 'g': |
| result = (*playerBufferqueue)->GetState(playerBufferqueue, &bufqstate); |
| checkResult(result); |
| printf("\rplayIndex=%u\r\n", (unsigned) bufqstate.INDEX); |
| printf("count=%u\r\n", (unsigned) bufqstate.count); |
| break; |
| case 'p': |
| state = SL_PLAYSTATE_PAUSED; |
| goto setplaystate; |
| case 's': |
| state = SL_PLAYSTATE_STOPPED; |
| goto setplaystate; |
| case 'P': |
| state = SL_PLAYSTATE_PLAYING; |
| setplaystate: |
| result = (*playerPlay)->SetPlayState(playerPlay, state); |
| checkResult(result); |
| SLuint32 newstate; |
| result = (*playerPlay)->GetPlayState(playerPlay, &newstate); |
| checkResult(result); |
| if (newstate != state) |
| printf("\rSetPlayState(%u) -> GetPlayState(%u)\r\n", (unsigned) state, |
| (unsigned) newstate); |
| #if 0 |
| putchar('\r'); |
| putchar('\n'); |
| fflush(stdout); |
| #endif |
| checkResult(result); |
| break; |
| case 'x': |
| goto out; |
| default: |
| putchar('?'); |
| fflush(stdout); |
| break; |
| } |
| in_count = 0; |
| } |
| } |
| |
| out: |
| (*playerObject)->Destroy(playerObject); |
| (*outputmixObject)->Destroy(outputmixObject); |
| (*engineObject)->Destroy(engineObject); |
| return EXIT_SUCCESS; |
| } |