comparison ALmixer.c @ 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
comparison
equal deleted inserted replaced
49:4b0268d86298 50:db5bc1c80057
1730 * for these constants since iOS 4.2, so I don't know if the value is also catching 4.3. 1730 * for these constants since iOS 4.2, so I don't know if the value is also catching 4.3.
1731 * TODO: Once I learn which version Apple fixes the bug in, I need to update the range so this check is not run on fixed versions. 1731 * TODO: Once I learn which version Apple fixes the bug in, I need to update the range so this check is not run on fixed versions.
1732 */ 1732 */
1733 if(kCFCoreFoundationVersionNumber >= 674.0) 1733 if(kCFCoreFoundationVersionNumber >= 674.0)
1734 { 1734 {
1735 if(AL_FALSE == is_predecoded) 1735 /* For OpenAL experts, this is contrary to what you know, but must be done because the OpenAL implementation is broken.
1736 Instead of unqueuing buffers on only streaming sources, it appears that alSourcei(source, AL_BUFFER, AL_NONE) is not reliable at all.
1737 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
1738 and only one buffer plays.
1739 The workaround seems to be to always unqueue buffers regardless of whether the source is streamed or not.
1740 And then avoid calling (source, AL_BUFFER, AL_NONE)
1741 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),
1742 but this seems to work for this bug.
1743 */
1744 ALint buffers_processed;
1745 /* Wow this is the bug that just keeps on sucking. There is even a race condition bug where the unqueue may not actually work.
1746 * So I have to keep doing it until it does.
1747 */
1748 do
1736 { 1749 {
1737 ALint buffers_processed; 1750 ALint temp_count;
1751
1738 /* Wow this is the bug that just keeps on sucking. There is even a race condition bug where the unqueue may not actually work. 1752 /* Wow this is the bug that just keeps on sucking. There is even a race condition bug where the unqueue may not actually work.
1739 * So I have to keep doing it until it does. 1753 * So I have to keep doing it until it does.
1754 * Sleeping for 20ms seems to help. 10ms was not long enough. (iPad 2)
1740 */ 1755 */
1741 do 1756 ALmixer_Delay(20);
1757
1758 alGetSourcei(
1759 source_id,
1760 AL_BUFFERS_PROCESSED, &buffers_processed
1761 );
1762 if((error = alGetError()) != AL_NO_ERROR)
1742 { 1763 {
1743 ALint temp_count; 1764 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",
1744 1765 alGetString(error));
1745 /* Wow this is the bug that just keeps on sucking. There is even a race condition bug where the unqueue may not actually work. 1766 ALmixer_SetError("Failed detecting still processed buffers: %s",
1746 * So I have to keep doing it until it does. 1767 alGetString(error) );
1747 * Sleeping for 20ms seems to help. 10ms was not long enough. (iPad 2) 1768 /* This whole iOS 5.0 bug is so messed up that returning an error value probably isn't helpful.
1748 */ 1769 retval = AL_FALSE;
1749 ALmixer_Delay(20); 1770 */
1750 1771 }
1751 alGetSourcei( 1772 /*
1773 fprintf(stderr, "Going to unqueue %d buffers\n", buffers_processed);
1774 */
1775 for(temp_count=0; temp_count<buffers_processed; temp_count++)
1776 {
1777 ALuint unqueued_buffer_id;
1778
1779 alSourceUnqueueBuffers(
1752 source_id, 1780 source_id,
1753 AL_BUFFERS_PROCESSED, &buffers_processed 1781 1, &unqueued_buffer_id
1754 ); 1782 );
1755 if((error = alGetError()) != AL_NO_ERROR) 1783 if((error = alGetError()) != AL_NO_ERROR)
1756 { 1784 {
1757 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", 1785 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",
1758 alGetString(error)); 1786 alGetString(error));
1759 ALmixer_SetError("Failed detecting still processed buffers: %s",
1760 alGetString(error) );
1761 /* This whole iOS 5.0 bug is so messed up that returning an error value probably isn't helpful.
1762 retval = AL_FALSE;
1763 */
1764 }
1765 /*
1766 fprintf(stderr, "Going to unqueue %d buffers\n", buffers_processed);
1767 */
1768 for(temp_count=0; temp_count<buffers_processed; temp_count++)
1769 {
1770 ALuint unqueued_buffer_id;
1771
1772 alSourceUnqueueBuffers(
1773 source_id,
1774 1, &unqueued_buffer_id
1775 );
1776 if((error = alGetError()) != AL_NO_ERROR)
1777 {
1778 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",
1779 alGetString(error));
1780 /* This whole iOS 5.0 bug is so messed up that returning an error value probably isn't helpful.
1781 retval = AL_FALSE;
1782 */
1783 }
1784 }
1785
1786 alGetSourcei(
1787 source_id,
1788 AL_BUFFERS_PROCESSED, &buffers_processed
1789 );
1790 if((error = alGetError()) != AL_NO_ERROR)
1791 {
1792 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",
1793 alGetString(error));
1794 ALmixer_SetError("Failed detecting still processed buffers: %s",
1795 alGetString(error) );
1796 /* This whole iOS 5.0 bug is so messed up that returning an error value probably isn't helpful. 1787 /* This whole iOS 5.0 bug is so messed up that returning an error value probably isn't helpful.
1797 retval = AL_FALSE; 1788 retval = AL_FALSE;
1798 */ 1789 */
1799 } 1790 }
1800 /* 1791 }
1801 fprintf(stderr, "unqueued buffers should be 0. Actual value is %d\n", buffers_processed); 1792
1802 */ 1793 alGetSourcei(
1803 /* Wow this is the bug that just keeps on sucking. There is an additional race condition bug where the unqueue may not actually work. 1794 source_id,
1804 * So I have to keep doing it until it does. 1795 AL_BUFFERS_PROCESSED, &buffers_processed
1805 * I hope this doesn't infinite loop. 1796 );
1797 if((error = alGetError()) != AL_NO_ERROR)
1798 {
1799 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",
1800 alGetString(error));
1801 ALmixer_SetError("Failed detecting still processed buffers: %s",
1802 alGetString(error) );
1803 /* This whole iOS 5.0 bug is so messed up that returning an error value probably isn't helpful.
1804 retval = AL_FALSE;
1806 */ 1805 */
1807 if(0 != buffers_processed) 1806 }
1808 { 1807 /*
1809 fprintf(stderr, "Evil Apple OpenAL iOS 5.0 race condition. Buffers didn't actually unqueue. Repeating unqueue loop.\n"); 1808 fprintf(stderr, "unqueued buffers should be 0. Actual value is %d\n", buffers_processed);
1810 } 1809 */
1811 } while(0 != buffers_processed); 1810 /* Wow this is the bug that just keeps on sucking. There is an additional race condition bug where the unqueue may not actually work.
1812 1811 * So I have to keep doing it until it does.
1813 } 1812 * I hope this doesn't infinite loop.
1813 */
1814 if(0 != buffers_processed)
1815 {
1816 fprintf(stderr, "Evil Apple OpenAL iOS 5.0 race condition. Buffers didn't actually unqueue. Repeating unqueue loop.\n");
1817 }
1818 } while(0 != buffers_processed);
1819
1820 /* Avoid calling the normal cleanup because part of this bug seems to be triggered by alSourcei(source_id, AL_BUFFER, AL_NONE); */
1821 return retval;
1814 } 1822 }
1815 1823
1816
1817 #endif 1824 #endif
1818 #endif /* iOS 5.0 workaround */ 1825 #endif /* iOS 5.0 workaround */
1819 1826
1820 /* According to the spec, this is the best way to clear a source. 1827 /* According to the spec, this is the best way to clear a source.
1821 * This is supposed to work for both streamed and non-streamed sources. 1828 * This is supposed to work for both streamed and non-streamed sources.