/*
* 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.
*/
// single-threaded, single-player monkey test
#include <SLES/OpenSLES.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
typedef enum {
STATE_UNCHANGED,
STATE_INITIAL,
STATE_NONEXISTENT,
STATE_CREATED,
STATE_REALIZED,
STATE_PAUSED,
STATE_PLAYING,
STATE_STOPPED,
STATE_ERROR,
// STATE_IDLE, // after Stop, then sleep for 3 seconds
STATE_TERMINAL
} State_t;
typedef struct {
SLObjectItf mObject;
SLPlayItf mPlay;
SLSeekItf mSeek;
} Player_t, *Player_pt;
typedef State_t (*Action_pt)(Player_pt player);
SLObjectItf engineObject;
SLEngineItf engineEngine;
SLObjectItf outputMixObject;
int countTransitions = 0;
int maxTransitions = 10;
State_t actionPause(Player_pt p)
{
assert(NULL != p->mPlay);
SLresult result = (*p->mPlay)->SetPlayState(p->mPlay, SL_PLAYSTATE_PAUSED);
assert(SL_RESULT_SUCCESS == result);
return STATE_PAUSED;
}
State_t actionPlay(Player_pt p)
{
assert(NULL != p->mPlay);
SLresult result = (*p->mPlay)->SetPlayState(p->mPlay, SL_PLAYSTATE_PLAYING);
assert(SL_RESULT_SUCCESS == result);
return STATE_PLAYING;
}
State_t actionStop(Player_pt p)
{
assert(NULL != p->mPlay);
SLresult result = (*p->mPlay)->SetPlayState(p->mPlay, SL_PLAYSTATE_STOPPED);
assert(SL_RESULT_SUCCESS == result);
return STATE_STOPPED;
}
State_t actionRewind(Player_pt p)
{
assert(NULL != p->mSeek);
SLresult result = (*p->mSeek)->SetPosition(p->mSeek, (SLmillisecond) 0, SL_SEEKMODE_FAST);
assert(SL_RESULT_SUCCESS == result);
return STATE_UNCHANGED;
}
State_t actionDestroy(Player_pt p)
{
assert(NULL != p->mObject);
(*p->mObject)->Destroy(p->mObject);
p->mObject = NULL;
p->mPlay = NULL;
p->mSeek = NULL;
return STATE_NONEXISTENT;
}
State_t actionCreate(Player_pt p)
{
// configure audio source
SLDataLocator_URI loc_uri;
loc_uri.locatorType = SL_DATALOCATOR_URI;
loc_uri.URI = (SLchar *) "wav/frog.wav";
SLDataFormat_MIME format_mime;
format_mime.formatType = SL_DATAFORMAT_MIME;
format_mime.mimeType = NULL;
format_mime.containerType = SL_CONTAINERTYPE_UNSPECIFIED;
SLDataSource audioSrc;
audioSrc.pLocator = &loc_uri;
audioSrc.pFormat = &format_mime;
// configure audio sink
SLDataLocator_OutputMix loc_outmix;
loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
loc_outmix.outputMix = outputMixObject;
SLDataSink audioSnk;
audioSnk.pLocator = &loc_outmix;
audioSnk.pFormat = NULL;
// create audio player
SLInterfaceID ids[1] = {SL_IID_SEEK};
SLboolean req[1] = {SL_BOOLEAN_TRUE};
SLresult result = (*engineEngine)->CreateAudioPlayer(engineEngine, &p->mObject, &audioSrc,
&audioSnk, 1, ids, req);
if (SL_RESULT_SUCCESS != result)
return STATE_ERROR;
return STATE_CREATED;
}
State_t actionRealize(Player_pt p)
{
assert(NULL != p->mObject);
// realize the player
SLresult result = (*p->mObject)->Realize(p->mObject, SL_BOOLEAN_FALSE);
assert(SL_RESULT_SUCCESS == result);
// get interfaces
result = (*p->mObject)->GetInterface(p->mObject, SL_IID_PLAY, &p->mPlay);
assert(SL_RESULT_SUCCESS == result);
result = (*p->mObject)->GetInterface(p->mObject, SL_IID_SEEK, &p->mSeek);
assert(SL_RESULT_SUCCESS == result);
return STATE_REALIZED;
}
State_t actionSleep(Player_pt p __unused)
{
unsigned us = 1000 + (rand() & 0xFFFFF);
usleep(us);
return STATE_UNCHANGED;
}
#if 0
State_t actionSleep3(Player_pt p)
{
sleep(3);
return STATE_IDLE;
}
#endif
State_t actionTerminateIfDone(Player_pt p)
{
if (countTransitions >= maxTransitions) {
assert(NULL == p->mObject);
// clean up output mix and engine
assert(NULL != outputMixObject);
(*outputMixObject)->Destroy(outputMixObject);
outputMixObject = NULL;
assert(NULL != engineObject);
(*engineObject)->Destroy(engineObject);
engineObject = NULL;
return STATE_TERMINAL;
} else
return STATE_UNCHANGED;
}
State_t actionInitialize(Player_pt p __unused)
{
// create engine
SLresult result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
assert(SL_RESULT_SUCCESS == result);
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
assert(SL_RESULT_SUCCESS == result);
result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
assert(SL_RESULT_SUCCESS == result);
// create output mix
result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL);
assert(SL_RESULT_SUCCESS == result);
result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
assert(SL_RESULT_SUCCESS == result);
return STATE_NONEXISTENT;
}
typedef struct {
State_t mEntryState;
Action_pt mAction;
unsigned mProbability;
const char *mActionName;
unsigned mCount;
} Transition_t;
Transition_t transitionTable[] = {
#define _(entryState, action, probability) {entryState, action, probability, #action, 0},
_(STATE_INITIAL, actionInitialize, 1)
_(STATE_CREATED, actionDestroy, 1)
_(STATE_CREATED, actionRealize, 1)
_(STATE_CREATED, actionSleep, 1)
_(STATE_NONEXISTENT, actionCreate, 1)
_(STATE_NONEXISTENT, actionSleep, 1)
_(STATE_PAUSED, actionDestroy, 1)
_(STATE_PAUSED, actionPause, 1)
_(STATE_PAUSED, actionPlay, 1)
_(STATE_PAUSED, actionRewind, 1)
_(STATE_PAUSED, actionSleep, 1)
_(STATE_PAUSED, actionStop, 1)
_(STATE_PLAYING, actionDestroy, 1)
_(STATE_PLAYING, actionPause, 1)
_(STATE_PLAYING, actionPlay, 1)
_(STATE_PLAYING, actionRewind, 1)
_(STATE_PLAYING, actionSleep, 1)
_(STATE_PLAYING, actionStop, 1)
_(STATE_REALIZED, actionDestroy, 1)
_(STATE_REALIZED, actionPause, 1)
_(STATE_REALIZED, actionPlay, 1)
_(STATE_REALIZED, actionSleep, 1)
_(STATE_REALIZED, actionStop, 1)
_(STATE_STOPPED, actionDestroy, 1)
_(STATE_STOPPED, actionPause, 1)
_(STATE_STOPPED, actionPlay, 1)
_(STATE_STOPPED, actionRewind, 1)
_(STATE_STOPPED, actionSleep, 1)
_(STATE_STOPPED, actionStop, 1)
// _(STATE_STOPPED, actionSleep3, 1)
// _(STATE_IDLE, actionDestroy, 1)
_(STATE_NONEXISTENT, actionTerminateIfDone, 1)
};
int main(int argc, char **argv)
{
int i;
for (i = 1; i < argc; ++i) {
char *arg = argv[i];
if (arg[0] != '-')
break;
if (!strncmp(arg, "-m", 2)) {
maxTransitions = atoi(&arg[2]);
} else {
fprintf(stderr, "Unknown option %s\n", arg);
}
}
unsigned possibleTransitions = sizeof(transitionTable) / sizeof(transitionTable[0]);
Player_t player;
player.mObject = NULL;
player.mPlay = NULL;
player.mSeek = NULL;
State_t currentState = STATE_INITIAL;
while (STATE_TERMINAL != currentState) {
unsigned matchingTransitions = 0;
unsigned totalProbability = 0;
for (i = 0; i < (int) possibleTransitions; ++i) {
if (currentState != transitionTable[i].mEntryState)
continue;
++matchingTransitions;
totalProbability += transitionTable[i].mProbability;
}
if (matchingTransitions == 0) {
fprintf(stderr, "No matching transitions in state %d\n", currentState);
assert(SL_BOOLEAN_FALSE);
break;
}
if (totalProbability == 0) {
fprintf(stderr, "Found at least one matching transition in state %d, "
"but with probability 0\n", currentState);
assert(SL_BOOLEAN_FALSE);
break;
}
unsigned choice = (rand() & 0x7FFFFFFF) % totalProbability;
totalProbability = 0;
for (i = 0; i < (int) possibleTransitions; ++i) {
if (currentState != transitionTable[i].mEntryState)
continue;
totalProbability += transitionTable[i].mProbability;
if (totalProbability <= choice)
continue;
++transitionTable[i].mCount;
++countTransitions;
printf("[%d] Selecting transition %s in state %d for the %u time\n", countTransitions,
transitionTable[i].mActionName, currentState, transitionTable[i].mCount);
State_t nextState = (*transitionTable[i].mAction)(&player);
if (STATE_UNCHANGED != nextState)
currentState = nextState;
goto found;
}
fprintf(stderr, "This shouldn't happen\n");
assert(SL_BOOLEAN_FALSE);
found:
;
}
for (i = 0; i < (int) possibleTransitions; ++i) {
printf("state %d action %s count %u\n",
transitionTable[i].mEntryState,
transitionTable[i].mActionName,
transitionTable[i].mCount);
}
return EXIT_SUCCESS;
}