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 // single-threaded, single-player monkey test
18 
19 #include <SLES/OpenSLES.h>
20 #include <assert.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 
26 typedef enum {
27     STATE_UNCHANGED,
28     STATE_INITIAL,
29     STATE_NONEXISTENT,
30     STATE_CREATED,
31     STATE_REALIZED,
32     STATE_PAUSED,
33     STATE_PLAYING,
34     STATE_STOPPED,
35     STATE_ERROR,
36 //    STATE_IDLE,         // after Stop, then sleep for 3 seconds
37     STATE_TERMINAL
38 } State_t;
39 
40 typedef struct {
41     SLObjectItf mObject;
42     SLPlayItf mPlay;
43     SLSeekItf mSeek;
44 } Player_t, *Player_pt;
45 
46 typedef State_t (*Action_pt)(Player_pt player);
47 
48 SLObjectItf engineObject;
49 SLEngineItf engineEngine;
50 SLObjectItf outputMixObject;
51 int countTransitions = 0;
52 int maxTransitions = 10;
53 
actionPause(Player_pt p)54 State_t actionPause(Player_pt p)
55 {
56     assert(NULL != p->mPlay);
57     SLresult result = (*p->mPlay)->SetPlayState(p->mPlay, SL_PLAYSTATE_PAUSED);
58     assert(SL_RESULT_SUCCESS == result);
59     return STATE_PAUSED;
60 }
61 
actionPlay(Player_pt p)62 State_t actionPlay(Player_pt p)
63 {
64     assert(NULL != p->mPlay);
65     SLresult result = (*p->mPlay)->SetPlayState(p->mPlay, SL_PLAYSTATE_PLAYING);
66     assert(SL_RESULT_SUCCESS == result);
67     return STATE_PLAYING;
68 }
69 
actionStop(Player_pt p)70 State_t actionStop(Player_pt p)
71 {
72     assert(NULL != p->mPlay);
73     SLresult result = (*p->mPlay)->SetPlayState(p->mPlay, SL_PLAYSTATE_STOPPED);
74     assert(SL_RESULT_SUCCESS == result);
75     return STATE_STOPPED;
76 }
77 
actionRewind(Player_pt p)78 State_t actionRewind(Player_pt p)
79 {
80     assert(NULL != p->mSeek);
81     SLresult result = (*p->mSeek)->SetPosition(p->mSeek, (SLmillisecond) 0, SL_SEEKMODE_FAST);
82     assert(SL_RESULT_SUCCESS == result);
83     return STATE_UNCHANGED;
84 }
85 
actionDestroy(Player_pt p)86 State_t actionDestroy(Player_pt p)
87 {
88     assert(NULL != p->mObject);
89     (*p->mObject)->Destroy(p->mObject);
90     p->mObject = NULL;
91     p->mPlay = NULL;
92     p->mSeek = NULL;
93     return STATE_NONEXISTENT;
94 }
95 
actionCreate(Player_pt p)96 State_t actionCreate(Player_pt p)
97 {
98     // configure audio source
99     SLDataLocator_URI loc_uri;
100     loc_uri.locatorType = SL_DATALOCATOR_URI;
101     loc_uri.URI = (SLchar *) "wav/frog.wav";
102     SLDataFormat_MIME format_mime;
103     format_mime.formatType = SL_DATAFORMAT_MIME;
104     format_mime.mimeType = NULL;
105     format_mime.containerType = SL_CONTAINERTYPE_UNSPECIFIED;
106     SLDataSource audioSrc;
107     audioSrc.pLocator = &loc_uri;
108     audioSrc.pFormat = &format_mime;
109     // configure audio sink
110     SLDataLocator_OutputMix loc_outmix;
111     loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
112     loc_outmix.outputMix = outputMixObject;
113     SLDataSink audioSnk;
114     audioSnk.pLocator = &loc_outmix;
115     audioSnk.pFormat = NULL;
116     // create audio player
117     SLInterfaceID ids[1] = {SL_IID_SEEK};
118     SLboolean req[1] = {SL_BOOLEAN_TRUE};
119     SLresult result = (*engineEngine)->CreateAudioPlayer(engineEngine, &p->mObject, &audioSrc,
120             &audioSnk, 1, ids, req);
121     if (SL_RESULT_SUCCESS != result)
122         return STATE_ERROR;
123     return STATE_CREATED;
124 }
125 
actionRealize(Player_pt p)126 State_t actionRealize(Player_pt p)
127 {
128     assert(NULL != p->mObject);
129     // realize the player
130     SLresult result = (*p->mObject)->Realize(p->mObject, SL_BOOLEAN_FALSE);
131     assert(SL_RESULT_SUCCESS == result);
132     // get interfaces
133     result = (*p->mObject)->GetInterface(p->mObject, SL_IID_PLAY, &p->mPlay);
134     assert(SL_RESULT_SUCCESS == result);
135     result = (*p->mObject)->GetInterface(p->mObject, SL_IID_SEEK, &p->mSeek);
136     assert(SL_RESULT_SUCCESS == result);
137     return STATE_REALIZED;
138 }
139 
actionSleep(Player_pt p __unused)140 State_t actionSleep(Player_pt p __unused)
141 {
142     unsigned us = 1000 + (rand() & 0xFFFFF);
143     usleep(us);
144     return STATE_UNCHANGED;
145 }
146 
147 #if 0
148 State_t actionSleep3(Player_pt p)
149 {
150     sleep(3);
151     return STATE_IDLE;
152 }
153 #endif
154 
actionTerminateIfDone(Player_pt p)155 State_t actionTerminateIfDone(Player_pt p)
156 {
157     if (countTransitions >= maxTransitions) {
158         assert(NULL == p->mObject);
159         // clean up output mix and engine
160         assert(NULL != outputMixObject);
161         (*outputMixObject)->Destroy(outputMixObject);
162         outputMixObject = NULL;
163         assert(NULL != engineObject);
164         (*engineObject)->Destroy(engineObject);
165         engineObject = NULL;
166         return STATE_TERMINAL;
167     } else
168         return STATE_UNCHANGED;
169 }
170 
actionInitialize(Player_pt p __unused)171 State_t actionInitialize(Player_pt p __unused)
172 {
173     // create engine
174     SLresult result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
175     assert(SL_RESULT_SUCCESS == result);
176     result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
177     assert(SL_RESULT_SUCCESS == result);
178     result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
179     assert(SL_RESULT_SUCCESS == result);
180 
181     // create output mix
182     result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL);
183     assert(SL_RESULT_SUCCESS == result);
184     result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
185     assert(SL_RESULT_SUCCESS == result);
186 
187     return STATE_NONEXISTENT;
188 }
189 
190 typedef struct {
191     State_t mEntryState;
192     Action_pt mAction;
193     unsigned mProbability;
194     const char *mActionName;
195     unsigned mCount;
196 } Transition_t;
197 
198 Transition_t transitionTable[] = {
199 #define _(entryState, action, probability) {entryState, action, probability, #action, 0},
200     _(STATE_INITIAL, actionInitialize, 1)
201     _(STATE_CREATED, actionDestroy, 1)
202     _(STATE_CREATED, actionRealize, 1)
203     _(STATE_CREATED, actionSleep, 1)
204     _(STATE_NONEXISTENT, actionCreate, 1)
205     _(STATE_NONEXISTENT, actionSleep, 1)
206     _(STATE_PAUSED, actionDestroy, 1)
207     _(STATE_PAUSED, actionPause, 1)
208     _(STATE_PAUSED, actionPlay, 1)
209     _(STATE_PAUSED, actionRewind, 1)
210     _(STATE_PAUSED, actionSleep, 1)
211     _(STATE_PAUSED, actionStop, 1)
212     _(STATE_PLAYING, actionDestroy, 1)
213     _(STATE_PLAYING, actionPause, 1)
214     _(STATE_PLAYING, actionPlay, 1)
215     _(STATE_PLAYING, actionRewind, 1)
216     _(STATE_PLAYING, actionSleep, 1)
217     _(STATE_PLAYING, actionStop, 1)
218     _(STATE_REALIZED, actionDestroy, 1)
219     _(STATE_REALIZED, actionPause, 1)
220     _(STATE_REALIZED, actionPlay, 1)
221     _(STATE_REALIZED, actionSleep, 1)
222     _(STATE_REALIZED, actionStop, 1)
223     _(STATE_STOPPED, actionDestroy, 1)
224     _(STATE_STOPPED, actionPause, 1)
225     _(STATE_STOPPED, actionPlay, 1)
226     _(STATE_STOPPED, actionRewind, 1)
227     _(STATE_STOPPED, actionSleep, 1)
228     _(STATE_STOPPED, actionStop, 1)
229 //    _(STATE_STOPPED, actionSleep3, 1)
230 //    _(STATE_IDLE, actionDestroy, 1)
231     _(STATE_NONEXISTENT, actionTerminateIfDone, 1)
232 };
233 
main(int argc,char ** argv)234 int main(int argc, char **argv)
235 {
236     int i;
237     for (i = 1; i < argc; ++i) {
238         char *arg = argv[i];
239         if (arg[0] != '-')
240             break;
241         if (!strncmp(arg, "-m", 2)) {
242             maxTransitions = atoi(&arg[2]);
243         } else {
244             fprintf(stderr, "Unknown option %s\n", arg);
245         }
246     }
247     unsigned possibleTransitions = sizeof(transitionTable) / sizeof(transitionTable[0]);
248     Player_t player;
249     player.mObject = NULL;
250     player.mPlay = NULL;
251     player.mSeek = NULL;
252     State_t currentState = STATE_INITIAL;
253     while (STATE_TERMINAL != currentState) {
254         unsigned matchingTransitions = 0;
255         unsigned totalProbability = 0;
256         for (i = 0; i < (int) possibleTransitions; ++i) {
257             if (currentState != transitionTable[i].mEntryState)
258                 continue;
259             ++matchingTransitions;
260             totalProbability += transitionTable[i].mProbability;
261         }
262         if (matchingTransitions == 0) {
263             fprintf(stderr, "No matching transitions in state %d\n", currentState);
264             assert(SL_BOOLEAN_FALSE);
265             break;
266         }
267         if (totalProbability == 0) {
268             fprintf(stderr, "Found at least one matching transition in state %d, "
269                     "but with probability 0\n", currentState);
270             assert(SL_BOOLEAN_FALSE);
271             break;
272         }
273         unsigned choice = (rand() & 0x7FFFFFFF) % totalProbability;
274         totalProbability = 0;
275         for (i = 0; i < (int) possibleTransitions; ++i) {
276             if (currentState != transitionTable[i].mEntryState)
277                 continue;
278             totalProbability += transitionTable[i].mProbability;
279             if (totalProbability <= choice)
280                 continue;
281             ++transitionTable[i].mCount;
282             ++countTransitions;
283             printf("[%d] Selecting transition %s in state %d for the %u time\n", countTransitions,
284                     transitionTable[i].mActionName, currentState, transitionTable[i].mCount);
285             State_t nextState = (*transitionTable[i].mAction)(&player);
286             if (STATE_UNCHANGED != nextState)
287                 currentState = nextState;
288             goto found;
289         }
290         fprintf(stderr, "This shouldn't happen\n");
291         assert(SL_BOOLEAN_FALSE);
292 found:
293         ;
294     }
295     for (i = 0; i < (int) possibleTransitions; ++i) {
296         printf("state %d action %s count %u\n",
297             transitionTable[i].mEntryState,
298             transitionTable[i].mActionName,
299             transitionTable[i].mCount);
300     }
301     return EXIT_SUCCESS;
302 }
303