comparison ALmixer.c @ 52:53ee4253c925

merged
author Eric Wing <ewing@anscamobile.com>
date Wed, 18 Jan 2012 12:20:54 -0800
parents e2687188aea5
children 8063b19bd40e
comparison
equal deleted inserted replaced
46:d7da72703681 52:53ee4253c925
1690 /* If we get here, all sources are in use */ 1690 /* If we get here, all sources are in use */
1691 return -1; 1691 return -1;
1692 } 1692 }
1693 1693
1694 1694
1695 static ALboolean Internal_DetachBuffersFromSource(ALuint source_id, ALboolean is_predecoded)
1696 {
1697 ALboolean retval = AL_TRUE;
1698 ALenum error;
1699 /* Here's the situation. My old method of using
1700 * alSourceUnqueueBuffers() seemed to be invalid in light
1701 * of all the problems I suffered through with getting
1702 * the CoreData backend to work with this code.
1703 * As such, I'm changing all the code to set the buffer to
1704 * AL_NONE. Furthermore, the queued vs. non-queued issue
1705 * doesn't need to apply here. For non-queued, Loki,
1706 * Creative Windows, and CoreAudio seem to leave the
1707 * buffer queued (Old Mac didn't.) For queued, we need to
1708 * remove the processed buffers and force remove the
1709 * still-queued buffers.
1710 * Update: This code is was changed agian due to a serious regression bug in iOS 5.0
1711 * Since the 1.1 spec, I think I can make some simplifying assumptions sans the iOS 5.0 bug.
1712 * Before I looked at buffers_still_queued and buffers_processed.
1713 * According to the spec, all buffers get marked processed when alSourceStop is called.
1714 * Also, in addition, alSourcei(source, AL_BUFFER, AL_NONE) is supposed
1715 * to detach buffers for both streamed and non-streamed so all the code
1716 * should just go through that.
1717 * Unfortunately, the iOS 5.0 bug doesn't detach/clear buffers with AL_NONE.
1718 * So I need a special handler for iOS 5.0 which manually unqueues the buffers.
1719 * Ironically, I think the original Mac version did not work reliably
1720 * with unqueuing buffers which is why I moved the code to the AL_NONE
1721 * solution in the first place. This means for safety, I need to
1722 * conditionalize the workaround as not to risk breaking Mac or other * platforms.
1723 */
1724 #ifdef __APPLE__ /* iOS 5.0 workaround */
1725 #if (TARGET_OS_IPHONE == 1) || (TARGET_IPHONE_SIMULATOR == 1)
1726 /*
1727 fprintf(stderr, "kCFCoreFoundationVersionNumber: %lf\n", kCFCoreFoundationVersionNumber);
1728 */
1729 /* I needed a C way to get the iOS version at runtime. This is returning 674.0 iOS 5.0 Beta 7. Apple hasn't updated the headers
1730 * for these constants since iOS 4.2, so I don't know if the value is also catching 4.3.
1731 * iOS 5.0.1 final is returning 675.0.
1732 * 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.
1733 * iOS 5.1 Beta 1 is returning 690.0.
1734 */
1735 if(kCFCoreFoundationVersionNumber >= 674.0 && kCFCoreFoundationVersionNumber < 690.0)
1736 {
1737 /* For OpenAL experts, this is contrary to what you know, but must be done because the OpenAL implementation is broken.
1738 Instead of unqueuing buffers on only streaming sources, it appears that alSourcei(source, AL_BUFFER, AL_NONE) is not reliable at all.
1739 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
1740 and only one buffer plays.
1741 The workaround seems to be to always unqueue buffers regardless of whether the source is streamed or not.
1742 And then avoid calling (source, AL_BUFFER, AL_NONE)
1743 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),
1744 but this seems to work for this bug.
1745 */
1746 ALint buffers_processed;
1747 /* Crap. Another iOS 5.0 problem. It seems our loop workaround below can get in cases where the buffer never clears.
1748 * It appears that in some cases (probably predecoded, but not always which makes it hard), that the buffer never can be unqueued.
1749 * I think it may possibly happen if you never use a source for streaming, and it is also possible it happens after loading or using a certain number of sources.
1750 * So to workaround, we need to abort after a certain amount of time to prevent an infinite loop check.
1751 * Some testing on iPad 2, 122ms is the highest number I've seen so far. So maybe 200ms is the cap?
1752 */
1753 ALuint timeout_counter = ALmixer_GetTicks();
1754 const ALuint MAX_NUMBER_OF_TICKS_TO_WAIT_IN_WORKAROUND = 200;
1755
1756 /* Wow this is the bug that just keeps on sucking. There is even a race condition bug where the unqueue may not actually work.
1757 * So I have to keep doing it until it does.
1758 */
1759 do
1760 {
1761 ALint temp_count;
1762
1763 /* Wow this is the bug that just keeps on sucking. There is even a race condition bug where the unqueue may not actually work.
1764 * So I have to keep doing it until it does.
1765 * Sleeping for 20ms seems to help. 10ms was not long enough. (iPad 2).
1766 * Update: A user is hitting this in a tight loop and calling dozens/hundreds of times. The sleep some times seems to result in a stutter.
1767 * My theory is that there is thread contention and sleeps may be queuing up. The workaround seems to be reduce the sleep or eliminate it.
1768 * I prefer to reduce it because fundamentally I am waiting for the Core Audio/OpenAL thread to finish processing so yielding seems like a good idea.
1769 * The flipside is that I hit a lot of OpenAL errors because the commands keep failing and I'm burning CPU unnecessarily.
1770 * So far, the OpenAL errors seem harmless and there are no serious cascading failures I've encountered.
1771 */
1772 ALmixer_Delay(0);
1773
1774 alGetSourcei(
1775 source_id,
1776 AL_BUFFERS_PROCESSED, &buffers_processed
1777 );
1778 if((error = alGetError()) != AL_NO_ERROR)
1779 {
1780 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",
1781 alGetString(error));
1782 ALmixer_SetError("Failed detecting still processed buffers: %s",
1783 alGetString(error) );
1784 /* This whole iOS 5.0 bug is so messed up that returning an error value probably isn't helpful.
1785 retval = AL_FALSE;
1786 */
1787 }
1788 /*
1789 fprintf(stderr, "Going to unqueue %d buffers\n", buffers_processed);
1790 */
1791 for(temp_count=0; temp_count<buffers_processed; temp_count++)
1792 {
1793 ALuint unqueued_buffer_id;
1794
1795 alSourceUnqueueBuffers(
1796 source_id,
1797 1, &unqueued_buffer_id
1798 );
1799 if((error = alGetError()) != AL_NO_ERROR)
1800 {
1801 /* Disabling this print because we hit it way too much with the usleep(0) */
1802 /* 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));
1803 */
1804 /* This whole iOS 5.0 bug is so messed up that returning an error value probably isn't helpful.
1805 retval = AL_FALSE;
1806 */
1807 }
1808 }
1809
1810 alGetSourcei(
1811 source_id,
1812 AL_BUFFERS_PROCESSED, &buffers_processed
1813 );
1814 if((error = alGetError()) != AL_NO_ERROR)
1815 {
1816 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));
1817 ALmixer_SetError("Failed detecting still processed buffers: %s", alGetString(error) );
1818 /* This whole iOS 5.0 bug is so messed up that returning an error value probably isn't helpful.
1819 retval = AL_FALSE;
1820 */
1821 }
1822 /*
1823 fprintf(stderr, "unqueued buffers should be 0. Actual value is %d\n", buffers_processed);
1824 */
1825 /* Wow this is the bug that just keeps on sucking. There is an additional race condition bug where the unqueue may not actually work.
1826 * So I have to keep doing it until it does.
1827 * I hope this doesn't infinite loop.
1828 */
1829 /* Disabling this print because we hit it way too much with the usleep(0) */
1830 /*
1831 if(0 != buffers_processed)
1832 {
1833 fprintf(stderr, "Evil Apple OpenAL iOS 5.0 race condition. Buffers didn't actually unqueue. Repeating unqueue loop. %d, %d %d\n", ALmixer_GetTicks(), timeout_counter, ALmixer_GetTicks()-timeout_counter);
1834 }
1835 */
1836 } while(0 != buffers_processed && ( (ALmixer_GetTicks()-timeout_counter) < MAX_NUMBER_OF_TICKS_TO_WAIT_IN_WORKAROUND) );
1837
1838 /* Avoid calling the normal cleanup because part of this bug seems to be triggered by alSourcei(source_id, AL_BUFFER, AL_NONE); */
1839 return retval;
1840 }
1841
1842 #endif
1843 #endif /* iOS 5.0 workaround */
1844
1845 /* According to the spec, this is the best way to clear a source.
1846 * This is supposed to work for both streamed and non-streamed sources.
1847 */
1848 alSourcei(source_id, AL_BUFFER, AL_NONE);
1849 if((error = alGetError()) != AL_NO_ERROR)
1850 {
1851 fprintf(stderr, "17dTesting Error with clearing buffer from source: %s",
1852 alGetString(error));
1853 ALmixer_SetError("Failed to clear buffer from source: %s",
1854 alGetString(error) );
1855 retval = AL_FALSE;
1856 }
1857
1858 return retval;
1859 }
1695 1860
1696 /* Will return the number of channels halted 1861 /* Will return the number of channels halted
1697 * or 0 for error 1862 * or 0 for error
1698 */ 1863 */
1699 static ALint Internal_HaltChannel(ALint channel, ALboolean did_finish_naturally) 1864 static ALint Internal_HaltChannel(ALint channel, ALboolean did_finish_naturally)
1700 { 1865 {
1701 ALint retval = 0; 1866 ALint retval = 0;
1702 ALint counter = 0; 1867 ALint counter = 0;
1703 ALenum error; 1868 ALenum error;
1704 ALint buffers_still_queued; 1869 ALboolean clear_succeeded;
1705 ALint buffers_processed;
1706 1870
1707 if(channel >= Number_of_Channels_global) 1871 if(channel >= Number_of_Channels_global)
1708 { 1872 {
1709 ALmixer_SetError("Cannot halt channel %d because it exceeds maximum number of channels (%d)\n", channel, Number_of_Channels_global); 1873 ALmixer_SetError("Cannot halt channel %d because it exceeds maximum number of channels (%d)\n", channel, Number_of_Channels_global);
1710 return -1; 1874 return -1;
1719 if((error = alGetError()) != AL_NO_ERROR) 1883 if((error = alGetError()) != AL_NO_ERROR)
1720 { 1884 {
1721 fprintf(stderr, "14Testing error: %s\n", 1885 fprintf(stderr, "14Testing error: %s\n",
1722 alGetString(error)); 1886 alGetString(error));
1723 } 1887 }
1724 /* Here's the situation. My old method of using 1888
1725 * alSourceUnqueueBuffers() seemed to be invalid in light 1889 clear_succeeded = Internal_DetachBuffersFromSource(ALmixer_Channel_List[channel].alsource, ALmixer_Channel_List[channel].almixer_data->decoded_all);
1726 * of all the problems I suffered through with getting 1890 if(AL_FALSE == clear_succeeded)
1727 * the CoreData backend to work with this code.
1728 * As such, I'm changing all the code to set the buffer to
1729 * AL_NONE. Furthermore, the queued vs. non-queued issue
1730 * doesn't need to apply here. For non-queued, Loki,
1731 * Creative Windows, and CoreAudio seem to leave the
1732 * buffer queued (Old Mac didn't.) For queued, we need to
1733 * remove the processed buffers and force remove the
1734 * still-queued buffers.
1735 */
1736 alGetSourcei(
1737 ALmixer_Channel_List[channel].alsource,
1738 AL_BUFFERS_QUEUED, &buffers_still_queued
1739 );
1740 if((error = alGetError()) != AL_NO_ERROR)
1741 { 1891 {
1742 fprintf(stderr, "17Testing Error with buffers_still_queued: %s",
1743 alGetString(error));
1744 ALmixer_SetError("Failed detecting still queued buffers: %s",
1745 alGetString(error) );
1746 retval = -1; 1892 retval = -1;
1747 } 1893 }
1748 alGetSourcei( 1894
1749 ALmixer_Channel_List[channel].alsource,
1750 AL_BUFFERS_PROCESSED, &buffers_processed
1751 );
1752 if((error = alGetError()) != AL_NO_ERROR)
1753 {
1754 fprintf(stderr, "17Testing Error with buffers_processed: %s",
1755 alGetString(error));
1756 ALmixer_SetError("Failed detecting still processed buffers: %s",
1757 alGetString(error) );
1758 retval = -1;
1759 }
1760 /* If either of these is greater than 0, it means we need
1761 * to clear the source
1762 */
1763 if((buffers_still_queued > 0) || (buffers_processed > 0))
1764 {
1765 alSourcei(ALmixer_Channel_List[channel].alsource,
1766 AL_BUFFER,
1767 AL_NONE);
1768 if((error = alGetError()) != AL_NO_ERROR)
1769 {
1770 fprintf(stderr, "17Testing Error with clearing buffer from source: %s",
1771 alGetString(error));
1772 ALmixer_SetError("Failed to clear buffer from source: %s",
1773 alGetString(error) );
1774 retval = -1;
1775 }
1776 }
1777 1895
1778 ALmixer_Channel_List[channel].almixer_data->num_buffers_in_use = 0; 1896 ALmixer_Channel_List[channel].almixer_data->num_buffers_in_use = 0;
1779 1897
1780 /* Launch callback for consistency? */ 1898 /* Launch callback for consistency? */
1781 Invoke_Channel_Done_Callback(channel, did_finish_naturally); 1899 Invoke_Channel_Done_Callback(channel, did_finish_naturally);
1799 { 1917 {
1800 fprintf(stderr, "19Testing error: %s\n", 1918 fprintf(stderr, "19Testing error: %s\n",
1801 alGetString(error)); 1919 alGetString(error));
1802 } 1920 }
1803 1921
1804 /* Here's the situation. My old method of using 1922 clear_succeeded = Internal_DetachBuffersFromSource(ALmixer_Channel_List[i].alsource, ALmixer_Channel_List[i].almixer_data->decoded_all);
1805 * alSourceUnqueueBuffers() seemed to be invalid in light 1923 if(AL_FALSE == clear_succeeded)
1806 * of all the problems I suffered through with getting
1807 * the CoreData backend to work with this code.
1808 * As such, I'm changing all the code to set the buffer to
1809 * AL_NONE. Furthermore, the queued vs. non-queued issue
1810 * doesn't need to apply here. For non-queued, Loki,
1811 * Creative Windows, and CoreAudio seem to leave the
1812 * buffer queued (Old Mac didn't.) For queued, we need to
1813 * remove the processed buffers and force remove the
1814 * still-queued buffers.
1815 */
1816 alGetSourcei(
1817 ALmixer_Channel_List[i].alsource,
1818 AL_BUFFERS_QUEUED, &buffers_still_queued
1819 );
1820 if((error = alGetError()) != AL_NO_ERROR)
1821 { 1924 {
1822 fprintf(stderr, "17Testing Error with buffers_still_queued: %s",
1823 alGetString(error));
1824 ALmixer_SetError("Failed detecting still queued buffers: %s",
1825 alGetString(error) );
1826 retval = -1; 1925 retval = -1;
1827 } 1926 }
1828 alGetSourcei( 1927
1829 ALmixer_Channel_List[i].alsource,
1830 AL_BUFFERS_PROCESSED, &buffers_processed
1831 );
1832 if((error = alGetError()) != AL_NO_ERROR)
1833 {
1834 fprintf(stderr, "17Testing Error with buffers_processed: %s",
1835 alGetString(error));
1836 ALmixer_SetError("Failed detecting still processed buffers: %s",
1837 alGetString(error) );
1838 retval = -1;
1839 }
1840 /* If either of these is greater than 0, it means we need
1841 * to clear the source
1842 */
1843 if((buffers_still_queued > 0) || (buffers_processed > 0))
1844 {
1845 alSourcei(ALmixer_Channel_List[i].alsource,
1846 AL_BUFFER,
1847 AL_NONE);
1848 if((error = alGetError()) != AL_NO_ERROR)
1849 {
1850 fprintf(stderr, "17Testing Error with clearing buffer from source: %s",
1851 alGetString(error));
1852 ALmixer_SetError("Failed to clear buffer from source: %s",
1853 alGetString(error) );
1854 retval = -1;
1855 }
1856 }
1857
1858 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use = 0; 1928 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use = 0;
1859 1929
1860 /* Launch callback for consistency? */ 1930 /* Launch callback for consistency? */
1861 Invoke_Channel_Done_Callback(i, did_finish_naturally); 1931 Invoke_Channel_Done_Callback(i, did_finish_naturally);
1862 1932
2177 if(channel >= 0) 2247 if(channel >= 0)
2178 { 2248 {
2179 /* only need to process channel if in use */ 2249 /* only need to process channel if in use */
2180 if(ALmixer_Channel_List[channel].channel_in_use) 2250 if(ALmixer_Channel_List[channel].channel_in_use)
2181 { 2251 {
2182 2252 running_count = 1;
2183 /* What should I do? Do I just rewind the channel 2253 /* What should I do? Do I just rewind the channel
2184 * or also rewind the data? Since the data is 2254 * or also rewind the data? Since the data is
2185 * shared, let's make it the user's responsibility 2255 * shared, let's make it the user's responsibility
2186 * to rewind the data. 2256 * to rewind the data.
2187 */ 2257 */
2241 * does no good. Rewinding the data will have an 2311 * does no good. Rewinding the data will have an
2242 * effect, but it will be lagged based on how 2312 * effect, but it will be lagged based on how
2243 * much data is queued. Recommend users call Halt 2313 * much data is queued. Recommend users call Halt
2244 * before rewind if they want immediate results. 2314 * before rewind if they want immediate results.
2245 */ 2315 */
2246 retval = Internal_RewindData(ALmixer_Channel_List[channel].almixer_data); 2316 if(AL_FALSE == Internal_RewindData(ALmixer_Channel_List[channel].almixer_data))
2317 {
2318 retval = -1;
2319 }
2247 } 2320 }
2248 } 2321 }
2249 } 2322 }
2250 /* The user wants to rewind all channels */ 2323 /* The user wants to rewind all channels */
2251 else 2324 else
2254 for(i=0; i<Number_of_Channels_global; i++) 2327 for(i=0; i<Number_of_Channels_global; i++)
2255 { 2328 {
2256 /* only need to process channel if in use */ 2329 /* only need to process channel if in use */
2257 if(ALmixer_Channel_List[i].channel_in_use) 2330 if(ALmixer_Channel_List[i].channel_in_use)
2258 { 2331 {
2332 running_count++;
2259 /* What should I do? Do I just rewind the channel 2333 /* What should I do? Do I just rewind the channel
2260 * or also rewind the data? Since the data is 2334 * or also rewind the data? Since the data is
2261 * shared, let's make it the user's responsibility 2335 * shared, let's make it the user's responsibility
2262 * to rewind the data. 2336 * to rewind the data.
2263 */ 2337 */
2317 * does no good. Rewinding the data will have an 2391 * does no good. Rewinding the data will have an
2318 * effect, but it will be lagged based on how 2392 * effect, but it will be lagged based on how
2319 * much data is queued. Recommend users call Halt 2393 * much data is queued. Recommend users call Halt
2320 * before rewind if they want immediate results. 2394 * before rewind if they want immediate results.
2321 */ 2395 */
2322 running_count += Internal_RewindData(ALmixer_Channel_List[i].almixer_data); 2396 if(AL_FALSE == Internal_RewindData(ALmixer_Channel_List[i].almixer_data))
2397 {
2398 retval = -1;
2399 }
2323 } 2400 }
2324 } 2401 }
2325 } 2402 }
2326 } 2403 }
2327 if(-1 == retval) 2404 if(-1 == retval)
2687 { 2764 {
2688 ALuint k; 2765 ALuint k;
2689 ALuint queue_ret_flag; 2766 ALuint queue_ret_flag;
2690 for(k=0; k<data->num_buffers_in_use; k++) 2767 for(k=0; k<data->num_buffers_in_use; k++)
2691 { 2768 {
2692 // fprintf(stderr, "56c: CircularQueue_PushBack.\n"); 2769 /* fprintf(stderr, "56c: CircularQueue_PushBack.\n"); */
2693 queue_ret_flag = CircularQueueUnsignedInt_PushBack(data->circular_buffer_queue, data->buffer[k]); 2770 queue_ret_flag = CircularQueueUnsignedInt_PushBack(data->circular_buffer_queue, data->buffer[k]);
2694 if(0 == queue_ret_flag) 2771 if(0 == queue_ret_flag)
2695 { 2772 {
2696 fprintf(stderr, "Serious internal error: CircularQueue could not push into queue.\n"); 2773 fprintf(stderr, "Serious internal error: CircularQueue could not push into queue.\n");
2697 ALmixer_SetError("Serious internal error: CircularQueue failed to push into queue"); 2774 ALmixer_SetError("Serious internal error: CircularQueue failed to push into queue");
3289 { 3366 {
3290 ALmixer_SetError("%s", 3367 ALmixer_SetError("%s",
3291 alGetString(error) ); 3368 alGetString(error) );
3292 retval = -1; 3369 retval = -1;
3293 } 3370 }
3294 /* Need to resume playback if it was originally playing */ 3371 /* OpenAL 1.1 spec says if this succeeds on a playing source, it will automatically jump */
3295 if(AL_PLAYING == state) 3372 if(AL_PAUSED == state)
3296 {
3297 alSourcePlay(ALmixer_Channel_List[channel].alsource);
3298 if((error = alGetError()) != AL_NO_ERROR)
3299 {
3300 ALmixer_SetError("%s",
3301 alGetString(error) );
3302 retval = -1;
3303 }
3304 }
3305 else if(AL_PAUSED == state)
3306 { 3373 {
3307 /* HACK: The problem is that when paused, after 3374 /* HACK: The problem is that when paused, after
3308 * the Rewind, I can't get it off the INITIAL 3375 * the Rewind, I can't get it off the INITIAL
3309 * state without restarting 3376 * state without restarting
3310 */ 3377 */
3329 * does no good. Rewinding the data will have an 3396 * does no good. Rewinding the data will have an
3330 * effect, but it will be lagged based on how 3397 * effect, but it will be lagged based on how
3331 * much data is queued. Recommend users call Halt 3398 * much data is queued. Recommend users call Halt
3332 * before rewind if they want immediate results. 3399 * before rewind if they want immediate results.
3333 */ 3400 */
3334 retval = Internal_SeekData(ALmixer_Channel_List[channel].almixer_data, msec); 3401 if(AL_FALSE == Internal_SeekData(ALmixer_Channel_List[channel].almixer_data, msec))
3402 {
3403 retval = -1;
3404 }
3335 } 3405 }
3406 running_count = 1;
3336 } 3407 }
3337 } 3408 }
3338 /* The user wants to rewind all channels */ 3409 /* The user wants to rewind all channels */
3339 else 3410 else
3340 { 3411 {
3361 { 3432 {
3362 fprintf(stderr, "26Testing error: %s\n", 3433 fprintf(stderr, "26Testing error: %s\n",
3363 alGetString(error)); 3434 alGetString(error));
3364 } 3435 }
3365 3436
3437 /* OpenAL 1.1 spec says if this succeeds on a playing source, it will automatically jump */
3366 alSourcef(ALmixer_Channel_List[channel].alsource, AL_SEC_OFFSET, sec_offset); 3438 alSourcef(ALmixer_Channel_List[channel].alsource, AL_SEC_OFFSET, sec_offset);
3367 if((error = alGetError()) != AL_NO_ERROR) 3439 if((error = alGetError()) != AL_NO_ERROR)
3368 { 3440 {
3369 ALmixer_SetError("%s", 3441 ALmixer_SetError("%s",
3370 alGetString(error) ); 3442 alGetString(error) );
3371 retval = -1; 3443 retval = -1;
3372 } 3444 }
3373 /* Need to resume playback if it was originally playing */ 3445 if(AL_PAUSED == state)
3374 if(AL_PLAYING == state)
3375 {
3376 alSourcePlay(ALmixer_Channel_List[i].alsource);
3377 if((error = alGetError()) != AL_NO_ERROR)
3378 {
3379 ALmixer_SetError("%s",
3380 alGetString(error) );
3381 retval = -1;
3382 }
3383 }
3384 else if(AL_PAUSED == state)
3385 { 3446 {
3386 /* HACK: The problem is that when paused, after 3447 /* HACK: The problem is that when paused, after
3387 * the Rewind, I can't get it off the INITIAL 3448 * the Rewind, I can't get it off the INITIAL
3388 * state without restarting 3449 * state without restarting
3389 */ 3450 */
3408 * does no good. Rewinding the data will have an 3469 * does no good. Rewinding the data will have an
3409 * effect, but it will be lagged based on how 3470 * effect, but it will be lagged based on how
3410 * much data is queued. Recommend users call Halt 3471 * much data is queued. Recommend users call Halt
3411 * before rewind if they want immediate results. 3472 * before rewind if they want immediate results.
3412 */ 3473 */
3413 running_count += Internal_SeekData(ALmixer_Channel_List[i].almixer_data, msec); 3474 if(AL_FALSE == Internal_SeekData(ALmixer_Channel_List[i].almixer_data, msec))
3475 {
3476 retval = -1;
3477 }
3414 } 3478 }
3479 running_count++;
3415 } 3480 }
3416 } 3481 }
3417 } 3482 }
3418 if(-1 == retval) 3483 if(-1 == retval)
3419 { 3484 {
5171 alGetString(error) ); 5236 alGetString(error) );
5172 error_flag--; 5237 error_flag--;
5173 } 5238 }
5174 if(buffers_still_queued > 0) 5239 if(buffers_still_queued > 0)
5175 { 5240 {
5176 5241 ALboolean clear_succeeded = Internal_DetachBuffersFromSource(ALmixer_Channel_List[i].alsource, ALmixer_Channel_List[i].almixer_data->decoded_all);
5177 #if 0 /* This triggers an error in OS X Core Audio. */ 5242 if(AL_FALSE == clear_succeeded)
5178 alSourceUnqueueBuffers(
5179 ALmixer_Channel_List[i].alsource,
5180 1,
5181 ALmixer_Channel_List[i].almixer_data->buffer
5182 );
5183 #else
5184 /* fprintf(stderr, "In the Bob Aron section...about to clear source\n");
5185 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
5186 */
5187 /* Rather than force unqueuing the buffer, let's see if
5188 * setting the buffer to none works (the OpenAL 1.0
5189 * Reference Annotation suggests this should work).
5190 */
5191 alSourcei(ALmixer_Channel_List[i].alsource,
5192 AL_BUFFER, AL_NONE);
5193 /*
5194 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
5195 */
5196 #endif
5197 if((error = alGetError()) != AL_NO_ERROR)
5198 { 5243 {
5199 fprintf(stderr, "Error with unqueue, after alSourceUnqueueBuffers, buffers_still_queued=%d, error is: %s", buffers_still_queued,
5200 alGetString(error));
5201 ALmixer_SetError("Predecoded Unqueue buffer failed: %s",
5202 alGetString(error) );
5203 error_flag--; 5244 error_flag--;
5204 } 5245 }
5205
5206 } 5246 }
5207 5247
5208 /* Launch callback */ 5248 /* Launch callback */
5209 Invoke_Channel_Done_Callback(i, AL_TRUE); 5249 Invoke_Channel_Done_Callback(i, AL_TRUE);
5210 5250
5274 * so we know if we need to refill 5314 * so we know if we need to refill
5275 */ 5315 */
5276 /* WARNING: It looks like Snow Leopard some times crashes on this call under x86_64 5316 /* WARNING: It looks like Snow Leopard some times crashes on this call under x86_64
5277 * typically when I suffer a lot of buffer underruns. 5317 * typically when I suffer a lot of buffer underruns.
5278 */ 5318 */
5279 // fprintf(stderr, "calling AL_BUFFERS_PROCESSED on source:%d", ALmixer_Channel_List[i].alsource); 5319 /* fprintf(stderr, "calling AL_BUFFERS_PROCESSED on source:%d", ALmixer_Channel_List[i].alsource); */
5280 alGetSourcei( 5320 alGetSourcei(
5281 ALmixer_Channel_List[i].alsource, 5321 ALmixer_Channel_List[i].alsource,
5282 AL_BUFFERS_PROCESSED, &buffers_processed 5322 AL_BUFFERS_PROCESSED, &buffers_processed
5283 ); 5323 );
5284 if((error = alGetError()) != AL_NO_ERROR) 5324 if((error = alGetError()) != AL_NO_ERROR)
5285 { 5325 {
5286 fprintf(stderr, "52Testing error: %s\n", 5326 fprintf(stderr, "52Testing error: %s\n",
5287 alGetString(error)); 5327 alGetString(error));
5288 } 5328 }
5289 // fprintf(stderr, "finished AL_BUFFERS_PROCESSED, buffers_processed=%d", buffers_processed); 5329 /* fprintf(stderr, "finished AL_BUFFERS_PROCESSED, buffers_processed=%d", buffers_processed); */
5290 5330
5291 /* WTF!!! The Nvidia distribution is failing on the alGetSourcei(source, AL_BUFFER, buf_id) call. 5331 /* WTF!!! The Nvidia distribution is failing on the alGetSourcei(source, AL_BUFFER, buf_id) call.
5292 * I need this call to figure out which buffer OpenAL is currently playing. 5332 * I need this call to figure out which buffer OpenAL is currently playing.
5293 * It keeps returning an "Invalid Enum" error. 5333 * It keeps returning an "Invalid Enum" error.
5294 * This is totally inane! It's a basic query. 5334 * This is totally inane! It's a basic query.
5481 * If in an underrun, queue up at least startup_buffers. 5521 * If in an underrun, queue up at least startup_buffers.
5482 */ 5522 */
5483 if(AL_STOPPED == state) 5523 if(AL_STOPPED == state)
5484 { 5524 {
5485 number_of_buffers_to_queue_this_pass = ALmixer_Channel_List[i].almixer_data->num_startup_buffers; 5525 number_of_buffers_to_queue_this_pass = ALmixer_Channel_List[i].almixer_data->num_startup_buffers;
5486 // fprintf(stderr, "assuming underrun condition, using num_startup_buffers=%d\n", number_of_buffers_to_queue_this_pass); 5526 /* fprintf(stderr, "assuming underrun condition, using num_startup_buffers=%d\n", number_of_buffers_to_queue_this_pass); */
5487 } 5527 }
5488 5528
5489 /* Don't bother to check to make sure the number_of_buffers_to_queue_this_pass does not exceed the maximum number of buffers because of the logic hack bug. */ 5529 /* Don't bother to check to make sure the number_of_buffers_to_queue_this_pass does not exceed the maximum number of buffers because of the logic hack bug. */
5490 /* Logic Hack/Bug: In adding the number_of_buffers_to_queue_this_pass, I discovered the for-loop needs to be more decoupled. 5530 /* Logic Hack/Bug: In adding the number_of_buffers_to_queue_this_pass, I discovered the for-loop needs to be more decoupled.
5491 * The loop still needs to be entered because unqueuing and completion callbacks and possibly other state processing are also done. 5531 * The loop still needs to be entered because unqueuing and completion callbacks and possibly other state processing are also done.
5495 { 5535 {
5496 number_of_buffers_to_queue_this_pass = 1; 5536 number_of_buffers_to_queue_this_pass = 1;
5497 } 5537 }
5498 for(current_count_of_buffer_queue_passes=0; current_count_of_buffer_queue_passes<number_of_buffers_to_queue_this_pass; current_count_of_buffer_queue_passes++) 5538 for(current_count_of_buffer_queue_passes=0; current_count_of_buffer_queue_passes<number_of_buffers_to_queue_this_pass; current_count_of_buffer_queue_passes++)
5499 { 5539 {
5500 // fprintf(stderr, "current_count_of_buffer_queue_passes:%d\n", current_count_of_buffer_queue_passes); 5540 /* fprintf(stderr, "current_count_of_buffer_queue_passes:%d\n", current_count_of_buffer_queue_passes); */
5541
5542 /* Because I introduced this for-loop, I think I need to regrab the number of processed buffers because
5543 * the number may now be stale from previous iterations. I suppose I could do it at the end of the loop,
5544 * but the logic flow is already too complicated to ensure that the block is being hit.
5545 */
5546 /* Get the number of buffers processed
5547 */
5548 alGetSourcei(
5549 ALmixer_Channel_List[i].alsource,
5550 AL_BUFFERS_PROCESSED,
5551 &buffers_processed
5552 );
5553 if((error = alGetError()) != AL_NO_ERROR)
5554 {
5555 fprintf(stderr, "59aTestingError, Can't get buffers_processed: %s\n",
5556 alGetString(error));
5557 }
5558
5501 5559
5502 /* For this to work, we must rely on EVERYTHING 5560 /* For this to work, we must rely on EVERYTHING
5503 * else to unset the EOF if there is looping. 5561 * else to unset the EOF if there is looping.
5504 * Remember, even Play() must do this 5562 * Remember, even Play() must do this
5505 */ 5563 */
5916 * "access_data" was set, indicated by whether the queue is NULL. 5974 * "access_data" was set, indicated by whether the queue is NULL.
5917 */ 5975 */
5918 if(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue != NULL) 5976 if(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue != NULL)
5919 { 5977 {
5920 ALuint queue_ret_flag; 5978 ALuint queue_ret_flag;
5921 // fprintf(stderr, "56d: CircularQueue_PushBack.\n"); 5979 /* fprintf(stderr, "56d: CircularQueue_PushBack.\n"); */
5922 queue_ret_flag = CircularQueueUnsignedInt_PushBack( 5980 queue_ret_flag = CircularQueueUnsignedInt_PushBack(
5923 ALmixer_Channel_List[i].almixer_data->circular_buffer_queue, 5981 ALmixer_Channel_List[i].almixer_data->circular_buffer_queue,
5924 ALmixer_Channel_List[i].almixer_data->buffer[ALmixer_Channel_List[i].almixer_data->num_buffers_in_use] 5982 ALmixer_Channel_List[i].almixer_data->buffer[ALmixer_Channel_List[i].almixer_data->num_buffers_in_use]
5925 ); 5983 );
5926 if(0 == queue_ret_flag) 5984 if(0 == queue_ret_flag)
5964 * "access_data" was set, indicated by whether the queue is NULL. 6022 * "access_data" was set, indicated by whether the queue is NULL.
5965 */ 6023 */
5966 if(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue != NULL) 6024 if(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue != NULL)
5967 { 6025 {
5968 ALuint queue_ret_flag; 6026 ALuint queue_ret_flag;
5969 // fprintf(stderr, "56e: CircularQueue_PushBack.\n"); 6027 /* fprintf(stderr, "56e: CircularQueue_PushBack.\n"); */
5970 queue_ret_flag = CircularQueueUnsignedInt_PushBack( 6028 queue_ret_flag = CircularQueueUnsignedInt_PushBack(
5971 ALmixer_Channel_List[i].almixer_data->circular_buffer_queue, 6029 ALmixer_Channel_List[i].almixer_data->circular_buffer_queue,
5972 unqueued_buffer_id 6030 unqueued_buffer_id
5973 ); 6031 );
5974 if(0 == queue_ret_flag) 6032 if(0 == queue_ret_flag)
6218 */ 6276 */
6219 /* Rather than force unqueuing the buffer, let's see if 6277 /* Rather than force unqueuing the buffer, let's see if
6220 * setting the buffer to none works (the OpenAL 1.0 6278 * setting the buffer to none works (the OpenAL 1.0
6221 * Reference Annotation suggests this should work). 6279 * Reference Annotation suggests this should work).
6222 */ 6280 */
6223 alSourcei(ALmixer_Channel_List[i].alsource, 6281 ALboolean clear_succeeded = Internal_DetachBuffersFromSource(ALmixer_Channel_List[i].alsource, ALmixer_Channel_List[i].almixer_data->decoded_all);
6224 AL_BUFFER, AL_NONE); 6282 if(AL_FALSE == clear_succeeded)
6283 {
6284 error_flag--;
6285 }
6225 /* 6286 /*
6226 PrintQueueStatus(ALmixer_Channel_List[i].alsource); 6287 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
6227 */ 6288 */
6228 /* This doesn't work because in some cases, I think 6289 /* This doesn't work because in some cases, I think
6229 * it causes the sound to be replayed 6290 * it causes the sound to be replayed
7735 fprintf(stderr, "Error: You should not call ALmixer_SetError while ALmixer is not initialized\n"); 7796 fprintf(stderr, "Error: You should not call ALmixer_SetError while ALmixer is not initialized\n");
7736 return; 7797 return;
7737 } 7798 }
7738 va_list argp; 7799 va_list argp;
7739 va_start(argp, err_str); 7800 va_start(argp, err_str);
7740 // SDL_SetError which I'm emulating has no number parameter. 7801 /* SDL_SetError which I'm emulating has no number parameter. */
7741 TError_SetErrorv(s_ALmixerErrorPool, 1, err_str, argp); 7802 TError_SetErrorv(s_ALmixerErrorPool, 1, err_str, argp);
7742 va_end(argp); 7803 va_end(argp);
7743 } 7804 }
7744 7805
7745 #endif 7806 #endif
8266 while(j>0) 8327 while(j>0)
8267 { 8328 {
8268 free(ret_data->buffer_map_list[j].data); 8329 free(ret_data->buffer_map_list[j].data);
8269 j--; 8330 j--;
8270 } 8331 }
8271 // Delete for j=0 because the while loop misses the last one 8332 /* Delete for j=0 because the while loop misses the last one */
8272 free(ret_data->buffer_map_list[j].data); 8333 free(ret_data->buffer_map_list[j].data);
8273 8334
8274 free(ret_data->buffer_map_list); 8335 free(ret_data->buffer_map_list);
8275 CircularQueueUnsignedInt_FreeQueue(ret_data->circular_buffer_queue); 8336 CircularQueueUnsignedInt_FreeQueue(ret_data->circular_buffer_queue);
8276 Sound_FreeSample(sample); 8337 Sound_FreeSample(sample);