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
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
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").
@ -61,135 +62,98 @@ idSoundHardware_OpenAL::idSoundHardware_OpenAL()
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 )
{
#if 1
// TODO
idLib::Warning( "No audio devices found" );
return;
#else
UINT32 deviceCount = 0;
if( pXAudio2->GetDeviceCount( &deviceCount ) != S_OK || deviceCount == 0 )
idLib::Printf( "Available playback devices:\n" );
if( alcIsExtensionPresent( NULL, "ALC_ENUMERATE_ALL_EXT" ) != AL_FALSE )
{
idLib::Warning( "No audio devices found" );
return;
idSoundHardware_OpenAL::PrintDeviceList( alcGetString( NULL, ALC_ALL_DEVICES_SPECIFIER ) );
}
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;
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] );
}
idLib::Printf( "Default playback device: %s\n", alcGetString( NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER ) );
}
#endif
// RB end
else
{
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 );
void FreeVoice( idSoundVoice* voice );
// video playback needs this
/*
IXAudio2* GetIXAudio2() const
// listDevices needs this
ALCdevice* GetOpenALDevice() const
{
return pXAudio2;
return openalDevice;
};
*/
int GetNumZombieVoices() const
{
@ -94,6 +92,11 @@ public:
return freeVoices.Num();
}
// OpenAL info
static void PrintDeviceList( const char* list );
static void PrintALCInfo( ALCdevice* device );
static void PrintALInfo();
protected:
friend class idSoundSample_OpenAL;
friend class idSoundVoice_OpenAL;

View file

@ -280,17 +280,17 @@ void idSoundSample_OpenAL::LoadResource()
void idSoundSample_OpenAL::CreateOpenALBuffer()
{
// build OpenAL buffer
alGetError();
CheckALErrors();
alGenBuffers( 1, &openalBuffer );
if( alGetError() != AL_NO_ERROR )
if( CheckALErrors() != AL_NO_ERROR )
{
common->Error( "idSoundSample_OpenAL::CreateOpenALBuffer: error generating OpenAL hardware buffer" );
}
if( alIsBuffer( openalBuffer ) )
{
alGetError();
CheckALErrors();
// RB: TODO decode idWaveFile::FORMAT_ADPCM to idWaveFile::FORMAT_PCM
// 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 );
}
if( alGetError() != AL_NO_ERROR )
if( CheckALErrors() != AL_NO_ERROR )
{
common->Error( "idSoundSample_OpenAL::CreateOpenALBuffer: error loading data into OpenAL hardware buffer" );
}
@ -579,19 +579,19 @@ void idSoundSample_OpenAL::MakeDefault()
playLength = DEFAULT_NUM_SAMPLES;
alGetError();
CheckALErrors();
alGenBuffers( 1, &openalBuffer );
if( alGetError() != AL_NO_ERROR )
if( CheckALErrors() != AL_NO_ERROR )
{
common->Error( "idSoundSample_OpenAL::MakeDefault: error generating OpenAL hardware buffer" );
}
if( alIsBuffer( openalBuffer ) )
{
alGetError();
CheckALErrors();
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" );
}
@ -627,9 +627,10 @@ void idSoundSample_OpenAL::FreeData()
if( alIsBuffer( openalBuffer ) )
{
alGetError();
CheckALErrors();
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" );
}

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 );
alGetError();
CheckALErrors();
alGenSources( 1, &openalSource );
if( alGetError() != AL_NO_ERROR )
if( CheckALErrors() != AL_NO_ERROR )
//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)
@ -568,9 +569,10 @@ void idSoundVoice_OpenAL::FlushSourceBuffers()
if( openalStreamingBuffer[0] && openalStreamingBuffer[1] && openalStreamingBuffer[2] )
{
alGetError();
CheckALErrors();
alDeleteBuffers( 3, &openalStreamingBuffer[0] );
if( alGetError() == AL_NO_ERROR )
if( CheckALErrors() == AL_NO_ERROR )
{
openalStreamingBuffer[0] = openalStreamingBuffer[1] = openalStreamingBuffer[2] = 0;
}
@ -578,9 +580,10 @@ void idSoundVoice_OpenAL::FlushSourceBuffers()
if( lastopenalStreamingBuffer[0] && lastopenalStreamingBuffer[1] && lastopenalStreamingBuffer[2] )
{
alGetError();
CheckALErrors();
alDeleteBuffers( 3, &lastopenalStreamingBuffer[0] );
if( alGetError() == AL_NO_ERROR )
if( CheckALErrors() == AL_NO_ERROR )
{
lastopenalStreamingBuffer[0] = lastopenalStreamingBuffer[1] = lastopenalStreamingBuffer[2] = 0;
}
@ -654,7 +657,7 @@ void idSoundVoice_OpenAL::Stop()
}
alSourceStop( openalSource );
//alSourcei( openalSource, AL_BUFFER, 0 );
alSourcei( openalSource, AL_BUFFER, 0 );
//pSourceVoice->Stop( 0, OPERATION_SET );
paused = true;

View file

@ -105,6 +105,28 @@ typedef enum
#include "OpenAL/AL_SoundVoice.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
#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..
// RB begin
virtual void* GetOpenALDevice() const;
// RB end
// for the sound level meter window
virtual cinData_t ImageForTime( const int milliseconds, const bool waveform );

View file

@ -399,6 +399,22 @@ void* idSoundSystemLocal::GetIXAudio2() const
// 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

View file

@ -321,6 +321,10 @@ public:
// video playback needs to get this
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
virtual cinData_t ImageForTime( const int milliseconds, const bool waveform ) = 0;