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 // Multiple threads create and destroy objects
18 
19 #include <SLES/OpenSLES.h>
20 #include <assert.h>
21 #include <pthread.h>
22 //#include <string.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 
27 typedef struct {
28     SLuint32 mObjectID;
29     SLchar *mURI;
30     SLEngineItf mEngineEngine;
31     SLObjectItf mMixObject;
32     SLuint32 mCounter;
33 } ThreadArgument;
34 
35 volatile int timeToExit = 0;
36 #define MAX_THREAD 10
37 pthread_t threads[MAX_THREAD];
38 ThreadArgument thread_args[MAX_THREAD];
39 
40 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
41 
thread_start(void * param)42 void *thread_start(void *param)
43 {
44     //pthread_mutex_lock(&mutex);
45     //pthread_mutex_unlock(&mutex);
46     ThreadArgument *ta = (ThreadArgument *) param;
47 
48     while (!timeToExit) {
49         SLresult result;
50 
51         ++ta->mCounter;
52         switch (ta->mObjectID) {
53         case SL_OBJECTID_OUTPUTMIX:
54             {
55             SLObjectItf myMixObject;
56             result = (*ta->mEngineEngine)->CreateOutputMix(ta->mEngineEngine, &myMixObject, 0, NULL,
57                     NULL);
58             assert(SL_RESULT_SUCCESS == result);
59             result = (*myMixObject)->Realize(myMixObject, SL_BOOLEAN_FALSE);
60             assert(SL_RESULT_SUCCESS == result);
61             (*myMixObject)->Destroy(myMixObject);
62             }
63             break;
64 
65         case SL_OBJECTID_AUDIOPLAYER:
66             {
67             SLDataLocator_URI locURI = {SL_DATALOCATOR_URI, ta->mURI};
68             SLDataFormat_MIME dfMIME = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};
69             SLDataSource audioSrc = {&locURI, &dfMIME};
70             SLDataLocator_OutputMix locOutputMix = {SL_DATALOCATOR_OUTPUTMIX, ta->mMixObject};
71             SLDataSink audioSnk = {&locOutputMix, NULL};
72             SLObjectItf myPlayerObject;
73             result = (*ta->mEngineEngine)->CreateAudioPlayer(ta->mEngineEngine, &myPlayerObject,
74                     &audioSrc, &audioSnk, 0, NULL, NULL);
75             assert(SL_RESULT_SUCCESS == result);
76             result = (*myPlayerObject)->Realize(myPlayerObject, SL_BOOLEAN_FALSE);
77             assert(SL_RESULT_SUCCESS == result);
78             SLPlayItf playerPlay;
79             result = (*myPlayerObject)->GetInterface(myPlayerObject, SL_IID_PLAY, &playerPlay);
80             assert(SL_RESULT_SUCCESS == result);
81             result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PAUSED);
82             assert(SL_RESULT_SUCCESS == result);
83             usleep(1000 + (rand() & 0xFFF));
84             //usleep(1000);
85             //sleep(1);
86             (*myPlayerObject)->Destroy(myPlayerObject);
87             }
88             break;
89 
90         default:
91             break;
92 
93         }
94         //usleep(100000);
95         //break;
96     }
97 
98     return NULL;
99 }
100 
101 
102 //const char * const uris[4] = {"wav/frog.wav", "wav/bach.wav", "wav/8days.wav", "wav/help16.wav"};
103 const char * const uris[4] = {"wav/frog.wav", "wav/frog.wav", "wav/frog.wav", "wav/frog.wav"};
104 
105 // Main program
106 
main(int argc __unused,char ** argv __unused)107 int main(int argc __unused, char **argv __unused)
108 {
109     SLresult result;
110 
111     // create engine
112     SLObjectItf engineObject;
113     result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
114     assert(SL_RESULT_SUCCESS == result);
115     result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
116     assert(SL_RESULT_SUCCESS == result);
117     SLEngineItf engineEngine;
118     result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
119     assert(SL_RESULT_SUCCESS == result);
120 
121     // create output mix
122     SLObjectItf mixObject;
123     result = (*engineEngine)->CreateOutputMix(engineEngine, &mixObject, 0, NULL, NULL);
124     assert(SL_RESULT_SUCCESS == result);
125     result = (*mixObject)->Realize(mixObject, SL_BOOLEAN_FALSE);
126     assert(SL_RESULT_SUCCESS == result);
127 
128     // create threads
129     int i;
130     int ok;
131     for (i = 0; i < MAX_THREAD; ++i) {
132         ThreadArgument *ta = &thread_args[i];
133         int r = rand();
134         switch (r & 1) {
135 #if 0
136         case 0:
137             ta->mObjectID = SL_OBJECTID_OUTPUTMIX;
138             ta->mURI = NULL;
139             ta->mEngineEngine = engineEngine;
140             ta->mMixObject = NULL;
141             ta->mCounter = 0;
142             break;
143         case 1:
144 #endif
145         default:
146             ta->mObjectID = SL_OBJECTID_AUDIOPLAYER;
147             ta->mURI = (SLchar *) uris[(r >> 1) & 3];
148             ta->mEngineEngine = engineEngine;
149             ta->mMixObject = mixObject;
150             ta->mCounter = 0;
151             break;
152         }
153         //pthread_mutex_lock(&mutex);
154         //pthread_mutex_unlock(&mutex);
155         ok = pthread_create(&threads[i], (const pthread_attr_t *) NULL, thread_start,
156                 &thread_args[i]);
157         assert(0 == ok);
158     }
159 
160     // let it run for a while
161     int j;
162     for (j = 0; j < 100; ++j) {
163         sleep(1);
164         for (i = 0; i < MAX_THREAD; ++i) {
165             ThreadArgument *ta = &thread_args[i];
166             printf("[%d]=%u ", j, ta->mCounter);
167         }
168         printf("\n");
169     }
170 
171     // signal threads that they should exit
172     timeToExit = 1;
173 
174     for (j = 0; j < 3; ++j) {
175         sleep(1);
176         for (i = 0; i < MAX_THREAD; ++i) {
177             ThreadArgument *ta = &thread_args[i];
178             printf("[%d]=%u ", j, ta->mCounter);
179         }
180         printf("\n");
181     }
182 
183     // now wait for the threads to actually exit
184     for (i = 0; i < MAX_THREAD; ++i) {
185         ok = pthread_join(threads[i], NULL);
186         assert(0 == ok);
187     }
188 
189     // tear down objects
190     (*mixObject)->Destroy(mixObject);
191     (*engineObject)->Destroy(engineObject);
192 
193     return EXIT_SUCCESS;
194 }
195