changeset 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 a44114dc8631 9b772c81b550
files ALmixer.c ALmixer.h
diffstat 2 files changed, 100 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/ALmixer.c	Tue Aug 30 19:42:31 2011 -0700
+++ b/ALmixer.c	Tue Sep 13 18:03:21 2011 -0700
@@ -2820,11 +2820,11 @@
 				ALmixer_Channel_List[channel].alsource,
 				AL_SOURCE_STATE, &state
 			);
-	if((error = alGetError()) != AL_NO_ERROR)
-	{
-		fprintf(stderr, "29Testing error: %s\n",
-			alGetString(error));				
-	}
+			if((error = alGetError()) != AL_NO_ERROR)
+			{
+				fprintf(stderr, "Internal_PauseChannel specific channel error: %s\n",
+				alGetString(error));				
+			}
 			if(AL_PLAYING == state)
 			{
 				/* Count the actual number of channels being paused */
@@ -2903,11 +2903,11 @@
 					ALmixer_Channel_List[i].alsource,
 					AL_SOURCE_STATE, &state
 				);
-	if((error = alGetError()) != AL_NO_ERROR)
-	{
-		fprintf(stderr, "30Testing error: %s\n",
-			alGetString(error));				
-	}
+				if((error = alGetError()) != AL_NO_ERROR)
+				{
+					fprintf(stderr, "Internal_PauseChannel all channels error: %s\n",
+					alGetString(error));				
+				}
 				if(AL_PLAYING == state)
 				{
 					/* Count the actual number of channels being paused */
@@ -5232,15 +5232,16 @@
 				ALuint number_of_buffers_to_queue_this_pass = ALmixer_Channel_List[i].almixer_data->num_target_buffers_per_pass;
 				ALuint current_count_of_buffer_queue_passes = 0;
 				
-#if 0
-		/********* Remove this **********/
-		fprintf(stderr, "For Streamed\n");
+/*		fprintf(stderr, "For Streamed\n"); */
 				
 	alGetSourcei(
 		ALmixer_Channel_List[i].alsource,
 		AL_SOURCE_STATE, &state
 				);
-	switch(state) {
+#if 0
+		/********* Remove this **********/
+	switch(state)
+	{
                 case AL_PLAYING:
 				fprintf(stderr, "Channel '%d' is PLAYING\n", i);
 				break;
@@ -7462,18 +7463,9 @@
 	{
 		return;
 	}
-#ifdef ENABLE_ALMIXER_THREADS
-	/* Kill bookkeeping thread to help minimize wasted CPU resources */
-
-	/* Is locking really necessary here? */
-/*	SDL_LockMutex(s_simpleLock); */
-	g_StreamThreadEnabled = AL_FALSE;
-/*	SDL_UnlockMutex(s_simpleLock); */
-
-	SDL_WaitThread(Stream_Thread_global, NULL);
-	Stream_Thread_global = NULL;
-
-#endif
+
+	ALmixer_SuspendUpdates();
+
 	s_interruptionContext = alcGetCurrentContext();
 	if(NULL != s_interruptionContext)
 	{
@@ -7513,15 +7505,8 @@
 		alcProcessContext(s_interruptionContext);
 		s_interruptionContext = NULL;
 	}
-#ifdef ENABLE_ALMIXER_THREADS
-	g_StreamThreadEnabled = AL_TRUE;
-
-	Stream_Thread_global = SDL_CreateThread(Stream_Data_Thread_Callback, NULL);
-	if(NULL == Stream_Thread_global)
-	{
-		fprintf(stderr, "Critical Error: Could not create bookkeeping thread in EndInterruption\n");
-	}
-#endif
+
+	ALmixer_ResumeUpdates();
 	g_inInterruption = AL_FALSE;
 }
 
@@ -7535,6 +7520,62 @@
 	return g_inInterruption;
 }
 
+void ALmixer_SuspendUpdates()
+{
+	if(AL_TRUE == ALmixer_AreUpdatesSuspended())
+	{
+		return;
+	}
+#ifdef ENABLE_ALMIXER_THREADS
+	/* Kill bookkeeping thread to help minimize wasted CPU resources */
+	
+	/* Is locking really necessary here? */
+	/*	SDL_LockMutex(s_simpleLock); */
+	g_StreamThreadEnabled = AL_FALSE;
+	/*	SDL_UnlockMutex(s_simpleLock); */
+	
+	SDL_WaitThread(Stream_Thread_global, NULL);
+	Stream_Thread_global = NULL;
+#endif
+}
+
+void ALmixer_ResumeUpdates()
+{
+	if(AL_FALSE == ALmixer_AreUpdatesSuspended())
+	{
+		return;
+	}
+
+#ifdef ENABLE_ALMIXER_THREADS
+	/* This must be set before the thread is created to prevent the thread from exiting. */
+	g_StreamThreadEnabled = AL_TRUE;
+	
+	Stream_Thread_global = SDL_CreateThread(Stream_Data_Thread_Callback, NULL);
+	if(NULL == Stream_Thread_global)
+	{
+		fprintf(stderr, "Critical Error: Could not create bookkeeping thread in EndInterruption\n");
+	}
+	/* Note: Only a few platforms change the priority. See implementation for notes. */
+	Internal_LowerThreadPriority(Stream_Thread_global);	
+#endif
+}
+
+ALboolean ALmixer_AreUpdatesSuspended()
+{
+#ifdef ENABLE_ALMIXER_THREADS
+	if(AL_FALSE == g_StreamThreadEnabled)
+	{
+		return AL_TRUE;
+	}
+	else
+	{
+		return AL_FALSE;
+	}
+#else
+	return AL_FALSE;
+#endif
+}
+
 /* Keep the return value void to allow easy use with
  * atexit()
  */
@@ -8487,6 +8528,10 @@
 	target.channels = 0;
 	target.rate = 0;
 	
+	if(0 == buffersize)
+	{
+		buffersize = ALMIXER_DEFAULT_BUFFERSIZE;
+	}
 #if 0
 	/* This requires my new additions to SDL_sound. It will
 	 * convert the sample to the proper endian order.
--- a/ALmixer.h	Tue Aug 30 19:42:31 2011 -0700
+++ b/ALmixer.h	Tue Sep 13 18:03:21 2011 -0700
@@ -372,14 +372,14 @@
 /**
  * (EXPERIMENTAL) Call to notify ALmixer that your device needs to handle an interruption.
  * (EXPERIMENTAL) For devices like iOS that need special handling for interruption events like phone calls and alarms,
- * this function will do the correct platform correct thing to handle the interruption w.r.t. OpenAL.
+ * this function will do the correct platform correct thing to handle the interruption w.r.t. OpenAL. This calls ALmixer_SuspendUpdates().
  */
 extern ALMIXER_DECLSPEC void ALMIXER_CALL ALmixer_BeginInterruption(void);
 
 /**
  * (EXPERIMENTAL) Call to notify ALmixer that your device needs to resume from an interruption.
  * (EXPERIMENTAL) For devices like iOS that need special handling for interruption events like phone calls and alarms,
- * this function will do the correct platform correct thing to resume from the interruption w.r.t. OpenAL.
+ * this function will do the correct platform correct thing to resume from the interruption w.r.t. OpenAL. This calls ALmixer_ResumeUpdates().
  */
 extern ALMIXER_DECLSPEC void ALMIXER_CALL ALmixer_EndInterruption(void);
 
@@ -390,6 +390,24 @@
  */	
 extern ALMIXER_DECLSPEC ALboolean ALmixer_IsInInterruption(void);
 
+
+/**
+ * (EXPERIMENTAL) Destroys the background update thread (ENABLE_ALMIXER_THREADS only). 
+ * (EXPERIMENTAL) Destroys the background update thread (ENABLE_ALMIXER_THREADS only). BeginInterruption used to do this internally, but this was split off due to an iOS OpenAL race condition bug (10081775). Being able to manipulate the thread without manipulating the context was useful for suspend/resume backgrounding when not dealing with a full-blown interruption event.
+ */
+extern ALMIXER_DECLSPEC void ALMIXER_CALL ALmixer_SuspendUpdates(void);
+
+/**
+ * (EXPERIMENTAL) Recreates the background update thread (ENABLE_ALMIXER_THREADS only). 
+ * (EXPERIMENTAL) Recreates the background update thread (ENABLE_ALMIXER_THREADS only). EndInterruption used to do this internally, but this was split off due to an iOS OpenAL race condition bug (10081775). Being able to manipulate the thread without manipulating the context was useful for suspend/resume backgrounding when not dealing with a full-blown interruption event.
+ */
+extern ALMIXER_DECLSPEC void ALMIXER_CALL ALmixer_ResumeUpdates(void);
+
+/**
+ * (EXPERIMENTAL) Call to determine if in ALmixer_SuspendUpdates(). (ENABLE_ALMIXER_THREADS only.)
+ */
+extern ALMIXER_DECLSPEC ALboolean ALmixer_AreUpdatesSuspended(void);
+
 	
 /**
  * This shuts down ALmixer. Please remember to free your ALmixer_Data* instances