Problem with alSourceUnqueueBuffers

View: New views
10 Messages — Rating Filter:   Alert me  

Problem with alSourceUnqueueBuffers

by qartar :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I am trying to implement a streaming sound engine with OpenAL by uploading small blocks of sound data into buffers as needed instead of the entire sound at once. Doing this requires a lot of buffers queued onto one source so I tried to reuse processed buffers when available instead of creating a new buffer for each block of data. The update loop looks something like this...

alGetSourceiv( source, AL_BUFFERS_PROCESSED, &count );

if ( count ) {
        alSourceUnqueueBuffers( source, 1, &buffer );
} else {
        alGenBuffers( 1, &buffer );
}

alBufferData( buffer, ... );
alSourceQueueBuffers( source, 1, buffer );

It seems that whenever I use alSourceUnqueueBuffers the source is stopped or otherwise no longer plays the data queued. This causes any sounds longer than the initial few buffers (about two tenths of a second worth) to stop or fail to play entirely. Even if not using the buffer from alSourceUnqueueBuffers  or calling alSourcePlay afterwards the problem persists. No errors are being generated. This problem can be circumvented by not calling alSourceUnqueueBuffers and generating new buffers for each sound segment.

The questions I have are, is there a significant performance gain from uploading one buffer per source as opposed to uploading segments at a time? Is there some functionality of alSourceUnqueueBuffers that I am missing which is causing this problem?

Re: Problem with alSourceUnqueueBuffers

by Luis-33 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi qartar. First of all, how big are your buffers? They might be too small. Also, from what I see, you are only unqueuing a single buffer per iteration, even if count is indicating more than one buffer processed. You should unqueue and refill every processed buffer in each loop iteration, else your source is going to run out of audio data quickly. Hope that helps :)
By the way, is there any reason not to be using buffers in a circular way?

Cheers!

On Wed, Jun 3, 2009 at 6:36 AM, qartar <qartar@...> wrote:

I am trying to implement a streaming sound engine with OpenAL by uploading
small blocks of sound data into buffers as needed instead of the entire
sound at once. Doing this requires a lot of buffers queued onto one source
so I tried to reuse processed buffers when available instead of creating a
new buffer for each block of data. The update loop looks something like
this...

alGetSourceiv( source, AL_BUFFERS_PROCESSED, &count );

if ( count ) {
       alSourceUnqueueBuffers( source, 1, &buffer );
} else {
       alGenBuffers( 1, &buffer );
}

alBufferData( buffer, ... );
alSourceQueueBuffers( source, 1, buffer );

It seems that whenever I use alSourceUnqueueBuffers the source is stopped or
otherwise no longer plays the data queued. This causes any sounds longer
than the initial few buffers (about two tenths of a second worth) to stop or
fail to play entirely. Even if not using the buffer from
alSourceUnqueueBuffers  or calling alSourcePlay afterwards the problem
persists. No errors are being generated. This problem can be circumvented by
not calling alSourceUnqueueBuffers and generating new buffers for each sound
segment.

The questions I have are, is there a significant performance gain from
uploading one buffer per source as opposed to uploading segments at a time?
Is there some functionality of alSourceUnqueueBuffers that I am missing
which is causing this problem?
--
View this message in context: http://www.nabble.com/Problem-with-alSourceUnqueueBuffers-tp23845230p23845230.html
Sent from the OpenAL - User mailing list archive at Nabble.com.

_______________________________________________
Openal mailing list
Openal@...
http://opensource.creative.com/mailman/listinfo/openal



--
Luis

_______________________________________________
Openal mailing list
Openal@...
http://opensource.creative.com/mailman/listinfo/openal

Re: Problem with alSourceUnqueueBuffers

by qartar :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Luis-33 wrote:
Hi qartar. First of all, how big are your buffers? They might be too small.
Also, from what I see, you are only unqueuing a single buffer per iteration,
even if count is indicating more than one buffer processed. You should
unqueue and refill every processed buffer in each loop iteration, else your
source is going to run out of audio data quickly. Hope that helps :)
By the way, is there any reason not to be using buffers in a circular way?

Cheers!
Thank you for your reply. The buffers are fairly small since they are updated around 60 hz, so approximately 360ish samples per iteration, but I never saw any documentation referring to minimum buffer sizes so I am a little confused. (It may be worth to mention again that no errors are being generated). The function determines how many samples to fill per iteration by checking the current source sample offset against a mixahead value so even if there are extra processed buffers the source does not underrun. As far as circular buffers go, since I haven't seen a way to update a buffer while it is playing (a la DirectSound) I thought this would be close. If you have better solution I would be very interested.

Re: Problem with alSourceUnqueueBuffers

by Daniel PEACOCK :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message





360 samples is very small for a Buffer, especially if you are playing at
44.1KHz, as that means the Buffers are only about 8 milliseconds in
duration.   Even if your application is updating the Buffers at 60Hz, the
OpenAL implementation is quite likely to be performing mixing in a separate
thread that is called less often (more likely 25 times per second).   So
this would definitely create a scenario where Buffers Processed returns 0
for a while, and then suddenly returns 2 or 3.   That might be OK - as long
as you have more than 3 Buffers in the queue, and that you immediately
unqueue, fill, and requeue all of the buffers (otherwise you will starve
the Source of audio data).

The Creative Windows OpenAL SDK includes some example code for streaming
that might be worth looking at.

In general, you will have to have a reasonable amount of data in the
Source's Buffer Queue (e.g. at least 100ms if this application is intended
to run on many OpenAL implementations on many PCs).  This should be split
into multiple Buffers (e.g 4 Buffers of 25ms each).   When ever you request
the numbers of Buffers processed, you should unqueue all of them and
requeue them with new audio data.   You should also include code that
checks that the Source is still playing, and if not, include logic to start
it playing again.

Dan
Creative Labs (UK) Ltd.

Notice
The information in this message is confidential and may be legally
privileged.  It is intended solely for the addressee.  Access to this
message by anyone else is unauthorized.  If you are not the intended
recipient,  any disclosure,  copying or distribution of the message,  or
any action taken by you in reliance on it,  is prohibited and may be
unlawful.  If you have received this message in error,  please delete it
and contact the sender immediately.  Thank you.

Creative Labs UK Ltd company number 2658256 registered in England and Wales
at Belmont Road, Belmont Place, Maidenhead, Berkshire, SL6 6TB



                                                                           
             qartar                                                        
             <qartar@...>                                            
             Sent by:                                                   To
             openal-bounces@op         openal@...      
             ensource.creative                                          cc
             .com                                                          
                                                                   Subject
                                       Re: [Openal] Problem with          
             06/03/2009 10:32          alSourceUnqueueBuffers              
             AM                                                            
                                                                           
                                                                           
                                                                           
                                                                           
                                                                           






Luis-33 wrote:

>
> Hi qartar. First of all, how big are your buffers? They might be too
> small.
> Also, from what I see, you are only unqueuing a single buffer per
> iteration,
> even if count is indicating more than one buffer processed. You should
> unqueue and refill every processed buffer in each loop iteration, else
> your
> source is going to run out of audio data quickly. Hope that helps :)
> By the way, is there any reason not to be using buffers in a circular
way?
>
> Cheers!
>

Thank you for your reply. The buffers are fairly small since they are
updated around 60 hz, so approximately 360ish samples per iteration, but I
never saw any documentation referring to minimum buffer sizes so I am a
little confused. (It may be worth to mention again that no errors are being
generated). The function determines how many samples to fill per iteration
by checking the current source sample offset against a mixahead value so
even if there are extra processed buffers the source does not underrun. As
far as circular buffers go, since I haven't seen a way to update a buffer
while it is playing (a la DirectSound) I thought this would be close. If
you
have better solution I would be very interested.
--
View this message in context:
http://www.nabble.com/Problem-with-alSourceUnqueueBuffers-tp23845230p23848351.html

Sent from the OpenAL - User mailing list archive at Nabble.com.

_______________________________________________
Openal mailing list
Openal@...
http://opensource.creative.com/mailman/listinfo/openal

ForwardSourceID:NT0006CABE

_______________________________________________
Openal mailing list
Openal@...
http://opensource.creative.com/mailman/listinfo/openal

Re: Problem with alSourceUnqueueBuffers

by Garin Hiebert :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

> You should also include code that
> checks that the Source is still playing, and if not, include logic  
> to start
> it playing again.

This is why there are no errors returned, by the way.  As far as  
OpenAL is concerned, everything is fine.  It runs out of data and then  
stops the source just like it should.  No error.   ;-)

In summary, make two changes:

1)  The implementation should be changed such that it has 100ms or so  
of data available in multiple buffers (four or so seems "reasonable,"  
but as few as two _should_ work).

2)  Detect an "under-run" by looking for streams which have stopped  
sources.  When detected, buffer up a full set of buffers for that  
source and do a Play on that source.  In most products, this should be  
a very rare occurrence, but may still happen during long disk access  
or some other operation which stalls the engine for a while.

Garin


_______________________________________________
Openal mailing list
Openal@...
http://opensource.creative.com/mailman/listinfo/openal

Re: Problem with alSourceUnqueueBuffers

by qartar :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


Garin Hiebert wrote:
> You should also include code that
> checks that the Source is still playing, and if not, include logic  
> to start
> it playing again.

This is why there are no errors returned, by the way.  As far as  
OpenAL is concerned, everything is fine.  It runs out of data and then  
stops the source just like it should.  No error.   ;-)

In summary, make two changes:

1)  The implementation should be changed such that it has 100ms or so  
of data available in multiple buffers (four or so seems "reasonable,"  
but as few as two _should_ work).

2)  Detect an "under-run" by looking for streams which have stopped  
sources.  When detected, buffer up a full set of buffers for that  
source and do a Play on that source.  In most products, this should be  
a very rare occurrence, but may still happen during long disk access  
or some other operation which stalls the engine for a while.

Garin
Thank you again for your replies. You seem to be focusing on buffer underrun issues. I went back to my code and added a check to be sure and it does not seem to be the issue. When a sound is played the engine determines how many samples ahead of the source it should be uploading, usually 100 milliseconds, and uploads that many samples, so on the first iteration 2205 samples are uploaded for a 22050 hz sound file, and then subsequent iterations are performed at approximately 60 hz. This works when not unqueueing buffers, but as soon as I unqueue a buffer, regardless of whether I delete or reuse that buffer, the sound stops playing.

Re: Problem with alSourceUnqueueBuffers

by Daniel PEACOCK :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message





> Thank you again for your replies. You seem to be focusing on buffer
underrun
> issues. I went back to my code and added a check to be sure and it does
not
> seem to be the issue. When a sound is played the engine determines how
many
> samples ahead of the source it should be uploading, usually 100
> milliseconds, and uploads that many samples, so on the first iteration
2205
> samples are uploaded for a 22050 hz sound file, and then subsequent
> iterations are performed at approximately 60 hz.

What OpenAL device are you using, and which OS and soundcard?

Buffer underrun is the most likely problem I think.  In your testing are
you able to confirm that Buffers Processed never returns the same number of
Buffers that are actually queued on the Source at the moment?

For the first iteration how many Buffers are you filling with the 2205
samples?

Are you using get playback offset to determine how many samples to fill?
I would recommend using a fixed buffer size for the streaming operations
rather than trying to compute how many samples have been played.   The get
sample offset call is tricky to use because it returns an offset from the
start of the buffer queue - not the offset in the current buffer.   So, I
would use, say 4 x 25ms buffers and as and when a buffer is processed,
unqueue it, fill it with 25ms of audio data, and requeue it.

> This works when not
> unqueueing buffers, but as soon as I unqueue a buffer, regardless of
whether
> I delete or reuse that buffer, the sound stops playing.

So if you keep generating, filling, and requeueing new Buffers the Source
keeps playing without any problems?  Does it play without glitches?  Some
implementations of OpenAL enable a starved Source to automagically restart
playing if the application never actually queries the playback state and
just queues new buffers on it.

Dan

_______________________________________________
Openal mailing list
Openal@...
http://opensource.creative.com/mailman/listinfo/openal

Re: Problem with alSourceUnqueueBuffers

by qartar :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Daniel PEACOCK wrote:
What OpenAL device are you using, and which OS and soundcard?
OpenAL driver information...
Vendor   : Creative Labs Inc.
Renderer : Software
Version  : 1.1

Daniel PEACOCK wrote:
Buffer underrun is the most likely problem I think.  In your testing are
you able to confirm that Buffers Processed never returns the same number of
Buffers that are actually queued on the Source at the moment?
Yes, confirmed it just now.

Daniel PEACOCK wrote:
For the first iteration how many Buffers are you filling with the 2205
samples?
One buffer.

Daniel PEACOCK wrote:
Are you using get playback offset to determine how many samples to fill?
I would recommend using a fixed buffer size for the streaming operations
rather than trying to compute how many samples have been played.   The get
sample offset call is tricky to use because it returns an offset from the
start of the buffer queue - not the offset in the current buffer.   So, I
would use, say 4 x 25ms buffers and as and when a buffer is processed,
unqueue it, fill it with 25ms of audio data, and requeue it.
Yes, with alGetSourceiv( source, AL_SAMPLE_OFFSET, &samplePos ). If I recall correctly, the function returns the sample offset from the beginning of playback, which would include buffers processed, not just the buffers queued. Is there an issue with buffers if they are uploaded with different lengths of data?

Daniel PEACOCK wrote:
So if you keep generating, filling, and requeueing new Buffers the Source
keeps playing without any problems?  Does it play without glitches?  Some
implementations of OpenAL enable a starved Source to automagically restart
playing if the application never actually queries the playback state and
just queues new buffers on it.
Yes, if I generate new buffers every iteration instead of trying to reuse processed buffers the source plays with zero problems, this is why I don't think it is an underrun issue. On the other hand, I have put queries before and after the calls to unqueue and queue and it reports that the source is still playing.

Re: Problem with alSourceUnqueueBuffers

by Daniel PEACOCK :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message





Hi,

> > What OpenAL device are you using, and which OS and soundcard?
> >
>
> OpenAL driver information...
> Vendor   : Creative Labs Inc.
> Renderer : Software
> Version  : 1.1

Can you output the actual name of the device being used, e.g.

printf("Device is %s\n", alcGetString(deviceHandle, ALC_DEVICE_SPECIFIER));

>From the above information, it could be the "Generic Hardware" or "Generic
Software" device.  Also, what version of the wrap_oal.dll do you have?

> > For the first iteration how many Buffers are you filling with the 2205
> > samples?
> >
>
> One buffer.
>
> > Are you using get playback offset to determine how many samples to
fill?
> > I would recommend using a fixed buffer size for the streaming
operations
> > rather than trying to compute how many samples have been played.   The
get
> > sample offset call is tricky to use because it returns an offset from
the
> > start of the buffer queue - not the offset in the current buffer.   So,
I
> > would use, say 4 x 25ms buffers and as and when a buffer is processed,
> > unqueue it, fill it with 25ms of audio data, and requeue it.
> >
>
> Yes, with alGetSourceiv( source, AL_SAMPLE_OFFSET, &samplePos ).

I think there is a fundamental difference in your method of streaming to
what I have typically seen.   Your method is relying more on get Sample
Offset than getting Buffers Processed as a way of determining when and how
many samples to requeue on the Source.

In the "buffer processed" method, you would need to queue more than one
buffer on the first iteration (e.g split the 2205 samples into 4 Buffers).
Then completely remove the get sample offset calls and simply wait for a
buffer to marked as processed.  At which time, you unqueue it, and fill it
with the same number of samples, and requeue it.

> If I recall
> correctly, the function returns the sample offset from the beginning of
> playback, which would include buffers processed, not just the buffers
> queued.

It is the sample offset from the beginning of the *current* queue. e.g If
sample offset returns say, 2000 samples, and then you unqueue a (processed)
buffer containing 1000 samples, and immediately ask for the sample offset,
it will be 1000 samples.   Are you taking this into account?

> Is there an issue with buffers if they are uploaded with different
> lengths of data?

There shouldn't be any issues ... but it may cost some memory reallocation,
that could otherwise be avoided by keeping the buffer the same size.

> > So if you keep generating, filling, and requeueing new Buffers the
Source
> > keeps playing without any problems?  Does it play without glitches?
Some
> > implementations of OpenAL enable a starved Source to automagically
restart
> > playing if the application never actually queries the playback state
and
> > just queues new buffers on it.
> >
>
> Yes, if I generate new buffers every iteration instead of trying to reuse
> processed buffers the source plays with zero problems, this is why I
don't
> think it is an underrun issue. On the other hand, I have put queries
before
> and after the calls to unqueue and queue and it reports that the source
is
> still playing.

So to be clear - the scenario that works is doing something like this ...

60 times per second ...

Get current Sample Offset
Compute samples played since last iteration
Gen a new buffer and fill it with that number of samples
Queue it on Source

Or are actually doing an unqueue operation and just ignoring the buffer
returned?

If you are not unqueuing then the sample offset returned each iteration
will always be greater or equal to the value you got on the previous
iteration.  As soon as you unqueue a buffer in an iteration, the next
iteration could see a lower sample offset value (quite likely given the 60
Hz update rate), which will cause issues as you won't queue any new data
for a longer period of time.

Dan
Creative Labs, UK



> --
> View this message in context: http://www.nabble.com/Problem-with-
> alSourceUnqueueBuffers-tp23845230p23856804.html
> Sent from the OpenAL - User mailing list archive at Nabble.com.
>
> _______________________________________________
> Openal mailing list
> Openal@...
> http://opensource.creative.com/mailman/listinfo/openal

> ForwardSourceID:NT0006CB12

_______________________________________________
Openal mailing list
Openal@...
http://opensource.creative.com/mailman/listinfo/openal

Re: Problem with alSourceUnqueueBuffers

by qartar :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


Daniel PEACOCK wrote:
It is the sample offset from the beginning of the *current* queue. e.g If
sample offset returns say, 2000 samples, and then you unqueue a (processed)
buffer containing 1000 samples, and immediately ask for the sample offset,
it will be 1000 samples.   Are you taking this into account?
It looks like this was my problem. I've just now added the logic to my code and it seems to be working fine. Thanks for the help!