comparison ALmixer.c @ 44:56855942fdc6

Split off background thread (threads only) termination and creation into separate functions from Interruption handling to make it easier to avoid race condition bug with Apple rdar://10081775 w.r.t. setting the OpenAL context. New APIs to suspend and resume update threads. Interruption handling calls these automatically. Also partially regressed simplification with regards to getting the current playing state in the main update loop.
author Eric Wing <ewing@anscamobile.com>
date Tue, 13 Sep 2011 18:03:21 -0700
parents 05e5dc4817a4
children 9b772c81b550
comparison
equal deleted inserted replaced
42:05e5dc4817a4 44:56855942fdc6
2818 */ 2818 */
2819 alGetSourcei( 2819 alGetSourcei(
2820 ALmixer_Channel_List[channel].alsource, 2820 ALmixer_Channel_List[channel].alsource,
2821 AL_SOURCE_STATE, &state 2821 AL_SOURCE_STATE, &state
2822 ); 2822 );
2823 if((error = alGetError()) != AL_NO_ERROR) 2823 if((error = alGetError()) != AL_NO_ERROR)
2824 { 2824 {
2825 fprintf(stderr, "29Testing error: %s\n", 2825 fprintf(stderr, "Internal_PauseChannel specific channel error: %s\n",
2826 alGetString(error)); 2826 alGetString(error));
2827 } 2827 }
2828 if(AL_PLAYING == state) 2828 if(AL_PLAYING == state)
2829 { 2829 {
2830 /* Count the actual number of channels being paused */ 2830 /* Count the actual number of channels being paused */
2831 counter++; 2831 counter++;
2832 2832
2901 */ 2901 */
2902 alGetSourcei( 2902 alGetSourcei(
2903 ALmixer_Channel_List[i].alsource, 2903 ALmixer_Channel_List[i].alsource,
2904 AL_SOURCE_STATE, &state 2904 AL_SOURCE_STATE, &state
2905 ); 2905 );
2906 if((error = alGetError()) != AL_NO_ERROR) 2906 if((error = alGetError()) != AL_NO_ERROR)
2907 { 2907 {
2908 fprintf(stderr, "30Testing error: %s\n", 2908 fprintf(stderr, "Internal_PauseChannel all channels error: %s\n",
2909 alGetString(error)); 2909 alGetString(error));
2910 } 2910 }
2911 if(AL_PLAYING == state) 2911 if(AL_PLAYING == state)
2912 { 2912 {
2913 /* Count the actual number of channels being paused */ 2913 /* Count the actual number of channels being paused */
2914 counter++; 2914 counter++;
2915 2915
5230 5230
5231 ALuint unqueued_buffer_id; 5231 ALuint unqueued_buffer_id;
5232 ALuint number_of_buffers_to_queue_this_pass = ALmixer_Channel_List[i].almixer_data->num_target_buffers_per_pass; 5232 ALuint number_of_buffers_to_queue_this_pass = ALmixer_Channel_List[i].almixer_data->num_target_buffers_per_pass;
5233 ALuint current_count_of_buffer_queue_passes = 0; 5233 ALuint current_count_of_buffer_queue_passes = 0;
5234 5234
5235 #if 0 5235 /* fprintf(stderr, "For Streamed\n"); */
5236 /********* Remove this **********/
5237 fprintf(stderr, "For Streamed\n");
5238 5236
5239 alGetSourcei( 5237 alGetSourcei(
5240 ALmixer_Channel_List[i].alsource, 5238 ALmixer_Channel_List[i].alsource,
5241 AL_SOURCE_STATE, &state 5239 AL_SOURCE_STATE, &state
5242 ); 5240 );
5243 switch(state) { 5241 #if 0
5242 /********* Remove this **********/
5243 switch(state)
5244 {
5244 case AL_PLAYING: 5245 case AL_PLAYING:
5245 fprintf(stderr, "Channel '%d' is PLAYING\n", i); 5246 fprintf(stderr, "Channel '%d' is PLAYING\n", i);
5246 break; 5247 break;
5247 case AL_PAUSED: 5248 case AL_PAUSED:
5248 fprintf(stderr, "Channel '%d' is PAUSED\n",i); 5249 fprintf(stderr, "Channel '%d' is PAUSED\n",i);
7460 { 7461 {
7461 if((AL_TRUE == g_inInterruption) || (AL_FALSE == ALmixer_Initialized)) 7462 if((AL_TRUE == g_inInterruption) || (AL_FALSE == ALmixer_Initialized))
7462 { 7463 {
7463 return; 7464 return;
7464 } 7465 }
7465 #ifdef ENABLE_ALMIXER_THREADS 7466
7466 /* Kill bookkeeping thread to help minimize wasted CPU resources */ 7467 ALmixer_SuspendUpdates();
7467 7468
7468 /* Is locking really necessary here? */
7469 /* SDL_LockMutex(s_simpleLock); */
7470 g_StreamThreadEnabled = AL_FALSE;
7471 /* SDL_UnlockMutex(s_simpleLock); */
7472
7473 SDL_WaitThread(Stream_Thread_global, NULL);
7474 Stream_Thread_global = NULL;
7475
7476 #endif
7477 s_interruptionContext = alcGetCurrentContext(); 7469 s_interruptionContext = alcGetCurrentContext();
7478 if(NULL != s_interruptionContext) 7470 if(NULL != s_interruptionContext)
7479 { 7471 {
7480 /* iOS alcSuspendContext is a no-op */ 7472 /* iOS alcSuspendContext is a no-op */
7481 alcSuspendContext(s_interruptionContext); 7473 alcSuspendContext(s_interruptionContext);
7511 { 7503 {
7512 alcMakeContextCurrent(s_interruptionContext); 7504 alcMakeContextCurrent(s_interruptionContext);
7513 alcProcessContext(s_interruptionContext); 7505 alcProcessContext(s_interruptionContext);
7514 s_interruptionContext = NULL; 7506 s_interruptionContext = NULL;
7515 } 7507 }
7516 #ifdef ENABLE_ALMIXER_THREADS 7508
7509 ALmixer_ResumeUpdates();
7510 g_inInterruption = AL_FALSE;
7511 }
7512
7513
7514 ALboolean ALmixer_IsInInterruption()
7515 {
7516 if(AL_FALSE == ALmixer_Initialized)
7517 {
7518 return AL_FALSE;
7519 }
7520 return g_inInterruption;
7521 }
7522
7523 void ALmixer_SuspendUpdates()
7524 {
7525 if(AL_TRUE == ALmixer_AreUpdatesSuspended())
7526 {
7527 return;
7528 }
7529 #ifdef ENABLE_ALMIXER_THREADS
7530 /* Kill bookkeeping thread to help minimize wasted CPU resources */
7531
7532 /* Is locking really necessary here? */
7533 /* SDL_LockMutex(s_simpleLock); */
7534 g_StreamThreadEnabled = AL_FALSE;
7535 /* SDL_UnlockMutex(s_simpleLock); */
7536
7537 SDL_WaitThread(Stream_Thread_global, NULL);
7538 Stream_Thread_global = NULL;
7539 #endif
7540 }
7541
7542 void ALmixer_ResumeUpdates()
7543 {
7544 if(AL_FALSE == ALmixer_AreUpdatesSuspended())
7545 {
7546 return;
7547 }
7548
7549 #ifdef ENABLE_ALMIXER_THREADS
7550 /* This must be set before the thread is created to prevent the thread from exiting. */
7517 g_StreamThreadEnabled = AL_TRUE; 7551 g_StreamThreadEnabled = AL_TRUE;
7518 7552
7519 Stream_Thread_global = SDL_CreateThread(Stream_Data_Thread_Callback, NULL); 7553 Stream_Thread_global = SDL_CreateThread(Stream_Data_Thread_Callback, NULL);
7520 if(NULL == Stream_Thread_global) 7554 if(NULL == Stream_Thread_global)
7521 { 7555 {
7522 fprintf(stderr, "Critical Error: Could not create bookkeeping thread in EndInterruption\n"); 7556 fprintf(stderr, "Critical Error: Could not create bookkeeping thread in EndInterruption\n");
7523 } 7557 }
7524 #endif 7558 /* Note: Only a few platforms change the priority. See implementation for notes. */
7525 g_inInterruption = AL_FALSE; 7559 Internal_LowerThreadPriority(Stream_Thread_global);
7526 } 7560 #endif
7527 7561 }
7528 7562
7529 ALboolean ALmixer_IsInInterruption() 7563 ALboolean ALmixer_AreUpdatesSuspended()
7530 { 7564 {
7531 if(AL_FALSE == ALmixer_Initialized) 7565 #ifdef ENABLE_ALMIXER_THREADS
7566 if(AL_FALSE == g_StreamThreadEnabled)
7567 {
7568 return AL_TRUE;
7569 }
7570 else
7532 { 7571 {
7533 return AL_FALSE; 7572 return AL_FALSE;
7534 } 7573 }
7535 return g_inInterruption; 7574 #else
7575 return AL_FALSE;
7576 #endif
7536 } 7577 }
7537 7578
7538 /* Keep the return value void to allow easy use with 7579 /* Keep the return value void to allow easy use with
7539 * atexit() 7580 * atexit()
7540 */ 7581 */
8485 * 0 tells SDL_sound to use the "actual" values 8526 * 0 tells SDL_sound to use the "actual" values
8486 */ 8527 */
8487 target.channels = 0; 8528 target.channels = 0;
8488 target.rate = 0; 8529 target.rate = 0;
8489 8530
8531 if(0 == buffersize)
8532 {
8533 buffersize = ALMIXER_DEFAULT_BUFFERSIZE;
8534 }
8490 #if 0 8535 #if 0
8491 /* This requires my new additions to SDL_sound. It will 8536 /* This requires my new additions to SDL_sound. It will
8492 * convert the sample to the proper endian order. 8537 * convert the sample to the proper endian order.
8493 * If the actual is 8-bit, it will do unsigned, if 8538 * If the actual is 8-bit, it will do unsigned, if
8494 * the actual is 16-bit, it will do signed. 8539 * the actual is 16-bit, it will do signed.