Files
UnrealEngineUWP/Engine/Source/Runtime/HTML5/HTML5Audio/Private/HTML5AudioDevice.cpp
Matthew Griffin 551379cad2 Fixing issues with SoundWave memory and duplicated variables in some platforms.
Moved most of the contents of FAudioDevice::FreeResource to USoundWave::FreeResources so that we can be sure that all memory is cleared up during teardown.
Removed FreeResource function from some subclasses of audio device, as they weren't doing anything different than the base one.
Also removed ListSounds function from these same classes as that seems to have fallen behind current base class version and isn't used anyway.
Removed platform specific audio buffer storage so that there isn't confusion about which is being used and ensured that casts are used when necessary.
Fixed compile issue with STAT_AudioResourceCreationTime for HTML5.

[CL 2109273 by Matthew Griffin in Main branch]
2014-06-18 10:31:15 -04:00

373 lines
9.6 KiB
C++

// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
/*=============================================================================
ALAudioDevice.cpp: Unreal OpenAL Audio interface object.
Unreal is RHS with Y and Z swapped (or technically LHS with flipped axis)
=============================================================================*/
/*------------------------------------------------------------------------------------
Audio includes.
------------------------------------------------------------------------------------*/
#include "HTML5AudioDevice.h"
#include "AudioDecompress.h"
#include "AudioEffect.h"
#include "Engine.h"
DEFINE_LOG_CATEGORY(LogALAudio);
// 2 UU == 1"
// <=> 1 UU == 0.0127 m
#define AUDIO_DISTANCE_FACTOR ( 0.0127f )
ALCdevice* FALAudioDevice::HardwareDevice = NULL;
ALCcontext* FALAudioDevice::SoundContext = NULL;
class FHTML5AudioDeviceModule : public IAudioDeviceModule
{
public:
/** Creates a new instance of the audio device implemented by the module. */
virtual FAudioDevice* CreateAudioDevice() override
{
return new FALAudioDevice;
}
};
IMPLEMENT_MODULE(FHTML5AudioDeviceModule, HTML5Audio );
/*------------------------------------------------------------------------------------
UALAudioDevice constructor and UObject interface.
------------------------------------------------------------------------------------*/
void FALAudioDevice::TeardownHardware( void )
{
// Flush stops all sources and deletes all buffers so sources can be safely deleted below.
Flush( NULL );
// Push any pending data to the hardware
if( &alcProcessContext )
{
alcProcessContext( SoundContext );
}
// Destroy all sound sources
for( int i = 0; i < Sources.Num(); i++ )
{
delete Sources[ i ];
}
Sources.Empty();
FreeSources.Empty();
// Disable the context
if( &alcMakeContextCurrent )
{
alcMakeContextCurrent( NULL );
}
// Destroy the context
if( &alcDestroyContext )
{
alcDestroyContext( SoundContext );
SoundContext = NULL;
}
// Close the hardware device
if( &alcCloseDevice )
{
alcCloseDevice( HardwareDevice );
HardwareDevice = NULL;
}
}
/*------------------------------------------------------------------------------------
UAudioDevice Interface.
------------------------------------------------------------------------------------*/
/**
* Initializes the audio device and creates sources.
*
* @warning:
*
* @return TRUE if initialization was successful, FALSE otherwise
*/
bool FALAudioDevice::InitializeHardware( void )
{
// Make sure no interface classes contain any garbage
Effects = NULL;
DLLHandle = NULL;
// Default to sensible channel count.
if( MaxChannels < 1 )
{
MaxChannels = 32;
}
// Load ogg and vorbis dlls if they haven't been loaded yet
//LoadVorbisLibraries();
// Open device
HardwareDevice = alcOpenDevice( NULL );
if( !HardwareDevice )
{
UE_LOG(LogALAudio, Log, TEXT( "ALAudio: no OpenAL devices found." ) );
return false ;
}
// Display the audio device that was actually opened
const ALCchar* OpenedDeviceName = alcGetString( HardwareDevice, ALC_DEVICE_SPECIFIER );
UE_LOG(LogALAudio, Log, TEXT("ALAudio device opened : %s"), StringCast<TCHAR>(static_cast<const ANSICHAR*>(OpenedDeviceName)).Get());
// Create a context
int Caps[] =
{
ALC_FREQUENCY, 44100,
ALC_STEREO_SOURCES, 4,
0, 0
};
#if PLATFORM_HTML5_WIN32
SoundContext = alcCreateContext( HardwareDevice, Caps );
#elif PLATFORM_HTML5
SoundContext = alcCreateContext( HardwareDevice, 0 );
#endif
if( !SoundContext )
{
return false ;
}
alcMakeContextCurrent( SoundContext );
// Make sure everything happened correctly
if( alError( TEXT( "Init" ) ) )
{
UE_LOG(LogALAudio, Warning, TEXT("ALAudio: alcMakeContextCurrent failed."));
return false ;
}
UE_LOG(LogALAudio, Log, TEXT("AL_VENDOR : %s"), StringCast<TCHAR>(static_cast<const ANSICHAR*>(alGetString(AL_VENDOR))).Get());
UE_LOG(LogALAudio, Log, TEXT("AL_RENDERER : %s"), StringCast<TCHAR>(static_cast<const ANSICHAR*>(alGetString(AL_RENDERER))).Get());
UE_LOG(LogALAudio, Log, TEXT("AL_VERSION : %s"), StringCast<TCHAR>(static_cast<const ANSICHAR*>(alGetString(AL_VERSION))).Get());
UE_LOG(LogALAudio, Log, TEXT("AL_EXTENSIONS : %s"), StringCast<TCHAR>(static_cast<const ANSICHAR*>(alGetString(AL_EXTENSIONS))).Get());
// Get the enums for multichannel support
#if !PLATFORM_HTML5
Surround40Format = alGetEnumValue( "AL_FORMAT_QUAD16" );
Surround51Format = alGetEnumValue( "AL_FORMAT_51CHN16" );
Surround61Format = alGetEnumValue( "AL_FORMAT_61CHN16" );
Surround71Format = alGetEnumValue( "AL_FORMAT_71CHN16" );
#endif
// Initialize channels.
alError( TEXT( "Emptying error stack" ), 0 );
for( int i = 0; i < (( MaxChannels > MAX_AUDIOCHANNELS ) ? MAX_AUDIOCHANNELS : MaxChannels); i++ )
{
ALuint SourceId;
alGenSources( 1, &SourceId );
if( !alError( TEXT( "Init (creating sources)" ), 0 ) )
{
FALSoundSource* Source = new FALSoundSource( this );
Source->SourceId = SourceId;
Sources.Add( Source );
FreeSources.Add( Source );
}
else
{
break;
}
}
if( Sources.Num() < 1 )
{
UE_LOG(LogALAudio, Warning, TEXT("ALAudio: couldn't allocate any sources"));
return false ;
}
// Update MaxChannels in case we couldn't create enough sources.
MaxChannels = Sources.Num();
UE_LOG(LogALAudio, Verbose, TEXT("ALAudioDevice: Allocated %i sources"), MaxChannels);
// Use our own distance model.
alDistanceModel( AL_NONE );
// Set up a default (nop) effects manager
Effects = new FAudioEffectsManager( this );
return true ;
}
/**
* Update the audio device and calculates the cached inverse transform later
* on used for spatialization.
*
* @param Realtime whether we are paused or not
*/
void FALAudioDevice::Update( bool Realtime )
{
FVector ListenerLocation = Listeners[ 0 ].Transform.GetLocation();
FVector ListenerFront = Listeners[ 0 ].GetFront();
FVector ListenerUp = Listeners[ 0 ].GetUp();
// Set Player position
FVector Location;
// See file header for coordinate system explanation.
Location.X = ListenerLocation.X;
Location.Y = ListenerLocation.Z; // Z/Y swapped on purpose, see file header
Location.Z = ListenerLocation.Y; // Z/Y swapped on purpose, see file header
Location *= AUDIO_DISTANCE_FACTOR;
// Set Player orientation.
FVector Orientation[2];
// See file header for coordinate system explanation.
Orientation[0].X = ListenerFront.X;
Orientation[0].Y = ListenerFront.Z; // Z/Y swapped on purpose, see file header
Orientation[0].Z = ListenerFront.Y; // Z/Y swapped on purpose, see file header
// See file header for coordinate system explanation.
Orientation[1].X = ListenerUp.X;
Orientation[1].Y = ListenerUp.Z; // Z/Y swapped on purpose, see file header
Orientation[1].Z = ListenerUp.Y; // Z/Y swapped on purpose, see file header
// Make the listener still and the sounds move relatively -- this allows
// us to scale the doppler effect on a per-sound basis.
FVector Velocity = FVector( 0.0f, 0.0f, 0.0f );
alListenerfv( AL_POSITION, ( ALfloat * )&Location );
alListenerfv( AL_ORIENTATION, ( ALfloat * )&Orientation[0] );
alListenerfv( AL_VELOCITY, ( ALfloat * )&Velocity );
alError( TEXT( "UALAudioDevice::Update" ) );
}
ALuint FALAudioDevice::GetInternalFormat( int NumChannels )
{
ALuint InternalFormat = 0;
switch( NumChannels )
{
case 0:
case 3:
case 5:
break;
case 1:
InternalFormat = AL_FORMAT_MONO16;
break;
case 2:
InternalFormat = AL_FORMAT_STEREO16;
break;
#if !PLATFORM_HTML5
case 4:
InternalFormat = Surround40Format;
break;
case 6:
InternalFormat = Surround51Format;
break;
case 7:
InternalFormat = Surround61Format;
break;
case 8:
InternalFormat = Surround71Format;
break;
#endif
}
return( InternalFormat );
}
/*------------------------------------------------------------------------------------
OpenAL utility functions
------------------------------------------------------------------------------------*/
//
// FindExt
//
bool FALAudioDevice::FindExt( const TCHAR* Name )
{
return alIsExtensionPresent(TCHAR_TO_ANSI(Name)) || alcIsExtensionPresent(HardwareDevice, TCHAR_TO_ANSI(Name));
}
//
// FindProc
//
void FALAudioDevice::FindProc( void*& ProcAddress, char* Name, char* SupportName, bool& Supports, bool AllowExt )
{
}
//
// FindProcs
//
void FALAudioDevice::FindProcs( bool AllowExt )
{
}
//
// alError
//
bool FALAudioDevice::alError( const TCHAR* Text, bool Log )
{
ALenum Error = alGetError();
if( Error != AL_NO_ERROR )
{
do
{
if( Log )
{
switch ( Error )
{
case AL_INVALID_NAME:
UE_LOG(LogALAudio, Warning, TEXT("ALAudio: AL_INVALID_NAME in %s"), Text);
break;
case AL_INVALID_VALUE:
UE_LOG(LogALAudio, Warning, TEXT("ALAudio: AL_INVALID_VALUE in %s"), Text);
break;
case AL_OUT_OF_MEMORY:
UE_LOG(LogALAudio, Warning, TEXT("ALAudio: AL_OUT_OF_MEMORY in %s"), Text);
break;
case AL_INVALID_ENUM:
UE_LOG(LogALAudio, Warning, TEXT("ALAudio: AL_INVALID_ENUM in %s"), Text);
break;
case AL_INVALID_OPERATION:
UE_LOG(LogALAudio, Warning, TEXT("ALAudio: AL_INVALID_OPERATION in %s"), Text);
break;
default:
UE_LOG(LogALAudio, Warning, TEXT("ALAudio: Unknown Error NUM in %s"), Text);
break;
}
}
}
while( ( Error = alGetError() ) != AL_NO_ERROR );
return true ;
}
return false ;
}
FSoundSource* FALAudioDevice::CreateSoundSource()
{
return new FALSoundSource(this);
}
bool FALAudioDevice::HasCompressedAudioInfoClass(USoundWave* SoundWave)
{
#if WITH_OGGVORBIS
return true;
#else
return false;
#endif
}
class ICompressedAudioInfo* FALAudioDevice::CreateCompressedAudioInfo(USoundWave* SoundWave)
{
#if WITH_OGGVORBIS
return new FVorbisAudioInfo();
#else
return NULL;
#endif
}