Mercurial > almixer_isolated
comparison ALmixer.c @ 29:1c23805d5ce9
Optimization to destroy bookkeeping thread on BeginInterruption() and recreate it on EndInterruption(). I'm concerned that Android may be running this thread and eating up unnecessary sleep cycles, particularly on certain devices that may have pathological sleep disorders. (There is a report about Samsung Galaxy Tab.)
author | Eric Wing <ewing . public |-at-| gmail . com> |
---|---|
date | Mon, 28 Mar 2011 16:05:25 -0700 |
parents | 60500a33735a |
children | a554e41eeb13 |
comparison
equal
deleted
inserted
replaced
28:60500a33735a | 29:1c23805d5ce9 |
---|---|
221 | 221 |
222 #ifdef ENABLE_ALMIXER_THREADS | 222 #ifdef ENABLE_ALMIXER_THREADS |
223 /* This is for a simple lock system. It is not meant to be good, | 223 /* This is for a simple lock system. It is not meant to be good, |
224 * but just sufficient to minimize/avoid threading issues | 224 * but just sufficient to minimize/avoid threading issues |
225 */ | 225 */ |
226 static ALuint g_StreamThreadEnabled = 0; | |
226 static SDL_mutex* s_simpleLock; | 227 static SDL_mutex* s_simpleLock; |
227 static SDL_Thread* Stream_Thread_global = NULL; | 228 static SDL_Thread* Stream_Thread_global = NULL; |
228 #endif /* ENABLE_ALMIXER_THREADS */ | 229 #endif /* ENABLE_ALMIXER_THREADS */ |
229 | 230 |
230 static LinkedList* s_listOfALmixerData = NULL; | 231 static LinkedList* s_listOfALmixerData = NULL; |
231 | 232 |
232 /* Special stuff for iOS interruption handling */ | 233 /* Special stuff for iOS interruption handling */ |
234 ALuint g_inInterruption = 0; | |
233 static ALCcontext* s_interruptionContext = NULL; | 235 static ALCcontext* s_interruptionContext = NULL; |
234 | 236 |
235 | 237 |
236 #ifdef __APPLE__ | 238 #ifdef __APPLE__ |
237 static ALvoid Internal_alcMacOSXMixerOutputRate(const ALdouble sample_rate) | 239 static ALvoid Internal_alcMacOSXMixerOutputRate(const ALdouble sample_rate) |
6190 | 6192 |
6191 static int Stream_Data_Thread_Callback(void* data) | 6193 static int Stream_Data_Thread_Callback(void* data) |
6192 { | 6194 { |
6193 ALint retval; | 6195 ALint retval; |
6194 | 6196 |
6195 while(ALmixer_Initialized) | 6197 while(g_StreamThreadEnabled) |
6196 { | 6198 { |
6197 retval = Update_ALmixer(data); | 6199 retval = Update_ALmixer(data); |
6198 /* 0 means that nothing needed updating and | 6200 /* 0 means that nothing needed updating and |
6199 * the function returned quickly | 6201 * the function returned quickly |
6200 */ | 6202 */ |
6771 ALmixer_Initialized = 0; | 6773 ALmixer_Initialized = 0; |
6772 Number_of_Channels_global = 0; | 6774 Number_of_Channels_global = 0; |
6773 return AL_FALSE; | 6775 return AL_FALSE; |
6774 } | 6776 } |
6775 | 6777 |
6776 | 6778 g_StreamThreadEnabled = 1; |
6777 Stream_Thread_global = SDL_CreateThread(Stream_Data_Thread_Callback, NULL); | 6779 Stream_Thread_global = SDL_CreateThread(Stream_Data_Thread_Callback, NULL); |
6778 if(NULL == Stream_Thread_global) | 6780 if(NULL == Stream_Thread_global) |
6779 { | 6781 { |
6780 /* SDL sets the error message already? */ | 6782 /* SDL sets the error message already? */ |
6781 SDL_DestroyMutex(s_simpleLock); | 6783 SDL_DestroyMutex(s_simpleLock); |
6785 LinkedList_Free(s_listOfALmixerData); | 6787 LinkedList_Free(s_listOfALmixerData); |
6786 alcDestroyContext(context); | 6788 alcDestroyContext(context); |
6787 alcCloseDevice(dev); | 6789 alcCloseDevice(dev); |
6788 ALmixer_Initialized = 0; | 6790 ALmixer_Initialized = 0; |
6789 Number_of_Channels_global = 0; | 6791 Number_of_Channels_global = 0; |
6792 g_StreamThreadEnabled = 0; | |
6790 return AL_FALSE; | 6793 return AL_FALSE; |
6791 } | 6794 } |
6792 | 6795 |
6793 /* Note: Only a few platforms change the priority. See implementation for notes. */ | 6796 /* Note: Only a few platforms change the priority. See implementation for notes. */ |
6794 Internal_LowerThreadPriority(Stream_Thread_global); | 6797 Internal_LowerThreadPriority(Stream_Thread_global); |
7328 Number_of_Channels_global = 0; | 7331 Number_of_Channels_global = 0; |
7329 return AL_FALSE; | 7332 return AL_FALSE; |
7330 } | 7333 } |
7331 | 7334 |
7332 | 7335 |
7336 g_StreamThreadEnabled = 1; | |
7333 Stream_Thread_global = SDL_CreateThread(Stream_Data_Thread_Callback, NULL); | 7337 Stream_Thread_global = SDL_CreateThread(Stream_Data_Thread_Callback, NULL); |
7334 if(NULL == Stream_Thread_global) | 7338 if(NULL == Stream_Thread_global) |
7335 { | 7339 { |
7336 /* SDL sets the error message already? */ | 7340 /* SDL sets the error message already? */ |
7337 SDL_DestroyMutex(s_simpleLock); | 7341 SDL_DestroyMutex(s_simpleLock); |
7338 free(source); | 7342 free(source); |
7339 free(ALmixer_Channel_List); | 7343 free(ALmixer_Channel_List); |
7340 free(Source_Map_List); | 7344 free(Source_Map_List); |
7341 ALmixer_Initialized = 0; | 7345 ALmixer_Initialized = 0; |
7342 Number_of_Channels_global = 0; | 7346 Number_of_Channels_global = 0; |
7347 g_StreamThreadEnabled = 0; | |
7343 return AL_FALSE; | 7348 return AL_FALSE; |
7344 } | 7349 } |
7345 | 7350 |
7346 /* Note: Only a few platforms change the priority. See implementation for notes. */ | 7351 /* Note: Only a few platforms change the priority. See implementation for notes. */ |
7347 Internal_LowerThreadPriority(Stream_Thread_global); | 7352 Internal_LowerThreadPriority(Stream_Thread_global); |
7358 return AL_TRUE; | 7363 return AL_TRUE; |
7359 } | 7364 } |
7360 | 7365 |
7361 void ALmixer_BeginInterruption() | 7366 void ALmixer_BeginInterruption() |
7362 { | 7367 { |
7363 #ifdef ENABLE_ALMIXER_THREADS | 7368 if(1 == g_inInterruption) |
7364 SDL_LockMutex(s_simpleLock); | 7369 { |
7370 return; | |
7371 } | |
7372 #ifdef ENABLE_ALMIXER_THREADS | |
7373 /* Kill bookkeeping thread to help minimize wasted CPU resources */ | |
7374 | |
7375 /* Is locking really necessary here? */ | |
7376 /* SDL_LockMutex(s_simpleLock); */ | |
7377 g_StreamThreadEnabled = 0; | |
7378 /* SDL_UnlockMutex(s_simpleLock); */ | |
7379 | |
7380 SDL_WaitThread(Stream_Thread_global, NULL); | |
7381 Stream_Thread_global = NULL; | |
7382 | |
7365 #endif | 7383 #endif |
7366 s_interruptionContext = alcGetCurrentContext(); | 7384 s_interruptionContext = alcGetCurrentContext(); |
7367 if(NULL != s_interruptionContext) | 7385 if(NULL != s_interruptionContext) |
7368 { | 7386 { |
7369 /* iOS alcSuspendContext is a no-op */ | 7387 /* iOS alcSuspendContext is a no-op */ |
7370 alcSuspendContext(s_interruptionContext); | 7388 alcSuspendContext(s_interruptionContext); |
7371 alcMakeContextCurrent(NULL); | 7389 alcMakeContextCurrent(NULL); |
7372 } | 7390 } |
7373 #ifdef ENABLE_ALMIXER_THREADS | 7391 |
7374 SDL_UnlockMutex(s_simpleLock); | 7392 g_inInterruption = 1; |
7375 #endif | |
7376 } | 7393 } |
7377 | 7394 |
7378 void ALmixer_EndInterruption() | 7395 void ALmixer_EndInterruption() |
7379 { | 7396 { |
7380 #ifdef ENABLE_ALMIXER_THREADS | 7397 if(0 == g_inInterruption) |
7381 SDL_LockMutex(s_simpleLock); | 7398 { |
7382 #endif | 7399 return; |
7400 } | |
7383 | 7401 |
7384 /* Note: iOS, you need to set the AudioSession active. | 7402 /* Note: iOS, you need to set the AudioSession active. |
7385 * But if the AudioSession is not initialized, this SetActive | 7403 * But if the AudioSession is not initialized, this SetActive |
7386 * call fails. | 7404 * call fails. |
7387 * So this is probably better if calling app sets this. | 7405 * So this is probably better if calling app sets this. |
7401 alcMakeContextCurrent(s_interruptionContext); | 7419 alcMakeContextCurrent(s_interruptionContext); |
7402 alcProcessContext(s_interruptionContext); | 7420 alcProcessContext(s_interruptionContext); |
7403 s_interruptionContext = NULL; | 7421 s_interruptionContext = NULL; |
7404 } | 7422 } |
7405 #ifdef ENABLE_ALMIXER_THREADS | 7423 #ifdef ENABLE_ALMIXER_THREADS |
7406 SDL_UnlockMutex(s_simpleLock); | 7424 g_StreamThreadEnabled = 1; |
7407 #endif | 7425 |
7426 Stream_Thread_global = SDL_CreateThread(Stream_Data_Thread_Callback, NULL); | |
7427 if(NULL == Stream_Thread_global) | |
7428 { | |
7429 fprintf(stderr, "Critical Error: Could not create bookkeeping thread in EndInterruption\n"); | |
7430 } | |
7431 #endif | |
7432 g_inInterruption = 0; | |
7408 } | 7433 } |
7409 | 7434 |
7410 /* Keep the return value void to allow easy use with | 7435 /* Keep the return value void to allow easy use with |
7411 * atexit() | 7436 * atexit() |
7412 */ | 7437 */ |
7418 | 7443 |
7419 if( ! ALmixer_Initialized) | 7444 if( ! ALmixer_Initialized) |
7420 { | 7445 { |
7421 return; | 7446 return; |
7422 } | 7447 } |
7448 | |
7423 #ifdef ENABLE_ALMIXER_THREADS | 7449 #ifdef ENABLE_ALMIXER_THREADS |
7424 SDL_LockMutex(s_simpleLock); | 7450 SDL_LockMutex(s_simpleLock); |
7425 #endif | 7451 #endif |
7426 | 7452 |
7427 /* Several things we need to do: | 7453 /* Several things we need to do: |
7455 Internal_HaltChannel(-1, AL_FALSE); | 7481 Internal_HaltChannel(-1, AL_FALSE); |
7456 | 7482 |
7457 /* This flag will cause the thread to terminate */ | 7483 /* This flag will cause the thread to terminate */ |
7458 ALmixer_Initialized = 0; | 7484 ALmixer_Initialized = 0; |
7459 #ifdef ENABLE_ALMIXER_THREADS | 7485 #ifdef ENABLE_ALMIXER_THREADS |
7486 g_StreamThreadEnabled = 0; | |
7460 SDL_UnlockMutex(s_simpleLock); | 7487 SDL_UnlockMutex(s_simpleLock); |
7488 /* This is safe to call with NULL thread, so we don't need to do anything special for interruptions. */ | |
7461 SDL_WaitThread(Stream_Thread_global, NULL); | 7489 SDL_WaitThread(Stream_Thread_global, NULL); |
7490 Stream_Thread_global = NULL; | |
7491 g_inInterruption = 0; | |
7462 | 7492 |
7463 SDL_DestroyMutex(s_simpleLock); | 7493 SDL_DestroyMutex(s_simpleLock); |
7464 #endif | 7494 #endif |
7465 | 7495 |
7466 /* Delete all the OpenAL sources */ | 7496 /* Delete all the OpenAL sources */ |