/*
* 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.
*/
// Multiple threads create and destroy objects
#include <SLES/OpenSLES.h>
#include <assert.h>
#include <pthread.h>
//#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
typedef struct {
SLuint32 mObjectID;
SLchar *mURI;
SLEngineItf mEngineEngine;
SLObjectItf mMixObject;
SLuint32 mCounter;
} ThreadArgument;
volatile int timeToExit = 0;
#define MAX_THREAD 10
pthread_t threads[MAX_THREAD];
ThreadArgument thread_args[MAX_THREAD];
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *thread_start(void *param)
{
//pthread_mutex_lock(&mutex);
//pthread_mutex_unlock(&mutex);
ThreadArgument *ta = (ThreadArgument *) param;
while (!timeToExit) {
SLresult result;
++ta->mCounter;
switch (ta->mObjectID) {
case SL_OBJECTID_OUTPUTMIX:
{
SLObjectItf myMixObject;
result = (*ta->mEngineEngine)->CreateOutputMix(ta->mEngineEngine, &myMixObject, 0, NULL,
NULL);
assert(SL_RESULT_SUCCESS == result);
result = (*myMixObject)->Realize(myMixObject, SL_BOOLEAN_FALSE);
assert(SL_RESULT_SUCCESS == result);
(*myMixObject)->Destroy(myMixObject);
}
break;
case SL_OBJECTID_AUDIOPLAYER:
{
SLDataLocator_URI locURI = {SL_DATALOCATOR_URI, ta->mURI};
SLDataFormat_MIME dfMIME = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};
SLDataSource audioSrc = {&locURI, &dfMIME};
SLDataLocator_OutputMix locOutputMix = {SL_DATALOCATOR_OUTPUTMIX, ta->mMixObject};
SLDataSink audioSnk = {&locOutputMix, NULL};
SLObjectItf myPlayerObject;
result = (*ta->mEngineEngine)->CreateAudioPlayer(ta->mEngineEngine, &myPlayerObject,
&audioSrc, &audioSnk, 0, NULL, NULL);
assert(SL_RESULT_SUCCESS == result);
result = (*myPlayerObject)->Realize(myPlayerObject, SL_BOOLEAN_FALSE);
assert(SL_RESULT_SUCCESS == result);
SLPlayItf playerPlay;
result = (*myPlayerObject)->GetInterface(myPlayerObject, SL_IID_PLAY, &playerPlay);
assert(SL_RESULT_SUCCESS == result);
result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PAUSED);
assert(SL_RESULT_SUCCESS == result);
usleep(1000 + (rand() & 0xFFF));
//usleep(1000);
//sleep(1);
(*myPlayerObject)->Destroy(myPlayerObject);
}
break;
default:
break;
}
//usleep(100000);
//break;
}
return NULL;
}
//const char * const uris[4] = {"wav/frog.wav", "wav/bach.wav", "wav/8days.wav", "wav/help16.wav"};
const char * const uris[4] = {"wav/frog.wav", "wav/frog.wav", "wav/frog.wav", "wav/frog.wav"};
// Main program
int main(int argc __unused, char **argv __unused)
{
SLresult result;
// create engine
SLObjectItf engineObject;
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);
SLEngineItf engineEngine;
result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
assert(SL_RESULT_SUCCESS == result);
// create output mix
SLObjectItf mixObject;
result = (*engineEngine)->CreateOutputMix(engineEngine, &mixObject, 0, NULL, NULL);
assert(SL_RESULT_SUCCESS == result);
result = (*mixObject)->Realize(mixObject, SL_BOOLEAN_FALSE);
assert(SL_RESULT_SUCCESS == result);
// create threads
int i;
int ok;
for (i = 0; i < MAX_THREAD; ++i) {
ThreadArgument *ta = &thread_args[i];
int r = rand();
switch (r & 1) {
#if 0
case 0:
ta->mObjectID = SL_OBJECTID_OUTPUTMIX;
ta->mURI = NULL;
ta->mEngineEngine = engineEngine;
ta->mMixObject = NULL;
ta->mCounter = 0;
break;
case 1:
#endif
default:
ta->mObjectID = SL_OBJECTID_AUDIOPLAYER;
ta->mURI = (SLchar *) uris[(r >> 1) & 3];
ta->mEngineEngine = engineEngine;
ta->mMixObject = mixObject;
ta->mCounter = 0;
break;
}
//pthread_mutex_lock(&mutex);
//pthread_mutex_unlock(&mutex);
ok = pthread_create(&threads[i], (const pthread_attr_t *) NULL, thread_start,
&thread_args[i]);
assert(0 == ok);
}
// let it run for a while
int j;
for (j = 0; j < 100; ++j) {
sleep(1);
for (i = 0; i < MAX_THREAD; ++i) {
ThreadArgument *ta = &thread_args[i];
printf("[%d]=%u ", j, ta->mCounter);
}
printf("\n");
}
// signal threads that they should exit
timeToExit = 1;
for (j = 0; j < 3; ++j) {
sleep(1);
for (i = 0; i < MAX_THREAD; ++i) {
ThreadArgument *ta = &thread_args[i];
printf("[%d]=%u ", j, ta->mCounter);
}
printf("\n");
}
// now wait for the threads to actually exit
for (i = 0; i < MAX_THREAD; ++i) {
ok = pthread_join(threads[i], NULL);
assert(0 == ok);
}
// tear down objects
(*mixObject)->Destroy(mixObject);
(*engineObject)->Destroy(engineObject);
return EXIT_SUCCESS;
}