Fixed OpenAL bug when deleting the OpenAL buffers that caused the game to hang.

This commit is contained in:
Robert Beckebans 2013-01-06 13:03:56 +01:00
parent 699e0e39f5
commit 4884cc5793
7 changed files with 161 additions and 144 deletions

View file

@ -4,6 +4,7 @@
Doom 3 BFG Edition GPL Source Code Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2013 Robert Beckebans Copyright (C) 2013 Robert Beckebans
Copyright (c) 2010 by Chris Robinson <chris.kcat@gmail.com> (OpenAL Info Utility)
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -61,135 +62,98 @@ idSoundHardware_OpenAL::idSoundHardware_OpenAL()
lastResetTime = 0; lastResetTime = 0;
} }
void idSoundHardware_OpenAL::PrintDeviceList( const char* list )
{
if( !list || *list == '\0' )
{
idLib::Printf( " !!! none !!!\n" );
}
else
{
do
{
idLib::Printf( " %s\n", list );
list += strlen( list ) + 1;
}
while( *list != '\0' );
}
}
void idSoundHardware_OpenAL::PrintALCInfo( ALCdevice* device )
{
ALCint major, minor;
if( device )
{
const ALCchar* devname = NULL;
idLib::Printf( "\n" );
if( alcIsExtensionPresent( device, "ALC_ENUMERATE_ALL_EXT" ) != AL_FALSE )
{
devname = alcGetString( device, ALC_ALL_DEVICES_SPECIFIER );
}
if( CheckALCErrors( device ) != ALC_NO_ERROR || !devname )
{
devname = alcGetString( device, ALC_DEVICE_SPECIFIER );
}
idLib::Printf( "** Info for device \"%s\" **\n", devname );
}
alcGetIntegerv( device, ALC_MAJOR_VERSION, 1, &major );
alcGetIntegerv( device, ALC_MINOR_VERSION, 1, &minor );
if( CheckALCErrors( device ) == ALC_NO_ERROR )
idLib::Printf( "ALC version: %d.%d\n", major, minor );
if( device )
{
idLib::Printf( "OpenAL extensions: %s", alGetString( AL_EXTENSIONS ) );
//idLib::Printf("ALC extensions:");
//printList(alcGetString(device, ALC_EXTENSIONS), ' ');
CheckALCErrors( device );
}
}
void idSoundHardware_OpenAL::PrintALInfo()
{
idLib::Printf( "OpenAL vendor string: %s\n", alGetString( AL_VENDOR ) );
idLib::Printf( "OpenAL renderer string: %s\n", alGetString( AL_RENDERER ) );
idLib::Printf( "OpenAL version string: %s\n", alGetString( AL_VERSION ) );
idLib::Printf( "OpenAL extensions: %s", alGetString( AL_EXTENSIONS ) );
//PrintList(alGetString(AL_EXTENSIONS), ' ');
CheckALErrors();
}
void listDevices_f( const idCmdArgs& args ) void listDevices_f( const idCmdArgs& args )
{ {
#if 1 idLib::Printf( "Available playback devices:\n" );
// TODO if( alcIsExtensionPresent( NULL, "ALC_ENUMERATE_ALL_EXT" ) != AL_FALSE )
idLib::Warning( "No audio devices found" );
return;
#else
UINT32 deviceCount = 0;
if( pXAudio2->GetDeviceCount( &deviceCount ) != S_OK || deviceCount == 0 )
{ {
idLib::Warning( "No audio devices found" ); idSoundHardware_OpenAL::PrintDeviceList( alcGetString( NULL, ALC_ALL_DEVICES_SPECIFIER ) );
return; }
else
{
idSoundHardware_OpenAL::PrintDeviceList( alcGetString( NULL, ALC_DEVICE_SPECIFIER ) );
} }
for( unsigned int i = 0; i < deviceCount; i++ ) //idLib::Printf("Available capture devices:\n");
//printDeviceList(alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER));
if( alcIsExtensionPresent( NULL, "ALC_ENUMERATE_ALL_EXT" ) != AL_FALSE )
{ {
XAUDIO2_DEVICE_DETAILS deviceDetails; idLib::Printf( "Default playback device: %s\n", alcGetString( NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER ) );
if( pXAudio2->GetDeviceDetails( i, &deviceDetails ) != S_OK )
{
continue;
}
idStaticList< const char*, 5 > roles;
if( deviceDetails.Role & DefaultConsoleDevice )
{
roles.Append( "Console Device" );
}
if( deviceDetails.Role & DefaultMultimediaDevice )
{
roles.Append( "Multimedia Device" );
}
if( deviceDetails.Role & DefaultCommunicationsDevice )
{
roles.Append( "Communications Device" );
}
if( deviceDetails.Role & DefaultGameDevice )
{
roles.Append( "Game Device" );
}
idStaticList< const char*, 11 > channelNames;
if( deviceDetails.OutputFormat.dwChannelMask & SPEAKER_FRONT_LEFT )
{
channelNames.Append( "Front Left" );
}
if( deviceDetails.OutputFormat.dwChannelMask & SPEAKER_FRONT_RIGHT )
{
channelNames.Append( "Front Right" );
}
if( deviceDetails.OutputFormat.dwChannelMask & SPEAKER_FRONT_CENTER )
{
channelNames.Append( "Front Center" );
}
if( deviceDetails.OutputFormat.dwChannelMask & SPEAKER_LOW_FREQUENCY )
{
channelNames.Append( "Low Frequency" );
}
if( deviceDetails.OutputFormat.dwChannelMask & SPEAKER_BACK_LEFT )
{
channelNames.Append( "Back Left" );
}
if( deviceDetails.OutputFormat.dwChannelMask & SPEAKER_BACK_RIGHT )
{
channelNames.Append( "Back Right" );
}
if( deviceDetails.OutputFormat.dwChannelMask & SPEAKER_FRONT_LEFT_OF_CENTER )
{
channelNames.Append( "Front Left of Center" );
}
if( deviceDetails.OutputFormat.dwChannelMask & SPEAKER_FRONT_RIGHT_OF_CENTER )
{
channelNames.Append( "Front Right of Center" );
}
if( deviceDetails.OutputFormat.dwChannelMask & SPEAKER_BACK_CENTER )
{
channelNames.Append( "Back Center" );
}
if( deviceDetails.OutputFormat.dwChannelMask & SPEAKER_SIDE_LEFT )
{
channelNames.Append( "Side Left" );
}
if( deviceDetails.OutputFormat.dwChannelMask & SPEAKER_SIDE_RIGHT )
{
channelNames.Append( "Side Right" );
}
char mbcsDisplayName[ 256 ];
wcstombs( mbcsDisplayName, deviceDetails.DisplayName, sizeof( mbcsDisplayName ) );
idLib::Printf( "%3d: %s\n", i, mbcsDisplayName );
idLib::Printf( " %d channels, %d Hz\n", deviceDetails.OutputFormat.Format.nChannels, deviceDetails.OutputFormat.Format.nSamplesPerSec );
if( channelNames.Num() != deviceDetails.OutputFormat.Format.nChannels )
{
idLib::Printf( S_COLOR_YELLOW "WARNING: " S_COLOR_RED "Mismatch between # of channels and channel mask\n" );
}
if( channelNames.Num() == 1 )
{
idLib::Printf( " %s\n", channelNames[0] );
}
else if( channelNames.Num() == 2 )
{
idLib::Printf( " %s and %s\n", channelNames[0], channelNames[1] );
}
else if( channelNames.Num() > 2 )
{
idLib::Printf( " %s", channelNames[0] );
for( int i = 1; i < channelNames.Num() - 1; i++ )
{
idLib::Printf( ", %s", channelNames[i] );
}
idLib::Printf( ", and %s\n", channelNames[channelNames.Num() - 1] );
}
if( roles.Num() == 1 )
{
idLib::Printf( " Default %s\n", roles[0] );
}
else if( roles.Num() == 2 )
{
idLib::Printf( " Default %s and %s\n", roles[0], roles[1] );
}
else if( roles.Num() > 2 )
{
idLib::Printf( " Default %s", roles[0] );
for( int i = 1; i < roles.Num() - 1; i++ )
{
idLib::Printf( ", %s", roles[i] );
}
idLib::Printf( ", and %s\n", roles[roles.Num() - 1] );
}
} }
#endif else
// RB end {
idLib::Printf( "Default playback device: %s\n", alcGetString( NULL, ALC_DEFAULT_DEVICE_SPECIFIER ) );
}
//idLib::Printf("Default capture device: %s\n", alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER));
idSoundHardware_OpenAL::PrintALCInfo( NULL );
idSoundHardware_OpenAL::PrintALCInfo( ( ALCdevice* )soundSystem->GetOpenALDevice() );
} }
/* /*

View file

@ -77,13 +77,11 @@ public:
idSoundVoice* AllocateVoice( const idSoundSample* leadinSample, const idSoundSample* loopingSample ); idSoundVoice* AllocateVoice( const idSoundSample* leadinSample, const idSoundSample* loopingSample );
void FreeVoice( idSoundVoice* voice ); void FreeVoice( idSoundVoice* voice );
// video playback needs this // listDevices needs this
/* ALCdevice* GetOpenALDevice() const
IXAudio2* GetIXAudio2() const
{ {
return pXAudio2; return openalDevice;
}; };
*/
int GetNumZombieVoices() const int GetNumZombieVoices() const
{ {
@ -94,6 +92,11 @@ public:
return freeVoices.Num(); return freeVoices.Num();
} }
// OpenAL info
static void PrintDeviceList( const char* list );
static void PrintALCInfo( ALCdevice* device );
static void PrintALInfo();
protected: protected:
friend class idSoundSample_OpenAL; friend class idSoundSample_OpenAL;
friend class idSoundVoice_OpenAL; friend class idSoundVoice_OpenAL;

View file

@ -280,17 +280,17 @@ void idSoundSample_OpenAL::LoadResource()
void idSoundSample_OpenAL::CreateOpenALBuffer() void idSoundSample_OpenAL::CreateOpenALBuffer()
{ {
// build OpenAL buffer // build OpenAL buffer
alGetError(); CheckALErrors();
alGenBuffers( 1, &openalBuffer ); alGenBuffers( 1, &openalBuffer );
if( alGetError() != AL_NO_ERROR ) if( CheckALErrors() != AL_NO_ERROR )
{ {
common->Error( "idSoundSample_OpenAL::CreateOpenALBuffer: error generating OpenAL hardware buffer" ); common->Error( "idSoundSample_OpenAL::CreateOpenALBuffer: error generating OpenAL hardware buffer" );
} }
if( alIsBuffer( openalBuffer ) ) if( alIsBuffer( openalBuffer ) )
{ {
alGetError(); CheckALErrors();
// RB: TODO decode idWaveFile::FORMAT_ADPCM to idWaveFile::FORMAT_PCM // RB: TODO decode idWaveFile::FORMAT_ADPCM to idWaveFile::FORMAT_PCM
// and build one big OpenAL buffer using the alBufferSubData extension // and build one big OpenAL buffer using the alBufferSubData extension
@ -352,7 +352,7 @@ void idSoundSample_OpenAL::CreateOpenALBuffer()
alBufferData( openalBuffer, GetOpenALBufferFormat(), buffer, bufferSize, format.basic.samplesPerSec ); alBufferData( openalBuffer, GetOpenALBufferFormat(), buffer, bufferSize, format.basic.samplesPerSec );
} }
if( alGetError() != AL_NO_ERROR ) if( CheckALErrors() != AL_NO_ERROR )
{ {
common->Error( "idSoundSample_OpenAL::CreateOpenALBuffer: error loading data into OpenAL hardware buffer" ); common->Error( "idSoundSample_OpenAL::CreateOpenALBuffer: error loading data into OpenAL hardware buffer" );
} }
@ -579,19 +579,19 @@ void idSoundSample_OpenAL::MakeDefault()
playLength = DEFAULT_NUM_SAMPLES; playLength = DEFAULT_NUM_SAMPLES;
alGetError(); CheckALErrors();
alGenBuffers( 1, &openalBuffer ); alGenBuffers( 1, &openalBuffer );
if( alGetError() != AL_NO_ERROR ) if( CheckALErrors() != AL_NO_ERROR )
{ {
common->Error( "idSoundSample_OpenAL::MakeDefault: error generating OpenAL hardware buffer" ); common->Error( "idSoundSample_OpenAL::MakeDefault: error generating OpenAL hardware buffer" );
} }
if( alIsBuffer( openalBuffer ) ) if( alIsBuffer( openalBuffer ) )
{ {
alGetError(); CheckALErrors();
alBufferData( openalBuffer, GetOpenALBufferFormat(), defaultBuffer, totalBufferSize, format.basic.samplesPerSec ); alBufferData( openalBuffer, GetOpenALBufferFormat(), defaultBuffer, totalBufferSize, format.basic.samplesPerSec );
if( alGetError() != AL_NO_ERROR ) if( CheckALErrors() != AL_NO_ERROR )
{ {
common->Error( "idSoundSample_OpenAL::MakeDefault: error loading data into OpenAL hardware buffer" ); common->Error( "idSoundSample_OpenAL::MakeDefault: error loading data into OpenAL hardware buffer" );
} }
@ -627,9 +627,10 @@ void idSoundSample_OpenAL::FreeData()
if( alIsBuffer( openalBuffer ) ) if( alIsBuffer( openalBuffer ) )
{ {
alGetError(); CheckALErrors();
alDeleteBuffers( 1, &openalBuffer ); alDeleteBuffers( 1, &openalBuffer );
if( alGetError() != AL_NO_ERROR ) if( CheckALErrors() != AL_NO_ERROR )
{ {
common->Error( "idSoundSample_OpenAL::FreeData: error unloading data from OpenAL hardware buffer" ); common->Error( "idSoundSample_OpenAL::FreeData: error unloading data from OpenAL hardware buffer" );
} }

View file

@ -145,9 +145,10 @@ void idSoundVoice_OpenAL::Create( const idSoundSample* leadinSample_, const idSo
//soundSystemLocal.hardware.pXAudio2->CreateSourceVoice( &pSourceVoice, ( const WAVEFORMATEX* )&leadinSample->format, XAUDIO2_VOICE_USEFILTER, 4.0f, &streamContext ); //soundSystemLocal.hardware.pXAudio2->CreateSourceVoice( &pSourceVoice, ( const WAVEFORMATEX* )&leadinSample->format, XAUDIO2_VOICE_USEFILTER, 4.0f, &streamContext );
alGetError(); CheckALErrors();
alGenSources( 1, &openalSource ); alGenSources( 1, &openalSource );
if( alGetError() != AL_NO_ERROR ) if( CheckALErrors() != AL_NO_ERROR )
//if( pSourceVoice == NULL ) //if( pSourceVoice == NULL )
{ {
// If this hits, then we are most likely passing an invalid sample format, which should have been caught by the loader (and the sample defaulted) // If this hits, then we are most likely passing an invalid sample format, which should have been caught by the loader (and the sample defaulted)
@ -568,9 +569,10 @@ void idSoundVoice_OpenAL::FlushSourceBuffers()
if( openalStreamingBuffer[0] && openalStreamingBuffer[1] && openalStreamingBuffer[2] ) if( openalStreamingBuffer[0] && openalStreamingBuffer[1] && openalStreamingBuffer[2] )
{ {
alGetError(); CheckALErrors();
alDeleteBuffers( 3, &openalStreamingBuffer[0] ); alDeleteBuffers( 3, &openalStreamingBuffer[0] );
if( alGetError() == AL_NO_ERROR ) if( CheckALErrors() == AL_NO_ERROR )
{ {
openalStreamingBuffer[0] = openalStreamingBuffer[1] = openalStreamingBuffer[2] = 0; openalStreamingBuffer[0] = openalStreamingBuffer[1] = openalStreamingBuffer[2] = 0;
} }
@ -578,9 +580,10 @@ void idSoundVoice_OpenAL::FlushSourceBuffers()
if( lastopenalStreamingBuffer[0] && lastopenalStreamingBuffer[1] && lastopenalStreamingBuffer[2] ) if( lastopenalStreamingBuffer[0] && lastopenalStreamingBuffer[1] && lastopenalStreamingBuffer[2] )
{ {
alGetError(); CheckALErrors();
alDeleteBuffers( 3, &lastopenalStreamingBuffer[0] ); alDeleteBuffers( 3, &lastopenalStreamingBuffer[0] );
if( alGetError() == AL_NO_ERROR ) if( CheckALErrors() == AL_NO_ERROR )
{ {
lastopenalStreamingBuffer[0] = lastopenalStreamingBuffer[1] = lastopenalStreamingBuffer[2] = 0; lastopenalStreamingBuffer[0] = lastopenalStreamingBuffer[1] = lastopenalStreamingBuffer[2] = 0;
} }
@ -654,7 +657,7 @@ void idSoundVoice_OpenAL::Stop()
} }
alSourceStop( openalSource ); alSourceStop( openalSource );
//alSourcei( openalSource, AL_BUFFER, 0 ); alSourcei( openalSource, AL_BUFFER, 0 );
//pSourceVoice->Stop( 0, OPERATION_SET ); //pSourceVoice->Stop( 0, OPERATION_SET );
paused = true; paused = true;

View file

@ -105,6 +105,28 @@ typedef enum
#include "OpenAL/AL_SoundVoice.h" #include "OpenAL/AL_SoundVoice.h"
#include "OpenAL/AL_SoundHardware.h" #include "OpenAL/AL_SoundHardware.h"
ID_INLINE_EXTERN ALenum CheckALErrors_( const char* filename, int line )
{
ALenum err = alGetError();
if( err != AL_NO_ERROR )
{
idLib::Printf( "OpenAL Error: %s (0x%x), @ %s %d\n", alGetString( err ), err, filename, line );
}
return err;
}
#define CheckALErrors() CheckALErrors_(__FILE__, __LINE__)
ID_INLINE_EXTERN ALCenum CheckALCErrors_( ALCdevice* device, const char* filename, int linenum )
{
ALCenum err = alcGetError( device );
if( err != ALC_NO_ERROR )
{
idLib::Printf( "ALC Error: %s (0x%x), @ %s %d\n", alcGetString( device, err ), err, filename, linenum );
}
return err;
}
#define CheckALCErrors(x) CheckALCErrors_((x), __FILE__, __LINE__)
#elif defined(_MSC_VER) // DG: stub out xaudio for MinGW etc #elif defined(_MSC_VER) // DG: stub out xaudio for MinGW etc
#define OPERATION_SET 1 #define OPERATION_SET 1
@ -460,6 +482,10 @@ public:
virtual void* GetIXAudio2() const; // FIXME: stupid name; get rid of this? not sure if it's really needed.. virtual void* GetIXAudio2() const; // FIXME: stupid name; get rid of this? not sure if it's really needed..
// RB begin
virtual void* GetOpenALDevice() const;
// RB end
// for the sound level meter window // for the sound level meter window
virtual cinData_t ImageForTime( const int milliseconds, const bool waveform ); virtual cinData_t ImageForTime( const int milliseconds, const bool waveform );

View file

@ -399,6 +399,22 @@ void* idSoundSystemLocal::GetIXAudio2() const
// RB end // RB end
} }
/*
========================
idSoundSystemLocal::GetOpenALDevice
========================
*/
// RB begin
void* idSoundSystemLocal::GetOpenALDevice() const
{
#if defined(USE_OPENAL)
return ( void* )hardware.GetOpenALDevice();
#else
return ( void* )hardware.GetIXAudio2();
#endif
}
// RB end
/* /*
======================== ========================
idSoundSystemLocal::SoundTime idSoundSystemLocal::SoundTime

View file

@ -321,6 +321,10 @@ public:
// video playback needs to get this // video playback needs to get this
virtual void* GetIXAudio2() const = 0; // FIXME: stupid name if we have other backends virtual void* GetIXAudio2() const = 0; // FIXME: stupid name if we have other backends
#if defined(USE_OPENAL)
virtual void* GetOpenALDevice() const = 0;
#endif
// for the sound level meter window // for the sound level meter window
virtual cinData_t ImageForTime( const int milliseconds, const bool waveform ) = 0; virtual cinData_t ImageForTime( const int milliseconds, const bool waveform ) = 0;