You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
294 lines
9.9 KiB
294 lines
9.9 KiB
/*
|
|
* 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.
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 2009 The Khronos Group Inc.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
|
* software and /or associated documentation files (the "Materials "), to deal in the
|
|
* Materials without restriction, including without limitation the rights to use, copy,
|
|
* modify, merge, publish, distribute, sublicense, and/or sell copies of the Materials,
|
|
* and to permit persons to whom the Materials are furnished to do so, subject to
|
|
* the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Materials.
|
|
*
|
|
* THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS IN THE
|
|
* MATERIALS.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sys/time.h>
|
|
|
|
|
|
#include <SLES/OpenSLES.h>
|
|
|
|
|
|
#define MAX_NUMBER_INTERFACES 3
|
|
|
|
/* Local storage for Audio data in 16 bit words */
|
|
#define AUDIO_DATA_STORAGE_SIZE (4096 * 100)
|
|
/* Audio data buffer size in 16 bit words. 8 data segments are used in
|
|
this simple example */
|
|
#define AUDIO_DATA_BUFFER_SIZE (4096/8)
|
|
|
|
/* Checks for error. If any errors exit the application! */
|
|
void CheckErr( SLresult res )
|
|
{
|
|
if ( res != SL_RESULT_SUCCESS )
|
|
{
|
|
fprintf(stdout, "%u SL failure, exiting\n", res);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
else {
|
|
//fprintf(stdout, "%d SL success, proceeding...\n", res);
|
|
}
|
|
}
|
|
|
|
/* Structure for passing information to callback function */
|
|
typedef struct CallbackCntxt_ {
|
|
SLPlayItf playItf;
|
|
SLint16* pDataBase; // Base adress of local audio data storage
|
|
SLint16* pData; // Current adress of local audio data storage
|
|
SLuint32 size;
|
|
} CallbackCntxt;
|
|
|
|
/* Local storage for Audio data */
|
|
SLint16 pcmData[AUDIO_DATA_STORAGE_SIZE];
|
|
|
|
/* Callback for Buffer Queue events */
|
|
void BufferQueueCallback(
|
|
SLBufferQueueItf queueItf,
|
|
void *pContext)
|
|
{
|
|
//fprintf(stdout, "BufferQueueCallback called\n");
|
|
SLresult res;
|
|
//fprintf(stdout, " pContext=%p\n", pContext);
|
|
CallbackCntxt *pCntxt = (CallbackCntxt*)pContext;
|
|
|
|
if(pCntxt->pData < (pCntxt->pDataBase + pCntxt->size))
|
|
{
|
|
//fprintf(stdout, "callback: before enqueue\n");
|
|
res = (*queueItf)->Enqueue(queueItf, (void*) pCntxt->pData,
|
|
2 * AUDIO_DATA_BUFFER_SIZE); /* Size given in bytes. */
|
|
CheckErr(res);
|
|
/* Increase data pointer by buffer size */
|
|
pCntxt->pData += AUDIO_DATA_BUFFER_SIZE;
|
|
}
|
|
//fprintf(stdout, "end of BufferQueueCallback()\n");
|
|
}
|
|
|
|
/* Play some audio from a buffer queue */
|
|
void TestPlaySawtoothBufferQueue( SLObjectItf sl )
|
|
{
|
|
SLEngineItf EngineItf;
|
|
|
|
SLresult res;
|
|
|
|
SLDataSource audioSource;
|
|
SLDataLocator_BufferQueue bufferQueue;
|
|
SLDataFormat_PCM pcm;
|
|
|
|
SLDataSink audioSink;
|
|
SLDataLocator_OutputMix locator_outputmix;
|
|
|
|
SLObjectItf player;
|
|
SLPlayItf playItf;
|
|
SLBufferQueueItf bufferQueueItf;
|
|
SLBufferQueueState state;
|
|
|
|
SLObjectItf OutputMix;
|
|
//SLVolumeItf volumeItf;
|
|
|
|
int i;
|
|
|
|
SLboolean required[MAX_NUMBER_INTERFACES];
|
|
SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
|
|
|
|
/* Callback context for the buffer queue callback function */
|
|
CallbackCntxt cntxt;
|
|
|
|
/* Get the SL Engine Interface which is implicit */
|
|
res = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf);
|
|
CheckErr(res);
|
|
|
|
/* Initialize arrays required[] and iidArray[] */
|
|
for (i=0;i<MAX_NUMBER_INTERFACES;i++)
|
|
{
|
|
required[i] = SL_BOOLEAN_FALSE;
|
|
iidArray[i] = SL_IID_NULL;
|
|
}
|
|
|
|
// Set arrays required[] and iidArray[] for VOLUME interface
|
|
required[0] = SL_BOOLEAN_TRUE;
|
|
iidArray[0] = SL_IID_VOLUME;
|
|
// Create Output Mix object to be used by player
|
|
res = (*EngineItf)->CreateOutputMix(EngineItf, &OutputMix, 0,
|
|
iidArray, required); CheckErr(res);
|
|
|
|
// Realizing the Output Mix object in synchronous mode.
|
|
res = (*OutputMix)->Realize(OutputMix, SL_BOOLEAN_FALSE);
|
|
CheckErr(res);
|
|
|
|
#if 0
|
|
res = (*OutputMix)->GetInterface(OutputMix, SL_IID_VOLUME,
|
|
(void*)&volumeItf); CheckErr(res);
|
|
#endif
|
|
|
|
/* Setup the data source structure for the buffer queue */
|
|
bufferQueue.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
|
|
bufferQueue.numBuffers = 4; /* Four buffers in our buffer queue */
|
|
|
|
/* Setup the format of the content in the buffer queue */
|
|
pcm.formatType = SL_DATAFORMAT_PCM;
|
|
pcm.numChannels = 1;//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;
|
|
|
|
audioSource.pFormat = (void *)&pcm;
|
|
audioSource.pLocator = (void *)&bufferQueue;
|
|
|
|
/* Setup the data sink structure */
|
|
locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
|
|
locator_outputmix.outputMix = OutputMix;
|
|
audioSink.pLocator = (void *)&locator_outputmix;
|
|
audioSink.pFormat = NULL;
|
|
|
|
/* Initialize the audio data to play */
|
|
unsigned int j;
|
|
for (j = 0; j < sizeof(pcmData)/sizeof(pcmData[0]); ++j) {
|
|
pcmData[j] = j*(100 + j / 200);// % 1000;
|
|
}
|
|
|
|
/* Initialize the context for Buffer queue callbacks */
|
|
cntxt.pDataBase = /*(void*)&*/pcmData;
|
|
cntxt.pData = cntxt.pDataBase;
|
|
cntxt.size = sizeof(pcmData) / 2;
|
|
|
|
/* Set arrays required[] and iidArray[] for SEEK interface
|
|
(PlayItf is implicit) */
|
|
required[0] = SL_BOOLEAN_TRUE;
|
|
iidArray[0] = SL_IID_BUFFERQUEUE;
|
|
|
|
/* Create the music player */
|
|
res = (*EngineItf)->CreateAudioPlayer(EngineItf, &player,
|
|
&audioSource, &audioSink, 1, iidArray, required); CheckErr(res);
|
|
fprintf(stdout, "bufferQueue example: after CreateAudioPlayer\n");
|
|
|
|
/* Realizing the player in synchronous mode. */
|
|
res = (*player)->Realize(player, SL_BOOLEAN_FALSE); CheckErr(res);
|
|
fprintf(stdout, "bufferQueue example: after Realize\n");
|
|
|
|
/* Get seek and play interfaces */
|
|
res = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf);
|
|
CheckErr(res);
|
|
fprintf(stdout, "bufferQueue example: after GetInterface(PLAY)\n");
|
|
|
|
res = (*player)->GetInterface(player, SL_IID_BUFFERQUEUE,
|
|
(void*)&bufferQueueItf); CheckErr(res);
|
|
|
|
/* Setup to receive buffer queue event callbacks */
|
|
res = (*bufferQueueItf)->RegisterCallback(bufferQueueItf,
|
|
BufferQueueCallback, &cntxt); CheckErr(res);
|
|
|
|
#if 0
|
|
/* Before we start set volume to -3dB (-300mB) */
|
|
res = (*volumeItf)->SetVolumeLevel(volumeItf, -300); CheckErr(res);
|
|
#endif
|
|
|
|
/* Enqueue a few buffers to get the ball rolling */
|
|
res = (*bufferQueueItf)->Enqueue(bufferQueueItf, cntxt.pData,
|
|
2 * AUDIO_DATA_BUFFER_SIZE); /* Size given in bytes. */
|
|
CheckErr(res);
|
|
cntxt.pData += AUDIO_DATA_BUFFER_SIZE;
|
|
|
|
res = (*bufferQueueItf)->Enqueue(bufferQueueItf, cntxt.pData,
|
|
2 * AUDIO_DATA_BUFFER_SIZE); /* Size given in bytes. */
|
|
CheckErr(res);
|
|
cntxt.pData += AUDIO_DATA_BUFFER_SIZE;
|
|
|
|
res = (*bufferQueueItf)->Enqueue(bufferQueueItf, cntxt.pData,
|
|
2 * AUDIO_DATA_BUFFER_SIZE); /* Size given in bytes. */
|
|
CheckErr(res);
|
|
cntxt.pData += AUDIO_DATA_BUFFER_SIZE;
|
|
|
|
/* Play the PCM samples using a buffer queue */
|
|
fprintf(stdout, "bufferQueue example: starting to play\n");
|
|
res = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING );
|
|
CheckErr(res);
|
|
|
|
/* Wait until the PCM data is done playing, the buffer queue callback
|
|
will continue to queue buffers until the entire PCM data has been
|
|
played. This is indicated by waiting for the count member of the
|
|
SLBufferQueueState to go to zero.
|
|
*/
|
|
res = (*bufferQueueItf)->GetState(bufferQueueItf, &state);
|
|
CheckErr(res);
|
|
|
|
// while (state.playIndex < 100) {
|
|
while (state.count) {
|
|
usleep(10000);
|
|
(*bufferQueueItf)->GetState(bufferQueueItf, &state);
|
|
}
|
|
|
|
/* Make sure player is stopped */
|
|
res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
|
|
CheckErr(res);
|
|
/* Destroy the player */
|
|
(*player)->Destroy(player);
|
|
|
|
/* Destroy Output Mix object */
|
|
(*OutputMix)->Destroy(OutputMix);
|
|
}
|
|
|
|
|
|
|
|
int main(int argc __unused, char* const argv[] __unused)
|
|
{
|
|
SLresult res;
|
|
SLObjectItf sl;
|
|
|
|
SLEngineOption EngineOption[] = {
|
|
{(SLuint32) SL_ENGINEOPTION_THREADSAFE,
|
|
(SLuint32) SL_BOOLEAN_TRUE}};
|
|
|
|
res = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL);
|
|
CheckErr(res);
|
|
/* Realizing the SL Engine in synchronous mode. */
|
|
res = (*sl)->Realize(sl, SL_BOOLEAN_FALSE); CheckErr(res);
|
|
|
|
/* Run the test */
|
|
TestPlaySawtoothBufferQueue(sl);
|
|
|
|
/* Shutdown OpenSL ES */
|
|
(*sl)->Destroy(sl);
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|