Discussion:
[Audiere-users] Audiere crash with OutputStreamPtr
Tim Conkling
2005-12-06 23:17:08 UTC
Permalink
Hello audiere-users,

I'm new to Audiere, and I'm having some problems using it in my
program. I'm developing with Visual Studio 2003 under Windows XP,
using the latest stable Audiere release from sourceforge (1.9.3). I'm
getting frequent crashes in an Audiere-spawned thread. I can't see the
call stack, but it's happening in ntdll.dll (by way of
audiere.dll->kernel32.dll->dsound.dll->ntdll.dll). Visual Studio is
reporting that there is an "Unhandled exception at [...]: An invalid
HANDLE was specified." (My application uses a single thread, except
for the threads that audiere spawns independently).

I've written a stress-test application that plays sounds as fast as
the machine will allow to see if I can narrow down the cause of this
issue, as it occurs unpredictably.

Simple fire-and-forget sound-playing logic works fine for me:

while(1)
{
const char* soundName = kSoundNames[Random::next(0,
ARRAYSIZE(kSoundNames))];
audiere::OutputStreamPtr osp = audiere::OpenSound(device, soundName);
if(NULL != osp.get ())
{
osp->play();
}
}

(Though this approach eventually brings the rest of running
applications to a halt as they all get paged out to disk).


The problem I'm having occurs when I use my SoundManager to play
sounds. The SoundManager has a simple and common design -- it
maintains an array of sounds being played, along with timestamps for
each playing sound, and ensures that the number of concurrently
playing sounds never exceeds a certain maximum by stopping the oldest
sound when this maximum is exceeded. This means that the OutputStreams
that are playing my sounds need to occasionally be stopped prematurely
to make room for new sounds -- and this seems to be what is causing my
problems.

When I need to stop an old sound from playing to make room for a new,
I do the following:

outputStreamPtr = NULL;

where outputStreamPtr is an OutputStreamPtr. I then reasign
outputStreamPtr to the value returned from audiere::OpenSound(). The
logic looks something like this:

if(sounds_playing == max)
{
OutputStreamPtr outputStreamPtr = findOldestSound();
outputStreamPtr = NULL;
outputStreamPtr = audiere::OpenSound(...)
outputStreamPtr->play();
}

The crash happens _much_ more quickly in the program's execution if I
stop() the outputStream before setting it to NULL. If I set all sounds
to repeat -- so that I can be guaranteed that they haven't finished
when I stop() them, my Invalid HANDLE exception becomes an "Access
violation" exception (still in ntdll.dll) when memory is either
illegally read or written.

Any suggestions as to why this might be happening? It seems to me to
be a thread-related race-condition. Are OutputStreams not meant to
touched once they are created? Should I not be reusing my
OutputStreamPtr for a new sound?

Thanks,
Tim
Tim Conkling
2005-12-07 01:27:00 UTC
Permalink
Post by Tim Conkling
I then reasign
outputStreamPtr to the value returned from audiere::OpenSound(). The
if(sounds_playing == max)
{
OutputStreamPtr outputStreamPtr = findOldestSound();
outputStreamPtr = NULL;
outputStreamPtr = audiere::OpenSound(...)
outputStreamPtr->play();
}
Whoops -- what I typed above is incorrect. I'm not creating a new
OutputStreamPtr (so there's not actually an extra ref()/unref()). In
fact, I never create new OutputStreamPtrs -- there's a single array of
them that I maintain. This would be more accurate pseudocode of what
I'm doing:

if(sounds_playing == max)
{
OutputStreamPtr& outputStreamPtr = findOldestSound();
outputStreamPtr = NULL; // unref old OSP
outputStreamPtr = audiere::OpenSound(...); // ref new OSP
outputStreamPtr->play();
}

I just want to make it clear that I don't have any extra refs() and
unrefs() that I'm not noticing in my code (just to make sure, I
changed my array of OutputStreamPtr's to an array of OutputStream*'s,
and manually ref() after OpenSound(...) and unref() right before
setting the ptr to NULL.

Everything else I wrote in my previous email was correct :)

Thanks,
Tim

Loading...