changeset 50:db5bc1c80057

Workaround for terrible iOS 5.0 regression bug in Apple's OpenAL implementation with regards to resetting streaming sources. The fix uses a version check to determine if the workaround is employed. Once Apple fixes the problem, an upper bounds version check should be added.
author Eric Wing <ewing@anscamobile.com>
date Fri, 21 Oct 2011 17:14:19 -0700
parents 4b0268d86298
children e2687188aea5
files ALmixer.c
diffstat 1 files changed, 73 insertions(+), 66 deletions(-) [+]
line wrap: on
line diff
--- a/ALmixer.c	Fri Sep 30 17:48:23 2011 -0700
+++ b/ALmixer.c	Fri Oct 21 17:14:19 2011 -0700
@@ -1732,88 +1732,95 @@
 		 */
 		if(kCFCoreFoundationVersionNumber >= 674.0)
 		{
-			if(AL_FALSE == is_predecoded)
+			/* For OpenAL experts, this is contrary to what you know, but must be done because the OpenAL implementation is broken.
+			   Instead of unqueuing buffers on only streaming sources, it appears that alSourcei(source, AL_BUFFER, AL_NONE) is not reliable at all.
+			   In cases where I switch between stream and non-stream on the same source and then stream again, the bug breaks playback on the third playback
+			   and only one buffer plays.
+			   The workaround seems to be to always unqueue buffers regardless of whether the source is streamed or not. 
+			   And then avoid calling (source, AL_BUFFER, AL_NONE)
+			   From past experience, I know it is a bad idea to try to unqueue buffers from a non-streamed source (which is the contrary to OpenAL part),
+			   but this seems to work for this bug.
+			 */
+			ALint buffers_processed;
+			/* Wow this is the bug that just keeps on sucking. There is even a race condition bug where the unqueue may not actually work. 
+			 * So I have to keep doing it until it does.
+			 */
+			do
 			{
-				ALint buffers_processed;
+				ALint temp_count;
+				
 				/* Wow this is the bug that just keeps on sucking. There is even a race condition bug where the unqueue may not actually work. 
 				 * So I have to keep doing it until it does.
+				 * Sleeping for 20ms seems to help. 10ms was not long enough. (iPad 2)
 				 */
-				do
+				ALmixer_Delay(20);
+
+				alGetSourcei(
+					source_id,
+					AL_BUFFERS_PROCESSED, &buffers_processed
+				);
+				if((error = alGetError()) != AL_NO_ERROR)
 				{
-					ALint temp_count;
-					
-					/* Wow this is the bug that just keeps on sucking. There is even a race condition bug where the unqueue may not actually work. 
-					 * So I have to keep doing it until it does.
-					 * Sleeping for 20ms seems to help. 10ms was not long enough. (iPad 2)
-					 */
-					ALmixer_Delay(20);
-
-					alGetSourcei(
+					fprintf(stderr, "17aTesting Error with buffers_processed on Halt. (You may be seeing this because of a bad Apple OpenAL iOS 5.0 regression bug): %s",
+						alGetString(error));
+					ALmixer_SetError("Failed detecting still processed buffers: %s",
+						alGetString(error) );
+					/* This whole iOS 5.0 bug is so messed up that returning an error value probably isn't helpful.
+					retval = AL_FALSE;
+					*/
+				}
+				/*
+				fprintf(stderr, "Going to unqueue %d buffers\n", buffers_processed);
+				 */
+				for(temp_count=0; temp_count<buffers_processed; temp_count++)
+				{
+					ALuint unqueued_buffer_id;
+
+					alSourceUnqueueBuffers(
 						source_id,
-						AL_BUFFERS_PROCESSED, &buffers_processed
+						1, &unqueued_buffer_id
 					);
 					if((error = alGetError()) != AL_NO_ERROR)
 					{
-						fprintf(stderr, "17aTesting Error with buffers_processed on Halt. (You may be seeing this because of a bad Apple OpenAL iOS 5.0 regression bug): %s",
-							alGetString(error));
-						ALmixer_SetError("Failed detecting still processed buffers: %s",
-							alGetString(error) );
-						/* This whole iOS 5.0 bug is so messed up that returning an error value probably isn't helpful.
-						retval = AL_FALSE;
-						*/
-					}
-					/*
-					fprintf(stderr, "Going to unqueue %d buffers\n", buffers_processed);
-					 */
-					for(temp_count=0; temp_count<buffers_processed; temp_count++)
-					{
-						ALuint unqueued_buffer_id;
-
-						alSourceUnqueueBuffers(
-							source_id,
-							1, &unqueued_buffer_id
-						);
-						if((error = alGetError()) != AL_NO_ERROR)
-						{
-							fprintf(stderr, "17bTesting error with unqueuing buffers on Halt (You may be seeing this because of a bad Apple OpenAL iOS 5.0 regression bug): %s\n",
-								alGetString(error));				
-							/* This whole iOS 5.0 bug is so messed up that returning an error value probably isn't helpful.
-							 retval = AL_FALSE;
-							 */
-						}
-					}
-					
-					alGetSourcei(
-								 source_id,
-								 AL_BUFFERS_PROCESSED, &buffers_processed
-								 );
-					if((error = alGetError()) != AL_NO_ERROR)
-					{
-						fprintf(stderr, "17cTesting Error with buffers_processed on Halt. (You may be seeing this because of a bad Apple OpenAL iOS 5.0 regression bug): %s",
-								alGetString(error));
-						ALmixer_SetError("Failed detecting still processed buffers: %s",
-										 alGetString(error) );
+						fprintf(stderr, "17bTesting error with unqueuing buffers on Halt (You may be seeing this because of a bad Apple OpenAL iOS 5.0 regression bug): %s\n",
+							alGetString(error));				
 						/* This whole iOS 5.0 bug is so messed up that returning an error value probably isn't helpful.
 						 retval = AL_FALSE;
 						 */
 					}
-					/*
-					fprintf(stderr, "unqueued buffers should be 0. Actual value is %d\n", buffers_processed);
-					*/
-					/* Wow this is the bug that just keeps on sucking. There is an additional race condition bug where the unqueue may not actually work. 
-					 * So I have to keep doing it until it does.
-					 * I hope this doesn't infinite loop.
+				}
+				
+				alGetSourcei(
+							 source_id,
+							 AL_BUFFERS_PROCESSED, &buffers_processed
+							 );
+				if((error = alGetError()) != AL_NO_ERROR)
+				{
+					fprintf(stderr, "17cTesting Error with buffers_processed on Halt. (You may be seeing this because of a bad Apple OpenAL iOS 5.0 regression bug): %s",
+							alGetString(error));
+					ALmixer_SetError("Failed detecting still processed buffers: %s",
+									 alGetString(error) );
+					/* This whole iOS 5.0 bug is so messed up that returning an error value probably isn't helpful.
+					 retval = AL_FALSE;
 					 */
-					if(0 != buffers_processed)
-					{
-						fprintf(stderr, "Evil Apple OpenAL iOS 5.0 race condition. Buffers didn't actually unqueue. Repeating unqueue loop.\n");
-					}
-				} while(0 != buffers_processed);
-
-			}
+				}
+				/*
+				fprintf(stderr, "unqueued buffers should be 0. Actual value is %d\n", buffers_processed);
+				*/
+				/* Wow this is the bug that just keeps on sucking. There is an additional race condition bug where the unqueue may not actually work. 
+				 * So I have to keep doing it until it does.
+				 * I hope this doesn't infinite loop.
+				 */
+				if(0 != buffers_processed)
+				{
+					fprintf(stderr, "Evil Apple OpenAL iOS 5.0 race condition. Buffers didn't actually unqueue. Repeating unqueue loop.\n");
+				}
+			} while(0 != buffers_processed);
+
+			/* Avoid calling the normal cleanup because part of this bug seems to be triggered by alSourcei(source_id, AL_BUFFER, AL_NONE); */
+			return retval;
 		}		
 	
-
 	#endif
 #endif /* iOS 5.0 workaround */