comparison ALmixer.c @ 43:a55e1f3d8f10

merged
author Eric Wing <ewing@anscamobile.com>
date Tue, 30 Aug 2011 19:43:49 -0700
parents 05e5dc4817a4
children 56855942fdc6
comparison
equal deleted inserted replaced
40:2b0b55b7f8cf 43:a55e1f3d8f10
59 /* SDL_sound keeps a private linked list of sounds which get auto-deleted 59 /* SDL_sound keeps a private linked list of sounds which get auto-deleted
60 * on Sound_Quit. This might actually create some leaks for me in certain 60 * on Sound_Quit. This might actually create some leaks for me in certain
61 * usage patterns. To be safe, I should do the same. 61 * usage patterns. To be safe, I should do the same.
62 */ 62 */
63 #include "LinkedList.h" 63 #include "LinkedList.h"
64
65 #ifdef ANDROID_NDK
66 #undef fprintf
67 #include <android/log.h>
68 #define fprintf(stderr, ...) __android_log_print(ANDROID_LOG_INFO, "ALmixer", __VA_ARGS__)
69 #endif
70
64 71
65 #ifdef ENABLE_ALMIXER_THREADS 72 #ifdef ENABLE_ALMIXER_THREADS
66 /* Needed for the Mutex locks (and threads if enabled) */ 73 /* Needed for the Mutex locks (and threads if enabled) */
67 #ifdef ALMIXER_COMPILE_WITHOUT_SDL 74 #ifdef ALMIXER_COMPILE_WITHOUT_SDL
68 #include "SimpleMutex.h" 75 #include "SimpleMutex.h"
5464 * except when there is looping 5471 * except when there is looping
5465 */ 5472 */
5466 5473
5467 /* NEW FEATURE: Try to queue up more buffers per pass, allowing the size of the buffer to be decoupled. */ 5474 /* NEW FEATURE: Try to queue up more buffers per pass, allowing the size of the buffer to be decoupled. */
5468 /* TODO: Optimization: If number of available buffers (max_buffers-buffers_in_use), adjust the number of buffers to queue for this pass. */ 5475 /* TODO: Optimization: If number of available buffers (max_buffers-buffers_in_use), adjust the number of buffers to queue for this pass. */
5476 /* I would benefit from a clearer flag that tells me whether we're in an underrun.
5477 * I think current_buffer only works if data callbacks are enabled.
5478 * So I'll look at for AL_STOPPED which might give me false positives, depending on the code above.
5479 * But I think/hope the code below will deal with it correctly.
5480 * If in an underrun, queue up at least startup_buffers.
5481 */
5482 if(AL_STOPPED == state)
5483 {
5484 number_of_buffers_to_queue_this_pass = ALmixer_Channel_List[i].almixer_data->num_startup_buffers;
5485 // fprintf(stderr, "assuming underrun condition, using num_startup_buffers=%d\n", number_of_buffers_to_queue_this_pass);
5486 }
5487
5488 /* 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. */
5489 /* Logic Hack/Bug: In adding the number_of_buffers_to_queue_this_pass, I discovered the for-loop needs to be more decoupled.
5490 * The loop still needs to be entered because unqueuing and completion callbacks and possibly other state processing are also done.
5491 * So we always need to claim to queue one buffer. (The code already checks for max_queue_buffers.)
5492 */
5493 if(0 == number_of_buffers_to_queue_this_pass)
5494 {
5495 number_of_buffers_to_queue_this_pass = 1;
5496 }
5469 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++) 5497 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++)
5470 { 5498 {
5471 5499 // fprintf(stderr, "current_count_of_buffer_queue_passes:%d\n", current_count_of_buffer_queue_passes);
5472 /* For this to work, we must rely on EVERYTHING 5500
5473 * else to unset the EOF if there is looping. 5501 /* For this to work, we must rely on EVERYTHING
5474 * Remember, even Play() must do this 5502 * else to unset the EOF if there is looping.
5475 */ 5503 * Remember, even Play() must do this
5476
5477 /* If not EOF, then we are still playing.
5478 * Inside, we might find num_of_buffers < NUM...QUEUE_BUF..
5479 * or buffers_process > 0
5480 * in which case we queue up.
5481 * We also might find no buffers we need to fill,
5482 * in which case we just keep going
5483 */
5484 if( ! ALmixer_Channel_List[i].almixer_data->eof)
5485 {
5486 ALuint bytes_returned;
5487 /* We have a priority. We first must assign
5488 * unused buffers in reserve. If there is nothing
5489 * left, then we may unqueue buffers. We can't
5490 * do it the other way around because we will
5491 * lose the pointer to the unqueued buffer
5492 */ 5504 */
5493 if(ALmixer_Channel_List[i].almixer_data->num_buffers_in_use 5505
5494 < ALmixer_Channel_List[i].almixer_data->max_queue_buffers) 5506 /* If not EOF, then we are still playing.
5495 { 5507 * Inside, we might find num_of_buffers < NUM...QUEUE_BUF..
5496 #if 0 5508 * or buffers_process > 0
5497 fprintf(stderr, "Getting more data in NOT_EOF and num_buffers_in_use (%d) < max_queue (%d)\n", 5509 * in which case we queue up.
5498 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use, 5510 * We also might find no buffers we need to fill,
5499 ALmixer_Channel_List[i].almixer_data->max_queue_buffers); 5511 * in which case we just keep going
5500 #endif 5512 */
5501 /* Going to add an unused packet. 5513 if( ! ALmixer_Channel_List[i].almixer_data->eof)
5502 * Grab next packet */ 5514 {
5503 bytes_returned = GetMoreData( 5515 ALuint bytes_returned;
5504 ALmixer_Channel_List[i].almixer_data, 5516 /* We have a priority. We first must assign
5505 ALmixer_Channel_List[i].almixer_data->buffer[ 5517 * unused buffers in reserve. If there is nothing
5506 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use] 5518 * left, then we may unqueue buffers. We can't
5519 * do it the other way around because we will
5520 * lose the pointer to the unqueued buffer
5521 */
5522 if(ALmixer_Channel_List[i].almixer_data->num_buffers_in_use
5523 < ALmixer_Channel_List[i].almixer_data->max_queue_buffers)
5524 {
5525 #if 0
5526 fprintf(stderr, "Getting more data in NOT_EOF and num_buffers_in_use (%d) < max_queue (%d)\n",
5527 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use,
5528 ALmixer_Channel_List[i].almixer_data->max_queue_buffers);
5529 #endif
5530 /* Going to add an unused packet.
5531 * Grab next packet */
5532 bytes_returned = GetMoreData(
5533 ALmixer_Channel_List[i].almixer_data,
5534 ALmixer_Channel_List[i].almixer_data->buffer[
5535 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use]
5536 );
5537 }
5538 /* For processed > 0 */
5539 else if(buffers_processed > 0)
5540 {
5541 /* Unqueue only 1 buffer for now.
5542 * If there are more than one,
5543 * let the next Update pass deal with it
5544 * so we don't stall the program for too long.
5545 */
5546 #if 0
5547 fprintf(stderr, "About to Unqueue, Buffers processed = %d\n", buffers_processed);
5548 fprintf(stderr, "Buffers queued= %d\n", buffers_still_queued);
5549 fprintf(stderr, "Unqueuing a buffer\n");
5550 #endif
5551 alSourceUnqueueBuffers(
5552 ALmixer_Channel_List[i].alsource,
5553 1, &unqueued_buffer_id
5507 ); 5554 );
5508 } 5555 if((error = alGetError()) != AL_NO_ERROR)
5509 /* For processed > 0 */ 5556 {
5510 else if(buffers_processed > 0) 5557 fprintf(stderr, "Error with unqueue: %s, buffer id is %d",
5511 { 5558 alGetString(error), unqueued_buffer_id);
5512 /* Unqueue only 1 buffer for now. 5559 ALmixer_SetError("Unqueue buffer failed: %s",
5513 * If there are more than one, 5560 alGetString(error) );
5514 * let the next Update pass deal with it 5561 error_flag--;
5515 * so we don't stall the program for too long. 5562 }
5563 /*
5564 fprintf(stderr, "Right after unqueue...");
5565 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
5566 fprintf(stderr, "Getting more data for NOT_EOF, max_buffers filled\n");
5567 */
5568 /* Grab unqueued packet */
5569 bytes_returned = GetMoreData(
5570 ALmixer_Channel_List[i].almixer_data,
5571 unqueued_buffer_id);
5572 }
5573 /* We are still streaming, but currently
5574 * don't need to fill any buffers */
5575 else
5576 {
5577 /* Might want to check state */
5578 /* In case the playback stopped,
5579 * we need to resume
5580 * a.k.a. buffer underrun
5581 */
5582 #if 1
5583 /* Try not refetching the state here because I'm getting a duplicate
5584 buffer playback (hiccup) */
5585 alGetSourcei(
5586 ALmixer_Channel_List[i].alsource,
5587 AL_SOURCE_STATE, &state
5588 );
5589 if((error = alGetError()) != AL_NO_ERROR)
5590 {
5591 fprintf(stderr, "54bTesting error: %s\n",
5592 alGetString(error));
5593 }
5594 /* Get the number of buffers processed
5595 */
5596 alGetSourcei(
5597 ALmixer_Channel_List[i].alsource,
5598 AL_BUFFERS_PROCESSED,
5599 &buffers_processed
5600 );
5601 if((error = alGetError()) != AL_NO_ERROR)
5602 {
5603 fprintf(stderr, "54cError, Can't get buffers_processed: %s\n",
5604 alGetString(error));
5605 }
5606 #endif
5607 if(AL_STOPPED == state)
5608 {
5609 /* Resuming in not eof, but nothing to buffer */
5610
5611 /* Okay, here's another lately discovered problem:
5612 * I can't find it in the spec, but for at least some of the
5613 * implementations, if I call play on a stopped source that
5614 * has processed buffers, all those buffers get marked as unprocessed
5615 * on alSourcePlay. So if I had a queue of 25 with 24 of the buffers
5616 * processed, on resume, the earlier 24 buffers will get replayed,
5617 * causing a "hiccup" like sound in the playback.
5618 * To avoid this, I must unqueue all processed buffers before
5619 * calling play. But to complicate things, I need to worry about resyncing
5620 * the circular queue with this since I designed this thing
5621 * with some correlation between the two. However, I might
5622 * have already handled this, so I will try writing this code without
5623 * syncing for now.
5624 * There is currently an assumption that a buffer
5625 * was queued above so I actually have something
5626 * to play.
5627 */
5628 ALint temp_count;
5629 #if 0
5630 fprintf(stderr, "STOPPED1, need to clear processed=%d, status is:\n", buffers_processed);
5631 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
5632 #endif
5633 for(temp_count=0; temp_count<buffers_processed; temp_count++)
5634 {
5635 alSourceUnqueueBuffers(
5636 ALmixer_Channel_List[i].alsource,
5637 1, &unqueued_buffer_id
5638 );
5639 if((error = alGetError()) != AL_NO_ERROR)
5640 {
5641 fprintf(stderr, "55aTesting error: %s\n",
5642 alGetString(error));
5643 error_flag--;
5644 }
5645 }
5646 #if 0
5647 fprintf(stderr, "After unqueue clear...:\n");
5648 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
5649 #endif
5650 /* My assertion: We are STOPPED but not EOF.
5651 * This means we have a buffer underrun.
5652 * We just cleared out the unqueued buffers.
5653 * So we need to reset the mixer_data to reflect we have
5654 * no buffers in queue.
5655 * We need to GetMoreData and then queue up the data.
5656 * Then we need to resume playing.
5657 */
5658 #if 0
5659 int buffers_queued;
5660 alGetSourcei(
5661 ALmixer_Channel_List[i].alsource,
5662 AL_BUFFERS_QUEUED,
5663 &buffers_queued
5664 );
5665
5666 if((error = alGetError()) != AL_NO_ERROR)
5667 {
5668 fprintf(stderr, "Error in PrintQueueStatus, Can't get buffers_queued: %s\n",
5669 alGetString(error));
5670 }
5671 assert(buffers_queued == 0);
5672 fprintf(stderr, "buffer underrun: buffers_queued:%d\n", buffers_queued);
5673 #endif
5674
5675 /* Reset the number of buffers in use to 0 */
5676 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use = 0;
5677
5678 /* Get more data and put it in the first buffer */
5679 bytes_returned = GetMoreData(
5680 ALmixer_Channel_List[i].almixer_data,
5681 ALmixer_Channel_List[i].almixer_data->buffer[0]
5682 );
5683 /* NOTE: We might want to look for EOF and handle it here.
5684 * Currently, I just let the next loop handle it which seems to be working.
5685 */
5686 if(bytes_returned > 0)
5687 {
5688 /* Queue up the new data */
5689 alSourceQueueBuffers(
5690 ALmixer_Channel_List[i].alsource,
5691 1,
5692 &ALmixer_Channel_List[i].almixer_data->buffer[0]
5693 );
5694 if((error = alGetError()) != AL_NO_ERROR)
5695 {
5696 fprintf(stderr, "56e alSourceQueueBuffers error: %s\n",
5697 alGetString(error));
5698 }
5699 /* Increment the number of buffers in use */
5700 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use++;
5701
5702
5703 /* We need to empty and update the circular buffer queue if it is in use */
5704 if(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue != NULL)
5705 {
5706 ALuint queue_ret_flag;
5707 CircularQueueUnsignedInt_Clear(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue);
5708 queue_ret_flag = CircularQueueUnsignedInt_PushBack(
5709 ALmixer_Channel_List[i].almixer_data->circular_buffer_queue,
5710 ALmixer_Channel_List[i].almixer_data->buffer[0]
5711 );
5712 if(0 == queue_ret_flag)
5713 {
5714 fprintf(stderr, "56fSerious internal error: CircularQueue could not push into queue.\n");
5715 ALmixer_SetError("Serious internal error: CircularQueue failed to push into queue");
5716 }
5717 }
5718
5719
5720
5721
5722 /* Resume playback from underrun */
5723 alSourcePlay(ALmixer_Channel_List[i].alsource);
5724 if((error = alGetError()) != AL_NO_ERROR)
5725 {
5726 fprintf(stderr, "55Tbesting error: %s\n",
5727 alGetString(error));
5728 }
5729 }
5730
5731 }
5732 /* Let's escape to the next loop.
5733 * All code below this point is for queuing up
5734 */
5735 /*
5736 fprintf(stderr, "Entry: Nothing to do...continue\n\n");
5737 */
5738 continue;
5739 }
5740 /* We now know we have to fill an available
5741 * buffer.
5516 */ 5742 */
5517 #if 0 5743
5518 fprintf(stderr, "About to Unqueue, Buffers processed = %d\n", buffers_processed); 5744 /* In the previous branch, we just grabbed more data.
5519 fprintf(stderr, "Buffers queued= %d\n", buffers_still_queued); 5745 * Let's check it to make sure it's okay,
5520 fprintf(stderr, "Unqueuing a buffer\n"); 5746 * and then queue it up
5521 #endif 5747 */
5522 alSourceUnqueueBuffers( 5748 /* This check doesn't work anymore because it is now ALuint */
5523 ALmixer_Channel_List[i].alsource, 5749 #if 0
5524 1, &unqueued_buffer_id 5750 if(-1 == bytes_returned)
5525 );
5526 if((error = alGetError()) != AL_NO_ERROR)
5527 { 5751 {
5528 fprintf(stderr, "Error with unqueue: %s", 5752 /* Problem occurred...not sure what to do */
5529 alGetString(error)); 5753 /* Go to next loop? */
5530 ALmixer_SetError("Unqueue buffer failed: %s",
5531 alGetString(error) );
5532 error_flag--; 5754 error_flag--;
5755 /* Set the eof flag to force a quit so
5756 * we don't get stuck in an infinite loop
5757 */
5758 ALmixer_Channel_List[i].almixer_data->eof = 1;
5759 continue;
5533 } 5760 }
5534 /* 5761 #endif
5535 fprintf(stderr, "Right after unqueue..."); 5762 /* This is a special case where we've run
5536 PrintQueueStatus(ALmixer_Channel_List[i].alsource); 5763 * out of data. We should check for loops
5537 fprintf(stderr, "Getting more data for NOT_EOF, max_buffers filled\n"); 5764 * and get more data. If there is no loop,
5538 */ 5765 * then do nothing and wait for future
5539 /* Grab unqueued packet */ 5766 * update passes to handle the EOF.
5540 bytes_returned = GetMoreData( 5767 * The advantage of handling the loop here
5541 ALmixer_Channel_List[i].almixer_data, 5768 * instead of waiting for play to stop is
5542 unqueued_buffer_id); 5769 * that we should be able to keep the buffer
5543 } 5770 * filled.
5544 /* We are still streaming, but currently 5771 */
5545 * don't need to fill any buffers */ 5772 #if 0
5546 else 5773 else if(0 == bytes_returned)
5547 { 5774 #endif
5775 if(0 == bytes_returned)
5776 {
5777 /*
5778 fprintf(stderr, "We got 0 bytes from reading. Checking for loops\n");
5779 */
5780 /* Check for loops */
5781 if( ALmixer_Channel_List[i].loops != 0 )
5782 {
5783 /* We have to loop, so rewind
5784 * and fetch more data
5785 */
5786 /*
5787 fprintf(stderr, "Rewinding data\n");
5788 */
5789 if(0 == Sound_Rewind(
5790 ALmixer_Channel_List[i].almixer_data->sample))
5791 {
5792 fprintf(stderr, "Rewinding failed\n");
5793 ALmixer_SetError( Sound_GetError() );
5794 ALmixer_Channel_List[i].loops = 0;
5795 error_flag--;
5796 /* We'll continue on because we do have some valid data */
5797 continue;
5798 }
5799 /* Remember to reset the data->eof flag */
5800 ALmixer_Channel_List[i].almixer_data->eof = 0;
5801 if(ALmixer_Channel_List[i].loops > 0)
5802 {
5803 ALmixer_Channel_List[i].loops--;
5804 }
5805 /* Try grabbing another packet now.
5806 * Since we may have already unqueued a
5807 * buffer, we don't want to lose it.
5808 */
5809 if(ALmixer_Channel_List[i].almixer_data->num_buffers_in_use
5810 < ALmixer_Channel_List[i].almixer_data->max_queue_buffers)
5811 {
5812 /*
5813 fprintf(stderr, "We got %d bytes from reading loop. Filling unused packet\n", bytes_returned);
5814 */
5815 /* Grab next packet */
5816 bytes_returned = GetMoreData(
5817 ALmixer_Channel_List[i].almixer_data,
5818 ALmixer_Channel_List[i].almixer_data->buffer[
5819 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use]
5820 );
5821 /*
5822 fprintf(stderr, "We reread %d bytes into unused packet\n", bytes_returned);
5823 */
5824 }
5825 /* Refilling unqueued packet */
5826 else
5827 {
5828 /*
5829 fprintf(stderr, "We got %d bytes from reading loop. Filling unqueued packet\n", bytes_returned);
5830 */
5831 /* Grab next packet */
5832 bytes_returned = GetMoreData(
5833 ALmixer_Channel_List[i].almixer_data,
5834 unqueued_buffer_id);
5835 /*
5836 fprintf(stderr, "We reread %d bytes into unqueued packet\n", bytes_returned);
5837 */
5838 }
5839 /* Another error check */
5840 /*
5841 if(bytes_returned <= 0)
5842 */
5843 if(0 == bytes_returned)
5844 {
5845 fprintf(stderr, "??????????ERROR\n");
5846 ALmixer_SetError("Could not loop because after rewind, no data could be retrieved");
5847 /* Problem occurred...not sure what to do */
5848 /* Go to next loop? */
5849 error_flag--;
5850 /* Set the eof flag to force a quit so
5851 * we don't get stuck in an infinite loop
5852 */
5853 ALmixer_Channel_List[i].almixer_data->eof = 1;
5854 continue;
5855 }
5856 /* We made it to the end. We still need
5857 * to BufferData, so let this branch
5858 * fall into the next piece of
5859 * code below which will handle that
5860 */
5861
5862
5863 } /* END loop check */
5864 else
5865 {
5866 /* No more loops to do.
5867 * EOF flag should be set.
5868 * Just go to next loop and
5869 * let things be handled correctly
5870 * in future update calls
5871 */
5872 /*
5873 fprintf(stderr, "SHOULD BE EOF\n");
5874
5875 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
5876 */
5877 continue;
5878 }
5879 } /* END if bytes_returned == 0 */
5880 /********* Possible trouble point. I might be queueing empty buffers on the mac.
5881 * This check doesn't say if the buffer is valid. Only the EOF assumption is a clue at this point
5882 */
5883 /* Fall here */
5884 /* Everything is normal. We aren't
5885 * at an EOF, but need to simply
5886 * queue more data. The data is already checked for good,
5887 * so queue it up */
5888 if(ALmixer_Channel_List[i].almixer_data->num_buffers_in_use
5889 < ALmixer_Channel_List[i].almixer_data->max_queue_buffers)
5890 {
5891 /* Keep count of how many buffers we have
5892 * to queue so we can return the value
5893 */
5894 retval++;
5895 /*
5896 fprintf(stderr, "NOT_EOF???, about to Queue more data for num_buffers (%d) < max_queue (%d)\n",
5897 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use,
5898 ALmixer_Channel_List[i].almixer_data->max_queue_buffers);
5899 */
5900 alSourceQueueBuffers(
5901 ALmixer_Channel_List[i].alsource,
5902 1,
5903 &ALmixer_Channel_List[i].almixer_data->buffer[
5904 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use]
5905 );
5906 if((error = alGetError()) != AL_NO_ERROR)
5907 {
5908 fprintf(stderr, "56Testing error: %s\n",
5909 alGetString(error));
5910 }
5911 /* This is part of the hideous Nvidia workaround. In order to figure out
5912 * which buffer to show during callbacks (for things like
5913 * o-scopes), I must keep a copy of the buffers that are queued in my own
5914 * data structure. This code will be called only if
5915 * "access_data" was set, indicated by whether the queue is NULL.
5916 */
5917 if(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue != NULL)
5918 {
5919 ALuint queue_ret_flag;
5920 // fprintf(stderr, "56d: CircularQueue_PushBack.\n");
5921 queue_ret_flag = CircularQueueUnsignedInt_PushBack(
5922 ALmixer_Channel_List[i].almixer_data->circular_buffer_queue,
5923 ALmixer_Channel_List[i].almixer_data->buffer[ALmixer_Channel_List[i].almixer_data->num_buffers_in_use]
5924 );
5925 if(0 == queue_ret_flag)
5926 {
5927 fprintf(stderr, "56aSerious internal error: CircularQueue could not push into queue.\n");
5928 ALmixer_SetError("Serious internal error: CircularQueue failed to push into queue");
5929 }
5930 /*
5931 else
5932 {
5933 CircularQueueUnsignedInt_Print(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue);
5934 }
5935 */
5936 }
5937 }
5938 /* for processed > 0 */
5939 else
5940 {
5941 /* Keep count of how many buffers we have
5942 * to queue so we can return the value
5943 */
5944 retval++;
5945 /*
5946 fprintf(stderr, "NOT_EOF, about to Queue more data for filled max_queue (%d)\n",
5947 ALmixer_Channel_List[i].almixer_data->max_queue_buffers);
5948 */
5949 alSourceQueueBuffers(
5950 ALmixer_Channel_List[i].alsource,
5951 1, &unqueued_buffer_id);
5952 if((error = alGetError()) != AL_NO_ERROR)
5953 {
5954 ALmixer_SetError("Could not QueueBuffer: %s",
5955 alGetString(error) );
5956 error_flag--;
5957 continue;
5958 }
5959 /* This is part of the hideous Nvidia workaround. In order to figure out
5960 * which buffer to show during callbacks (for things like
5961 * o-scopes), I must keep a copy of the buffers that are queued in my own
5962 * data structure. This code will be called only if
5963 * "access_data" was set, indicated by whether the queue is NULL.
5964 */
5965 if(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue != NULL)
5966 {
5967 ALuint queue_ret_flag;
5968 // fprintf(stderr, "56e: CircularQueue_PushBack.\n");
5969 queue_ret_flag = CircularQueueUnsignedInt_PushBack(
5970 ALmixer_Channel_List[i].almixer_data->circular_buffer_queue,
5971 unqueued_buffer_id
5972 );
5973 if(0 == queue_ret_flag)
5974 {
5975 fprintf(stderr, "56bSerious internal error: CircularQueue could not push into queue.\n");
5976 ALmixer_SetError("Serious internal error: CircularQueue failed to push into queue");
5977 }
5978 #if 0
5979 else
5980 {
5981 CircularQueueUnsignedInt_Print(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue);
5982 }
5983 #endif
5984 }
5985 }
5986 /* If we used an available buffer queue,
5987 * then we need to update the number of them in use
5988 */
5989 if(ALmixer_Channel_List[i].almixer_data->num_buffers_in_use
5990 < ALmixer_Channel_List[i].almixer_data->max_queue_buffers)
5991 {
5992 /* Increment the number of buffers in use */
5993 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use++;
5994 }
5548 /* Might want to check state */ 5995 /* Might want to check state */
5549 /* In case the playback stopped, 5996 /* In case the playback stopped,
5550 * we need to resume 5997 * we need to resume */
5551 * a.k.a. buffer underrun
5552 */
5553 #if 1 5998 #if 1
5554 /* Try not refetching the state here because I'm getting a duplicate 5999 /* Try not refetching the state here because I'm getting a duplicate
5555 buffer playback (hiccup) */ 6000 buffer playback (hiccup) */
5556 alGetSourcei( 6001 alGetSourcei(
5557 ALmixer_Channel_List[i].alsource, 6002 ALmixer_Channel_List[i].alsource,
5558 AL_SOURCE_STATE, &state 6003 AL_SOURCE_STATE, &state
5559 ); 6004 );
5560 if((error = alGetError()) != AL_NO_ERROR) 6005 if((error = alGetError()) != AL_NO_ERROR)
5561 { 6006 {
5562 fprintf(stderr, "54bTesting error: %s\n", 6007 fprintf(stderr, "57bTesting error: %s\n",
5563 alGetString(error)); 6008 alGetString(error));
5564 } 6009 }
5565 /* Get the number of buffers processed 6010 /* Get the number of buffers processed
5566 */ 6011 */
5567 alGetSourcei( 6012 alGetSourcei(
5569 AL_BUFFERS_PROCESSED, 6014 AL_BUFFERS_PROCESSED,
5570 &buffers_processed 6015 &buffers_processed
5571 ); 6016 );
5572 if((error = alGetError()) != AL_NO_ERROR) 6017 if((error = alGetError()) != AL_NO_ERROR)
5573 { 6018 {
5574 fprintf(stderr, "54cError, Can't get buffers_processed: %s\n", 6019 fprintf(stderr, "57cError, Can't get buffers_processed: %s\n",
5575 alGetString(error)); 6020 alGetString(error));
5576 } 6021 }
5577 #endif 6022 #endif
5578 if(AL_STOPPED == state) 6023 if(AL_STOPPED == state)
5579 { 6024 {
5580 /* Resuming in not eof, but nothing to buffer */ 6025 /*
5581 6026 fprintf(stderr, "Resuming in not eof\n");
5582 /* Okay, here's another lately discovered problem: 6027 */
5583 * I can't find it in the spec, but for at least some of the 6028 /* Okay, here's another lately discovered problem:
5584 * implementations, if I call play on a stopped source that 6029 * I can't find it in the spec, but for at least some of the
5585 * has processed buffers, all those buffers get marked as unprocessed 6030 * implementations, if I call play on a stopped source that
5586 * on alSourcePlay. So if I had a queue of 25 with 24 of the buffers 6031 * has processed buffers, all those buffers get marked as unprocessed
5587 * processed, on resume, the earlier 24 buffers will get replayed, 6032 * on alSourcePlay. So if I had a queue of 25 with 24 of the buffers
5588 * causing a "hiccup" like sound in the playback. 6033 * processed, on resume, the earlier 24 buffers will get replayed,
5589 * To avoid this, I must unqueue all processed buffers before 6034 * causing a "hiccup" like sound in the playback.
5590 * calling play. But to complicate things, I need to worry about resyncing 6035 * To avoid this, I must unqueue all processed buffers before
5591 * the circular queue with this since I designed this thing 6036 * calling play. But to complicate things, I need to worry about resyncing
5592 * with some correlation between the two. However, I might 6037 * the circular queue with this since I designed this thing
5593 * have already handled this, so I will try writing this code without 6038 * with some correlation between the two. However, I might
5594 * syncing for now. 6039 * have already handled this, so I will try writing this code without
5595 * There is currently an assumption that a buffer 6040 * syncing for now.
5596 * was queued above so I actually have something 6041 * There is currently an assumption that a buffer
5597 * to play. 6042 * was queued above so I actually have something
6043 * to play.
6044 */
6045 ALint temp_count;
6046 /*
6047 fprintf(stderr, "STOPPED2, need to clear processed, status is:\n");
6048 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
6049 */
6050
6051 for(temp_count=0; temp_count<buffers_processed; temp_count++)
6052 {
6053 alSourceUnqueueBuffers(
6054 ALmixer_Channel_List[i].alsource,
6055 1, &unqueued_buffer_id
6056 );
6057 if((error = alGetError()) != AL_NO_ERROR)
6058 {
6059 fprintf(stderr, "58aTesting error: %s\n",
6060 alGetString(error));
6061 error_flag--;
6062 }
6063 }
6064 /*
6065 fprintf(stderr, "After unqueue clear...:\n");
6066 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
6067 */
6068
6069 alSourcePlay(ALmixer_Channel_List[i].alsource);
6070 if((error = alGetError()) != AL_NO_ERROR)
6071 {
6072 fprintf(stderr, "55Tbesting 8rror: %s\n",
6073 alGetString(error));
6074 }
6075 }
6076 continue;
6077 } /* END if( ! eof) */
6078 /* We have hit EOF in the SDL_Sound sample and there
6079 * are no more loops. However, there may still be
6080 * buffers in the OpenAL queue which still need to
6081 * be played out. The following body of code will
6082 * determine if play is still happening or
6083 * initiate the stop/cleanup sequenece.
6084 */
6085 else
6086 {
6087 /* Let's continue to remove the used up
6088 * buffers as they come in. */
6089 if(buffers_processed > 0)
6090 {
6091 ALint temp_count;
6092 /* Do as a for-loop because I don't want
6093 * to have to create an array for the
6094 * unqueued_buffer_id's
5598 */ 6095 */
5599 ALint temp_count;
5600 #if 0
5601 fprintf(stderr, "STOPPED1, need to clear processed=%d, status is:\n", buffers_processed);
5602 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
5603 #endif
5604 for(temp_count=0; temp_count<buffers_processed; temp_count++) 6096 for(temp_count=0; temp_count<buffers_processed; temp_count++)
5605 { 6097 {
6098 /*
6099 fprintf(stderr, "unqueuing remainder, %d\n", temp_count);
6100 */
5606 alSourceUnqueueBuffers( 6101 alSourceUnqueueBuffers(
5607 ALmixer_Channel_List[i].alsource, 6102 ALmixer_Channel_List[i].alsource,
5608 1, &unqueued_buffer_id 6103 1, &unqueued_buffer_id
5609 ); 6104 );
5610 if((error = alGetError()) != AL_NO_ERROR) 6105 if((error = alGetError()) != AL_NO_ERROR)
5611 { 6106 {
5612 fprintf(stderr, "55aTesting error: %s\n", 6107 fprintf(stderr, "59Testing error: %s\n",
5613 alGetString(error)); 6108 alGetString(error));
5614 error_flag--;
5615 } 6109 }
5616 } 6110 }
5617 #if 0 6111 /*
5618 fprintf(stderr, "After unqueue clear...:\n"); 6112 fprintf(stderr, "done unqueuing remainder for this loop, %d\n", temp_count);
5619 PrintQueueStatus(ALmixer_Channel_List[i].alsource); 6113 */
5620 #endif 6114
5621 /* My assertion: We are STOPPED but not EOF. 6115 /* Need to update counts since we removed everything.
5622 * This means we have a buffer underrun. 6116 * If we don't update the counts here, we end up in the
5623 * We just cleared out the unqueued buffers. 6117 * "Shouldn't be here section, but maybe it's okay due to race conditions"
5624 * So we need to reset the mixer_data to reflect we have
5625 * no buffers in queue.
5626 * We need to GetMoreData and then queue up the data.
5627 * Then we need to resume playing.
5628 */ 6118 */
5629 #if 0
5630 int buffers_queued;
5631 alGetSourcei( 6119 alGetSourcei(
5632 ALmixer_Channel_List[i].alsource, 6120 ALmixer_Channel_List[i].alsource,
5633 AL_BUFFERS_QUEUED, 6121 AL_BUFFERS_QUEUED, &buffers_still_queued
5634 &buffers_queued
5635 ); 6122 );
5636
5637 if((error = alGetError()) != AL_NO_ERROR) 6123 if((error = alGetError()) != AL_NO_ERROR)
5638 { 6124 {
5639 fprintf(stderr, "Error in PrintQueueStatus, Can't get buffers_queued: %s\n", 6125 fprintf(stderr, "5100Testing error: %s\n",
5640 alGetString(error)); 6126 alGetString(error));
5641 }
5642 assert(buffers_queued == 0);
5643 fprintf(stderr, "buffer underrun: buffers_queued:%d\n", buffers_queued);
5644 #endif
5645
5646 /* Reset the number of buffers in use to 0 */
5647 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use = 0;
5648
5649 /* Get more data and put it in the first buffer */
5650 bytes_returned = GetMoreData(
5651 ALmixer_Channel_List[i].almixer_data,
5652 ALmixer_Channel_List[i].almixer_data->buffer[0]
5653 );
5654 /* NOTE: We might want to look for EOF and handle it here.
5655 * Currently, I just let the next loop handle it which seems to be working.
5656 */
5657 if(bytes_returned > 0)
5658 {
5659 /* Queue up the new data */
5660 alSourceQueueBuffers(
5661 ALmixer_Channel_List[i].alsource,
5662 1,
5663 &ALmixer_Channel_List[i].almixer_data->buffer[0]
5664 );
5665 if((error = alGetError()) != AL_NO_ERROR)
5666 {
5667 fprintf(stderr, "56e alSourceQueueBuffers error: %s\n",
5668 alGetString(error));
5669 }
5670 /* Increment the number of buffers in use */
5671 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use++;
5672
5673
5674 /* We need to empty and update the circular buffer queue if it is in use */
5675 if(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue != NULL)
5676 {
5677 ALuint queue_ret_flag;
5678 CircularQueueUnsignedInt_Clear(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue);
5679 queue_ret_flag = CircularQueueUnsignedInt_PushBack(
5680 ALmixer_Channel_List[i].almixer_data->circular_buffer_queue,
5681 ALmixer_Channel_List[i].almixer_data->buffer[0]
5682 );
5683 if(0 == queue_ret_flag)
5684 {
5685 fprintf(stderr, "56fSerious internal error: CircularQueue could not push into queue.\n");
5686 ALmixer_SetError("Serious internal error: CircularQueue failed to push into queue");
5687 }
5688 }
5689
5690
5691
5692
5693 /* Resume playback from underrun */
5694 alSourcePlay(ALmixer_Channel_List[i].alsource);
5695 if((error = alGetError()) != AL_NO_ERROR)
5696 {
5697 fprintf(stderr, "55Tbesting error: %s\n",
5698 alGetString(error));
5699 }
5700 } 6127 }
5701 6128 /* Get the number of buffers processed
5702 } 6129 * so we know if we need to refill
5703 /* Let's escape to the next loop. 6130 */
5704 * All code below this point is for queuing up 6131 alGetSourcei(
5705 */ 6132 ALmixer_Channel_List[i].alsource,
5706 /* 6133 AL_BUFFERS_PROCESSED, &buffers_processed
5707 fprintf(stderr, "Entry: Nothing to do...continue\n\n"); 6134 );
5708 */
5709 continue;
5710 }
5711 /* We now know we have to fill an available
5712 * buffer.
5713 */
5714
5715 /* In the previous branch, we just grabbed more data.
5716 * Let's check it to make sure it's okay,
5717 * and then queue it up
5718 */
5719 /* This check doesn't work anymore because it is now ALuint */
5720 #if 0
5721 if(-1 == bytes_returned)
5722 {
5723 /* Problem occurred...not sure what to do */
5724 /* Go to next loop? */
5725 error_flag--;
5726 /* Set the eof flag to force a quit so
5727 * we don't get stuck in an infinite loop
5728 */
5729 ALmixer_Channel_List[i].almixer_data->eof = 1;
5730 continue;
5731 }
5732 #endif
5733 /* This is a special case where we've run
5734 * out of data. We should check for loops
5735 * and get more data. If there is no loop,
5736 * then do nothing and wait for future
5737 * update passes to handle the EOF.
5738 * The advantage of handling the loop here
5739 * instead of waiting for play to stop is
5740 * that we should be able to keep the buffer
5741 * filled.
5742 */
5743 #if 0
5744 else if(0 == bytes_returned)
5745 #endif
5746 if(0 == bytes_returned)
5747 {
5748 /*
5749 fprintf(stderr, "We got 0 bytes from reading. Checking for loops\n");
5750 */
5751 /* Check for loops */
5752 if( ALmixer_Channel_List[i].loops != 0 )
5753 {
5754 /* We have to loop, so rewind
5755 * and fetch more data
5756 */
5757 /*
5758 fprintf(stderr, "Rewinding data\n");
5759 */
5760 if(0 == Sound_Rewind(
5761 ALmixer_Channel_List[i].almixer_data->sample))
5762 {
5763 fprintf(stderr, "Rewinding failed\n");
5764 ALmixer_SetError( Sound_GetError() );
5765 ALmixer_Channel_List[i].loops = 0;
5766 error_flag--;
5767 /* We'll continue on because we do have some valid data */
5768 continue;
5769 }
5770 /* Remember to reset the data->eof flag */
5771 ALmixer_Channel_List[i].almixer_data->eof = 0;
5772 if(ALmixer_Channel_List[i].loops > 0)
5773 {
5774 ALmixer_Channel_List[i].loops--;
5775 }
5776 /* Try grabbing another packet now.
5777 * Since we may have already unqueued a
5778 * buffer, we don't want to lose it.
5779 */
5780 if(ALmixer_Channel_List[i].almixer_data->num_buffers_in_use
5781 < ALmixer_Channel_List[i].almixer_data->max_queue_buffers)
5782 {
5783 /*
5784 fprintf(stderr, "We got %d bytes from reading loop. Filling unused packet\n", bytes_returned);
5785 */
5786 /* Grab next packet */
5787 bytes_returned = GetMoreData(
5788 ALmixer_Channel_List[i].almixer_data,
5789 ALmixer_Channel_List[i].almixer_data->buffer[
5790 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use]
5791 );
5792 /*
5793 fprintf(stderr, "We reread %d bytes into unused packet\n", bytes_returned);
5794 */
5795 }
5796 /* Refilling unqueued packet */
5797 else
5798 {
5799 /*
5800 fprintf(stderr, "We got %d bytes from reading loop. Filling unqueued packet\n", bytes_returned);
5801 */
5802 /* Grab next packet */
5803 bytes_returned = GetMoreData(
5804 ALmixer_Channel_List[i].almixer_data,
5805 unqueued_buffer_id);
5806 /*
5807 fprintf(stderr, "We reread %d bytes into unqueued packet\n", bytes_returned);
5808 */
5809 }
5810 /* Another error check */
5811 /*
5812 if(bytes_returned <= 0)
5813 */
5814 if(0 == bytes_returned)
5815 {
5816 fprintf(stderr, "??????????ERROR\n");
5817 ALmixer_SetError("Could not loop because after rewind, no data could be retrieved");
5818 /* Problem occurred...not sure what to do */
5819 /* Go to next loop? */
5820 error_flag--;
5821 /* Set the eof flag to force a quit so
5822 * we don't get stuck in an infinite loop
5823 */
5824 ALmixer_Channel_List[i].almixer_data->eof = 1;
5825 continue;
5826 }
5827 /* We made it to the end. We still need
5828 * to BufferData, so let this branch
5829 * fall into the next piece of
5830 * code below which will handle that
5831 */
5832
5833
5834 } /* END loop check */
5835 else
5836 {
5837 /* No more loops to do.
5838 * EOF flag should be set.
5839 * Just go to next loop and
5840 * let things be handled correctly
5841 * in future update calls
5842 */
5843 /*
5844 fprintf(stderr, "SHOULD BE EOF\n");
5845
5846 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
5847 */
5848 continue;
5849 }
5850 } /* END if bytes_returned == 0 */
5851 /********* Possible trouble point. I might be queueing empty buffers on the mac.
5852 * This check doesn't say if the buffer is valid. Only the EOF assumption is a clue at this point
5853 */
5854 /* Fall here */
5855 /* Everything is normal. We aren't
5856 * at an EOF, but need to simply
5857 * queue more data. The data is already checked for good,
5858 * so queue it up */
5859 if(ALmixer_Channel_List[i].almixer_data->num_buffers_in_use
5860 < ALmixer_Channel_List[i].almixer_data->max_queue_buffers)
5861 {
5862 /* Keep count of how many buffers we have
5863 * to queue so we can return the value
5864 */
5865 retval++;
5866 /*
5867 fprintf(stderr, "NOT_EOF???, about to Queue more data for num_buffers (%d) < max_queue (%d)\n",
5868 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use,
5869 ALmixer_Channel_List[i].almixer_data->max_queue_buffers);
5870 */
5871 alSourceQueueBuffers(
5872 ALmixer_Channel_List[i].alsource,
5873 1,
5874 &ALmixer_Channel_List[i].almixer_data->buffer[
5875 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use]
5876 );
5877 if((error = alGetError()) != AL_NO_ERROR)
5878 {
5879 fprintf(stderr, "56Testing error: %s\n",
5880 alGetString(error));
5881 }
5882 /* This is part of the hideous Nvidia workaround. In order to figure out
5883 * which buffer to show during callbacks (for things like
5884 * o-scopes), I must keep a copy of the buffers that are queued in my own
5885 * data structure. This code will be called only if
5886 * "access_data" was set, indicated by whether the queue is NULL.
5887 */
5888 if(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue != NULL)
5889 {
5890 ALuint queue_ret_flag;
5891 // fprintf(stderr, "56d: CircularQueue_PushBack.\n");
5892 queue_ret_flag = CircularQueueUnsignedInt_PushBack(
5893 ALmixer_Channel_List[i].almixer_data->circular_buffer_queue,
5894 ALmixer_Channel_List[i].almixer_data->buffer[ALmixer_Channel_List[i].almixer_data->num_buffers_in_use]
5895 );
5896 if(0 == queue_ret_flag)
5897 {
5898 fprintf(stderr, "56aSerious internal error: CircularQueue could not push into queue.\n");
5899 ALmixer_SetError("Serious internal error: CircularQueue failed to push into queue");
5900 }
5901 /*
5902 else
5903 {
5904 CircularQueueUnsignedInt_Print(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue);
5905 }
5906 */
5907 }
5908 }
5909 /* for processed > 0 */
5910 else
5911 {
5912 /* Keep count of how many buffers we have
5913 * to queue so we can return the value
5914 */
5915 retval++;
5916 /*
5917 fprintf(stderr, "NOT_EOF, about to Queue more data for filled max_queue (%d)\n",
5918 ALmixer_Channel_List[i].almixer_data->max_queue_buffers);
5919 */
5920 alSourceQueueBuffers(
5921 ALmixer_Channel_List[i].alsource,
5922 1, &unqueued_buffer_id);
5923 if((error = alGetError()) != AL_NO_ERROR)
5924 {
5925 ALmixer_SetError("Could not QueueBuffer: %s",
5926 alGetString(error) );
5927 error_flag--;
5928 continue;
5929 }
5930 /* This is part of the hideous Nvidia workaround. In order to figure out
5931 * which buffer to show during callbacks (for things like
5932 * o-scopes), I must keep a copy of the buffers that are queued in my own
5933 * data structure. This code will be called only if
5934 * "access_data" was set, indicated by whether the queue is NULL.
5935 */
5936 if(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue != NULL)
5937 {
5938 ALuint queue_ret_flag;
5939 // fprintf(stderr, "56e: CircularQueue_PushBack.\n");
5940 queue_ret_flag = CircularQueueUnsignedInt_PushBack(
5941 ALmixer_Channel_List[i].almixer_data->circular_buffer_queue,
5942 unqueued_buffer_id
5943 );
5944 if(0 == queue_ret_flag)
5945 {
5946 fprintf(stderr, "56bSerious internal error: CircularQueue could not push into queue.\n");
5947 ALmixer_SetError("Serious internal error: CircularQueue failed to push into queue");
5948 }
5949 #if 0
5950 else
5951 {
5952 CircularQueueUnsignedInt_Print(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue);
5953 }
5954 #endif
5955 }
5956 }
5957 /* If we used an available buffer queue,
5958 * then we need to update the number of them in use
5959 */
5960 if(ALmixer_Channel_List[i].almixer_data->num_buffers_in_use
5961 < ALmixer_Channel_List[i].almixer_data->max_queue_buffers)
5962 {
5963 /* Increment the number of buffers in use */
5964 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use++;
5965 }
5966 /* Might want to check state */
5967 /* In case the playback stopped,
5968 * we need to resume */
5969 #if 1
5970 /* Try not refetching the state here because I'm getting a duplicate
5971 buffer playback (hiccup) */
5972 alGetSourcei(
5973 ALmixer_Channel_List[i].alsource,
5974 AL_SOURCE_STATE, &state
5975 );
5976 if((error = alGetError()) != AL_NO_ERROR)
5977 {
5978 fprintf(stderr, "57bTesting error: %s\n",
5979 alGetString(error));
5980 }
5981 /* Get the number of buffers processed
5982 */
5983 alGetSourcei(
5984 ALmixer_Channel_List[i].alsource,
5985 AL_BUFFERS_PROCESSED,
5986 &buffers_processed
5987 );
5988 if((error = alGetError()) != AL_NO_ERROR)
5989 {
5990 fprintf(stderr, "57cError, Can't get buffers_processed: %s\n",
5991 alGetString(error));
5992 }
5993 #endif
5994 if(AL_STOPPED == state)
5995 {
5996 /*
5997 fprintf(stderr, "Resuming in not eof\n");
5998 */
5999 /* Okay, here's another lately discovered problem:
6000 * I can't find it in the spec, but for at least some of the
6001 * implementations, if I call play on a stopped source that
6002 * has processed buffers, all those buffers get marked as unprocessed
6003 * on alSourcePlay. So if I had a queue of 25 with 24 of the buffers
6004 * processed, on resume, the earlier 24 buffers will get replayed,
6005 * causing a "hiccup" like sound in the playback.
6006 * To avoid this, I must unqueue all processed buffers before
6007 * calling play. But to complicate things, I need to worry about resyncing
6008 * the circular queue with this since I designed this thing
6009 * with some correlation between the two. However, I might
6010 * have already handled this, so I will try writing this code without
6011 * syncing for now.
6012 * There is currently an assumption that a buffer
6013 * was queued above so I actually have something
6014 * to play.
6015 */
6016 ALint temp_count;
6017 /*
6018 fprintf(stderr, "STOPPED2, need to clear processed, status is:\n");
6019 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
6020 */
6021
6022 for(temp_count=0; temp_count<buffers_processed; temp_count++)
6023 {
6024 alSourceUnqueueBuffers(
6025 ALmixer_Channel_List[i].alsource,
6026 1, &unqueued_buffer_id
6027 );
6028 if((error = alGetError()) != AL_NO_ERROR)
6029 {
6030 fprintf(stderr, "58aTesting error: %s\n",
6031 alGetString(error));
6032 error_flag--;
6033 }
6034 }
6035 /*
6036 fprintf(stderr, "After unqueue clear...:\n");
6037 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
6038 */
6039
6040 alSourcePlay(ALmixer_Channel_List[i].alsource);
6041 if((error = alGetError()) != AL_NO_ERROR) 6135 if((error = alGetError()) != AL_NO_ERROR)
6042 { 6136 {
6043 fprintf(stderr, "55Tbesting 8rror: %s\n", 6137 fprintf(stderr, "5200Testing error: %s\n",
6044 alGetString(error));
6045 }
6046 }
6047 continue;
6048 } /* END if( ! eof) */
6049 /* We have hit EOF in the SDL_Sound sample and there
6050 * are no more loops. However, there may still be
6051 * buffers in the OpenAL queue which still need to
6052 * be played out. The following body of code will
6053 * determine if play is still happening or
6054 * initiate the stop/cleanup sequenece.
6055 */
6056 else
6057 {
6058 /* Let's continue to remove the used up
6059 * buffers as they come in. */
6060 if(buffers_processed > 0)
6061 {
6062 ALint temp_count;
6063 /* Do as a for-loop because I don't want
6064 * to have to create an array for the
6065 * unqueued_buffer_id's
6066 */
6067 for(temp_count=0; temp_count<buffers_processed; temp_count++)
6068 {
6069 /*
6070 fprintf(stderr, "unqueuing remainder, %d\n", temp_count);
6071 */
6072 alSourceUnqueueBuffers(
6073 ALmixer_Channel_List[i].alsource,
6074 1, &unqueued_buffer_id
6075 );
6076 if((error = alGetError()) != AL_NO_ERROR)
6077 {
6078 fprintf(stderr, "59Testing error: %s\n",
6079 alGetString(error)); 6138 alGetString(error));
6080 } 6139 }
6081 } 6140 }
6082 /* 6141
6083 fprintf(stderr, "done unqueuing remainder for this loop, %d\n", temp_count); 6142
6084 */ 6143 /* Else if buffers_processed == 0
6085 6144 * and buffers_still_queued == 0.
6086 /* Need to update counts since we removed everything. 6145 * then we check to see if the source
6087 * If we don't update the counts here, we end up in the 6146 * is still playing. Quit if stopped
6088 * "Shouldn't be here section, but maybe it's okay due to race conditions" 6147 * We shouldn't need to worry about
6148 * looping because that should have
6149 * been handled above.
6089 */ 6150 */
6090 alGetSourcei( 6151 if(0 == buffers_still_queued)
6091 ALmixer_Channel_List[i].alsource,
6092 AL_BUFFERS_QUEUED, &buffers_still_queued
6093 );
6094 if((error = alGetError()) != AL_NO_ERROR)
6095 { 6152 {
6096 fprintf(stderr, "5100Testing error: %s\n", 6153 /* Make sure playback has stopped before
6097 alGetString(error)); 6154 * we shutdown.
6098 } 6155 */
6099 /* Get the number of buffers processed 6156 alGetSourcei(
6100 * so we know if we need to refill 6157 ALmixer_Channel_List[i].alsource,
6101 */ 6158 AL_SOURCE_STATE, &state
6102 alGetSourcei( 6159 );
6103 ALmixer_Channel_List[i].alsource, 6160 if((error = alGetError()) != AL_NO_ERROR)
6104 AL_BUFFERS_PROCESSED, &buffers_processed 6161 {
6105 ); 6162 fprintf(stderr, "60Testing error: %s\n",
6106 if((error = alGetError()) != AL_NO_ERROR) 6163 alGetString(error));
6164 }
6165 if(AL_STOPPED == state)
6166 {
6167 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use = 0;
6168 /* Playback has ended.
6169 * Loop if necessary, or launch callback
6170 * and clear channel (or clear channel and
6171 * then launch callback?)
6172 * Update: Need to do callback first because I reference the mixer_data and source
6173 */
6174
6175 /* Launch callback */
6176 Invoke_Channel_Done_Callback(i, AL_TRUE);
6177
6178 Clean_Channel(i);
6179 /* Subtract counter */
6180 Is_Playing_global--;
6181
6182
6183 /* We're done for this loop.
6184 * Go to next channel
6185 */
6186
6187 /* I used to call continue here, but continue isn't safe anymore because we are in the number_of_queue_buffers_per_pass loop now.
6188 * We should break, but we need to be careful that there is no code that is run once we break that wasn't run before.
6189 * We want to make sure we go immediately to the next iteration in the channel loop.
6190 */
6191 break;
6192 }
6193 } /* End end-playback */
6194 else
6107 { 6195 {
6108 fprintf(stderr, "5200Testing error: %s\n", 6196 /* Need to run out buffer */
6109 alGetString(error)); 6197 #if 1
6110 } 6198 /* Might want to check state */
6111 } 6199 /* In case the playback stopped,
6112 6200 * we need to resume */
6113 6201 alGetSourcei(
6114 /* Else if buffers_processed == 0 6202 ALmixer_Channel_List[i].alsource,
6115 * and buffers_still_queued == 0. 6203 AL_SOURCE_STATE, &state
6116 * then we check to see if the source 6204 );
6117 * is still playing. Quit if stopped 6205 if((error = alGetError()) != AL_NO_ERROR)
6118 * We shouldn't need to worry about 6206 {
6119 * looping because that should have 6207 fprintf(stderr, "61Testing error: %s\n",
6120 * been handled above. 6208 alGetString(error));
6121 */ 6209 }
6122 if(0 == buffers_still_queued) 6210 if(AL_STOPPED == state)
6123 { 6211 {
6124 /* Make sure playback has stopped before 6212 /*
6125 * we shutdown. 6213 fprintf(stderr, "Shouldn't be here. %d Buffers still in queue, but play stopped. This might be correct though because race conditions could have caused the STOP to happen right after our other tests...Checking queue status...\n", buffers_still_queued);
6126 */ 6214 */
6127 alGetSourcei( 6215 /*
6128 ALmixer_Channel_List[i].alsource, 6216 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
6129 AL_SOURCE_STATE, &state 6217 */
6130 ); 6218 /* Rather than force unqueuing the buffer, let's see if
6131 if((error = alGetError()) != AL_NO_ERROR) 6219 * setting the buffer to none works (the OpenAL 1.0
6132 { 6220 * Reference Annotation suggests this should work).
6133 fprintf(stderr, "60Testing error: %s\n", 6221 */
6134 alGetString(error)); 6222 alSourcei(ALmixer_Channel_List[i].alsource,
6135 } 6223 AL_BUFFER, AL_NONE);
6136 if(AL_STOPPED == state) 6224 /*
6137 { 6225 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
6138 ALmixer_Channel_List[i].almixer_data->num_buffers_in_use = 0; 6226 */
6139 /* Playback has ended. 6227 /* This doesn't work because in some cases, I think
6140 * Loop if necessary, or launch callback 6228 * it causes the sound to be replayed
6141 * and clear channel (or clear channel and 6229 */
6142 * then launch callback?) 6230 /*
6143 * Update: Need to do callback first because I reference the mixer_data and source 6231 fprintf(stderr, "Resuming in eof (trying to run out buffers\n");
6144 */ 6232 alSourcePlay(ALmixer_Channel_List[i].alsource);
6145 6233 */
6146 /* Launch callback */ 6234 }
6147 Invoke_Channel_Done_Callback(i, AL_TRUE); 6235 #endif
6148 6236 } /* End trap section */
6149 Clean_Channel(i); 6237 } /* End POST-EOF use-up buffer section */
6150 /* Subtract counter */ 6238
6151 Is_Playing_global--; 6239 } /* END NEW number of queue buffers per pass */
6152
6153
6154 /* We're done for this loop.
6155 * Go to next channel
6156 */
6157 continue;
6158 }
6159 } /* End end-playback */
6160 else
6161 {
6162 /* Need to run out buffer */
6163 #if 1
6164 /* Might want to check state */
6165 /* In case the playback stopped,
6166 * we need to resume */
6167 alGetSourcei(
6168 ALmixer_Channel_List[i].alsource,
6169 AL_SOURCE_STATE, &state
6170 );
6171 if((error = alGetError()) != AL_NO_ERROR)
6172 {
6173 fprintf(stderr, "61Testing error: %s\n",
6174 alGetString(error));
6175 }
6176 if(AL_STOPPED == state)
6177 {
6178 /*
6179 fprintf(stderr, "Shouldn't be here. %d Buffers still in queue, but play stopped. This might be correct though because race conditions could have caused the STOP to happen right after our other tests...Checking queue status...\n", buffers_still_queued);
6180 */
6181 /*
6182 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
6183 */
6184 /* Rather than force unqueuing the buffer, let's see if
6185 * setting the buffer to none works (the OpenAL 1.0
6186 * Reference Annotation suggests this should work).
6187 */
6188 alSourcei(ALmixer_Channel_List[i].alsource,
6189 AL_BUFFER, AL_NONE);
6190 /*
6191 PrintQueueStatus(ALmixer_Channel_List[i].alsource);
6192 */
6193 /* This doesn't work because in some cases, I think
6194 * it causes the sound to be replayed
6195 */
6196 /*
6197 fprintf(stderr, "Resuming in eof (trying to run out buffers\n");
6198 alSourcePlay(ALmixer_Channel_List[i].alsource);
6199 */
6200 }
6201 #endif
6202 } /* End trap section */
6203 } /* End POST-EOF use-up buffer section */
6204
6205 } /* END NEW number of queue buffers per pass */
6206 6240
6207 } /* END Streamed section */ 6241 } /* END Streamed section */
6208 } /* END channel in use */ 6242 } /* END channel in use */
6209 } /* END for-loop for each channel */ 6243 } /* END for-loop for each channel */
6210 6244
7827 } 7861 }
7828 7862
7829 7863
7830 7864
7831 7865
7832 static ALmixer_Data* DoLoad(Sound_Sample* sample, ALuint buffersize, ALboolean decode_mode_is_predecoded, ALuint max_queue_buffers, ALuint num_startup_buffers, ALboolean access_data) 7866 static ALmixer_Data* DoLoad(Sound_Sample* sample, ALuint buffersize, ALboolean decode_mode_is_predecoded, ALuint max_queue_buffers, ALuint num_startup_buffers, ALuint suggested_number_of_buffers_to_queue_per_update_pass, ALuint access_data)
7833 { 7867 {
7834 ALuint bytes_decoded; 7868 ALuint bytes_decoded;
7835 ALmixer_Data* ret_data; 7869 ALmixer_Data* ret_data;
7836 ALenum error; 7870 ALenum error;
7837 7871
7880 { 7914 {
7881 num_startup_buffers = max_queue_buffers; 7915 num_startup_buffers = max_queue_buffers;
7882 } 7916 }
7883 ret_data->num_startup_buffers = num_startup_buffers; 7917 ret_data->num_startup_buffers = num_startup_buffers;
7884 7918
7885 /* TODO: Expose value through public API */ 7919 /* Set up the update pass buffers */
7886 ret_data->num_target_buffers_per_pass = 1; 7920 if(0 == suggested_number_of_buffers_to_queue_per_update_pass)
7921 {
7922 suggested_number_of_buffers_to_queue_per_update_pass = ALMIXER_DEFAULT_BUFFERS_TO_QUEUE_PER_UPDATE_PASS;
7923 }
7924 /* Make sure update pass up buffers is less or equal to max_queue_buffers */
7925 if(suggested_number_of_buffers_to_queue_per_update_pass > max_queue_buffers)
7926 {
7927 suggested_number_of_buffers_to_queue_per_update_pass = max_queue_buffers;
7928 }
7929 ret_data->num_target_buffers_per_pass = suggested_number_of_buffers_to_queue_per_update_pass;
7887 7930
7888 ret_data->buffer_map_list = NULL; 7931 ret_data->buffer_map_list = NULL;
7889 ret_data->current_buffer = 0; 7932 ret_data->current_buffer = 0;
7890 7933
7891 ret_data->circular_buffer_queue = NULL; 7934 ret_data->circular_buffer_queue = NULL;
8375 * I don't like the AudioInfo parameter. I removed it once, 8418 * I don't like the AudioInfo parameter. I removed it once,
8376 * but the system will fail on RAW samples because the user 8419 * but the system will fail on RAW samples because the user
8377 * must specify it, so I had to bring it back. 8420 * must specify it, so I had to bring it back.
8378 * Remember I must close the rwops if there is an error before NewSample() 8421 * Remember I must close the rwops if there is an error before NewSample()
8379 */ 8422 */
8380 ALmixer_Data* ALmixer_LoadSample_RW(ALmixer_RWops* rwops, const char* fileext, ALuint buffersize, ALboolean decode_mode_is_predecoded, ALuint max_queue_buffers, ALuint num_startup_buffers, ALboolean access_data) 8423 ALmixer_Data* ALmixer_LoadSample_RW(ALmixer_RWops* rwops, const char* fileext, ALuint buffersize, ALboolean decode_mode_is_predecoded, ALuint max_queue_buffers, ALuint num_startup_buffers, ALuint suggested_number_of_buffers_to_queue_per_update_pass, ALuint access_data)
8381 { 8424 {
8382 Sound_Sample* sample = NULL; 8425 Sound_Sample* sample = NULL;
8383 Sound_AudioInfo target; 8426 Sound_AudioInfo target;
8384 8427
8385 if( (AL_FALSE == ALmixer_Initialized) || (AL_TRUE == g_inInterruption) ) 8428 if( (AL_FALSE == ALmixer_Initialized) || (AL_TRUE == g_inInterruption) )
8416 { 8459 {
8417 ALmixer_SetError(Sound_GetError()); 8460 ALmixer_SetError(Sound_GetError());
8418 return NULL; 8461 return NULL;
8419 } 8462 }
8420 8463
8421 return( DoLoad(sample, buffersize, decode_mode_is_predecoded, max_queue_buffers, num_startup_buffers, access_data)); 8464 return( DoLoad(sample, buffersize, decode_mode_is_predecoded, max_queue_buffers, num_startup_buffers, suggested_number_of_buffers_to_queue_per_update_pass, access_data));
8422 } 8465 }
8423 8466
8424 8467
8425 8468
8426 /* This will load a sample for us from 8469 /* This will load a sample for us from
8427 * a file (instead of RWops). Most of the uglyness is 8470 * a file (instead of RWops). Most of the uglyness is
8428 * error checking and the fact that streamed/predecoded files 8471 * error checking and the fact that streamed/predecoded files
8429 * must be treated differently. 8472 * must be treated differently.
8430 */ 8473 */
8431 ALmixer_Data* ALmixer_LoadSample(const char* filename, ALuint buffersize, ALboolean decode_mode_is_predecoded, ALuint max_queue_buffers, ALuint num_startup_buffers, ALboolean access_data) 8474 ALmixer_Data* ALmixer_LoadSample(const char* filename, ALuint buffersize, ALboolean decode_mode_is_predecoded, ALuint max_queue_buffers, ALuint num_startup_buffers, ALuint suggested_number_of_buffers_to_queue_per_update_pass, ALuint access_data)
8432 { 8475 {
8433 Sound_Sample* sample = NULL; 8476 Sound_Sample* sample = NULL;
8434 Sound_AudioInfo target; 8477 Sound_AudioInfo target;
8435 8478
8436 if( (AL_FALSE == ALmixer_Initialized) || (AL_TRUE == g_inInterruption) ) 8479 if( (AL_FALSE == ALmixer_Initialized) || (AL_TRUE == g_inInterruption) )
8526 } 8569 }
8527 8570
8528 /* 8571 /*
8529 fprintf(stderr, "Correction test: Actual rate=%d, desired=%d, actual format=%d, desired format=%d\n", sample->actual.rate, sample->desired.rate, sample->actual.format, sample->desired.format); 8572 fprintf(stderr, "Correction test: Actual rate=%d, desired=%d, actual format=%d, desired format=%d\n", sample->actual.rate, sample->desired.rate, sample->actual.format, sample->desired.format);
8530 */ 8573 */
8531 return( DoLoad(sample, buffersize, decode_mode_is_predecoded, max_queue_buffers, num_startup_buffers, access_data)); 8574 return( DoLoad(sample, buffersize, decode_mode_is_predecoded, max_queue_buffers, num_startup_buffers, suggested_number_of_buffers_to_queue_per_update_pass, access_data));
8532 } 8575 }
8533 8576
8534 8577
8535 /* This is a back door for RAW samples or if you need the 8578 /* This is a back door for RAW samples or if you need the
8536 * AudioInfo field. Use at your own risk. 8579 * AudioInfo field. Use at your own risk.
8537 */ 8580 */
8538 ALmixer_Data* ALmixer_LoadSample_RAW_RW(ALmixer_RWops* rwops, const char* fileext, ALmixer_AudioInfo* desired, ALuint buffersize, ALboolean decode_mode_is_predecoded, ALuint max_queue_buffers, ALuint num_startup_buffers, ALboolean access_data) 8581 ALmixer_Data* ALmixer_LoadSample_RAW_RW(ALmixer_RWops* rwops, const char* fileext, ALmixer_AudioInfo* desired, ALuint buffersize, ALboolean decode_mode_is_predecoded, ALuint max_queue_buffers, ALuint num_startup_buffers, ALuint suggested_number_of_buffers_to_queue_per_update_pass, ALuint access_data)
8539 { 8582 {
8540 Sound_Sample* sample = NULL; 8583 Sound_Sample* sample = NULL;
8541 Sound_AudioInfo sound_desired; 8584 Sound_AudioInfo sound_desired;
8542 8585
8543 if( (AL_FALSE == ALmixer_Initialized) || (AL_TRUE == g_inInterruption) ) 8586 if( (AL_FALSE == ALmixer_Initialized) || (AL_TRUE == g_inInterruption) )
8566 if(NULL == sample) 8609 if(NULL == sample)
8567 { 8610 {
8568 ALmixer_SetError(Sound_GetError()); 8611 ALmixer_SetError(Sound_GetError());
8569 return NULL; 8612 return NULL;
8570 } 8613 }
8571 return( DoLoad(sample, buffersize, decode_mode_is_predecoded, max_queue_buffers, num_startup_buffers, access_data)); 8614 return( DoLoad(sample, buffersize, decode_mode_is_predecoded, max_queue_buffers, num_startup_buffers,suggested_number_of_buffers_to_queue_per_update_pass, access_data));
8572 } 8615 }
8573 8616
8574 8617
8575 8618
8576 8619
8577 /* This is a back door for RAW samples or if you need the 8620 /* This is a back door for RAW samples or if you need the
8578 * AudioInfo field. Use at your own risk. 8621 * AudioInfo field. Use at your own risk.
8579 */ 8622 */
8580 ALmixer_Data* ALmixer_LoadSample_RAW(const char* filename, ALmixer_AudioInfo* desired, ALuint buffersize, ALboolean decode_mode_is_predecoded, ALuint max_queue_buffers, ALuint num_startup_buffers, ALboolean access_data) 8623 ALmixer_Data* ALmixer_LoadSample_RAW(const char* filename, ALmixer_AudioInfo* desired, ALuint buffersize, ALboolean decode_mode_is_predecoded, ALuint max_queue_buffers, ALuint num_startup_buffers, ALuint suggested_number_of_buffers_to_queue_per_update_pass, ALuint access_data)
8581 { 8624 {
8582 Sound_Sample* sample = NULL; 8625 Sound_Sample* sample = NULL;
8583 Sound_AudioInfo sound_desired; 8626 Sound_AudioInfo sound_desired;
8584 8627
8585 if( (AL_FALSE == ALmixer_Initialized) || (AL_TRUE == g_inInterruption) ) 8628 if( (AL_FALSE == ALmixer_Initialized) || (AL_TRUE == g_inInterruption) )
8609 if(NULL == sample) 8652 if(NULL == sample)
8610 { 8653 {
8611 ALmixer_SetError(Sound_GetError()); 8654 ALmixer_SetError(Sound_GetError());
8612 return NULL; 8655 return NULL;
8613 } 8656 }
8614 return( DoLoad(sample, buffersize, decode_mode_is_predecoded, max_queue_buffers, num_startup_buffers, access_data)); 8657 return( DoLoad(sample, buffersize, decode_mode_is_predecoded, max_queue_buffers, num_startup_buffers, suggested_number_of_buffers_to_queue_per_update_pass, access_data));
8615 } 8658 }
8616 8659
8617 8660
8618 void ALmixer_FreeData(ALmixer_Data* data) 8661 void ALmixer_FreeData(ALmixer_Data* data)
8619 { 8662 {