You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Original Notes (adapted) Implementation and Integration of Oculus Audio SDK for VR Audio Spatialization - Adding new audio extension which wraps the oculus audio sdk and the new XAPO plugin - Adding new XAPO (Xaudio2 Audio Processing Object) effect for processing mono audio source streams inside the new module - Added new enumeration which allows users to select which spatialization algorithm to use for spatialized mono sources - Refactored the regular sound source spatialization/effect in XAudio2 device code to support the new HRTF mono-to-stereo effect - Designed feature so that if the sound spatialization module isn't used, the spatialization will default to normal spatialization algorithm Notes on implementation: - Because the audio engine doesn't bifurcate spatialized vs. non-spatialized sound sources into separate source pools, I had to create up-front the effects for the full number of supported sounds 32). This is because the oculus sdk requires at initialization the total number of sound sources that will be used in the SDK. - Because the oculus SDK refers to sound source instances by index (into the pre-allocated array of sources set at init), I had to save each sound source's index so that it can be used on the HRTF XAPO effect, and then piped to the oculus SDK inside the UE audio extension. - The audio engine assumes that mono-sources will be treated a certain way (during send-routing and spatialization). Because this new HRTF effect is effectively turning mono-sources into stereo-sources, some code had to be changed to send/route these audio sources as if they were stereo. - This implementation is slightly different than the original GDC implementation to better work with multiple audio devices. Each audio device creates an IAudioSpatializationAlgorithm object which contains the oculus HRTF processing contexts. #codereview Nick.Whiting Marc.Audy [CL 2488287 by Aaron McLeran in Main branch]
189 lines
5.3 KiB
C++
189 lines
5.3 KiB
C++
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
/*------------------------------------------------------------------------------------
|
|
Audio includes.
|
|
------------------------------------------------------------------------------------*/
|
|
|
|
#include "AndroidAudioDevice.h"
|
|
#include "VorbisAudioInfo.h"
|
|
#include "ADPCMAudioInfo.h"
|
|
#include "AudioEffect.h"
|
|
#include "Engine.h"
|
|
|
|
DEFINE_LOG_CATEGORY(LogAndroidAudio);
|
|
|
|
|
|
class FSLESAudioDeviceModule : public IAudioDeviceModule
|
|
{
|
|
public:
|
|
|
|
/** Creates a new instance of the audio device implemented by the module. */
|
|
virtual FAudioDevice* CreateAudioDevice() override
|
|
{
|
|
return new FSLESAudioDevice;
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_MODULE(FSLESAudioDeviceModule, AndroidAudio );
|
|
/*------------------------------------------------------------------------------------
|
|
UALAudioDevice constructor and UObject interface.
|
|
------------------------------------------------------------------------------------*/
|
|
|
|
void FSLESAudioDevice::Teardown( void )
|
|
{
|
|
// Flush stops all sources and deletes all buffers so sources can be safely deleted below.
|
|
Flush( NULL );
|
|
|
|
// Destroy all sound sources
|
|
for( int32 i = 0; i < Sources.Num(); i++ )
|
|
{
|
|
delete Sources[ i ];
|
|
}
|
|
|
|
UE_LOG( LogAndroidAudio, Warning, TEXT("OpenSLES Tearing Down HW"));
|
|
|
|
// Teardown OpenSLES..
|
|
// Destroy the SLES objects in reverse order of creation:
|
|
if (SL_OutputMixObject)
|
|
{
|
|
(*SL_OutputMixObject)->Destroy(SL_OutputMixObject);
|
|
SL_OutputMixObject = NULL;
|
|
}
|
|
if (SL_EngineObject)
|
|
{
|
|
(*SL_EngineObject)->Destroy(SL_EngineObject);
|
|
SL_EngineObject = NULL;
|
|
SL_EngineEngine = NULL;
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------------
|
|
UAudioDevice Interface.
|
|
------------------------------------------------------------------------------------*/
|
|
/**
|
|
* Initializes the audio device and creates sources.
|
|
*
|
|
* @warning:
|
|
*
|
|
* @return TRUE if initialization was successful, FALSE otherwise
|
|
*/
|
|
bool FSLESAudioDevice::InitializeHardware( void )
|
|
{
|
|
UE_LOG( LogAndroidAudio, Warning, TEXT("SL Entered Init HW"));
|
|
|
|
SLresult result;
|
|
|
|
UE_LOG( LogAndroidAudio, Warning, TEXT("OpenSLES Initializing HW"));
|
|
|
|
SLEngineOption EngineOption[] = { {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE} };
|
|
|
|
// create engine
|
|
result = slCreateEngine( &SL_EngineObject, 1, EngineOption, 0, NULL, NULL);
|
|
//check(SL_RESULT_SUCCESS == result);
|
|
if (SL_RESULT_SUCCESS != result)
|
|
{
|
|
UE_LOG( LogAndroidAudio, Error, TEXT("Engine create failed %d"), int32(result));
|
|
}
|
|
|
|
// realize the engine
|
|
result = (*SL_EngineObject)->Realize(SL_EngineObject, SL_BOOLEAN_FALSE);
|
|
check(SL_RESULT_SUCCESS == result);
|
|
|
|
// get the engine interface, which is needed in order to create other objects
|
|
result = (*SL_EngineObject)->GetInterface(SL_EngineObject, SL_IID_ENGINE, &SL_EngineEngine);
|
|
check(SL_RESULT_SUCCESS == result);
|
|
|
|
// create output mix, with environmental reverb specified as a non-required interface
|
|
result = (*SL_EngineEngine)->CreateOutputMix( SL_EngineEngine, &SL_OutputMixObject, 0, NULL, NULL );
|
|
check(SL_RESULT_SUCCESS == result);
|
|
|
|
// realize the output mix
|
|
result = (*SL_OutputMixObject)->Realize(SL_OutputMixObject, SL_BOOLEAN_FALSE);
|
|
check(SL_RESULT_SUCCESS == result);
|
|
|
|
UE_LOG( LogAndroidAudio, Warning, TEXT("OpenSLES Initialized"));
|
|
// ignore unsuccessful result codes for env
|
|
|
|
|
|
// Default to sensible channel count.
|
|
if( MaxChannels < 1 )
|
|
{
|
|
MaxChannels = 12;
|
|
}
|
|
|
|
|
|
// Initialize channels.
|
|
for( int32 i = 0; i < FMath::Min( MaxChannels, 12 ); i++ )
|
|
{
|
|
FSLESSoundSource* Source = new FSLESSoundSource( this );
|
|
Sources.Add( Source );
|
|
FreeSources.Add( Source );
|
|
}
|
|
|
|
if( Sources.Num() < 1 )
|
|
{
|
|
UE_LOG( LogAndroidAudio, Warning, TEXT( "OpenSLAudio: couldn't allocate any sources" ) );
|
|
return false;
|
|
}
|
|
|
|
// Update MaxChannels in case we couldn't create enough sources.
|
|
MaxChannels = Sources.Num();
|
|
UE_LOG( LogAndroidAudio, Warning, TEXT( "OpenSLAudioDevice: Allocated %i sources" ), MaxChannels );
|
|
|
|
// Set up a default (nop) effects manager
|
|
Effects = new FAudioEffectsManager( this );
|
|
|
|
return true;
|
|
}
|
|
|
|
FSoundSource* FSLESAudioDevice::CreateSoundSource(uint32 VoiceId)
|
|
{
|
|
return new FSLESSoundSource(this);
|
|
}
|
|
|
|
bool FSLESAudioDevice::HasCompressedAudioInfoClass(USoundWave* SoundWave)
|
|
{
|
|
#if WITH_OGGVORBIS
|
|
static FName NAME_OGG(TEXT("OGG"));
|
|
if (SoundWave->CompressionName.IsValid() && SoundWave->CompressionName == NAME_OGG)
|
|
{
|
|
return true;
|
|
}
|
|
#endif
|
|
static FName NAME_ADPCM(TEXT("ADPCM"));
|
|
if (SoundWave->CompressionName.IsValid() && SoundWave->CompressionName == NAME_ADPCM)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
class ICompressedAudioInfo* FSLESAudioDevice::CreateCompressedAudioInfo(USoundWave* SoundWave)
|
|
{
|
|
#if WITH_OGGVORBIS
|
|
static FName NAME_OGG(TEXT("OGG"));
|
|
if (SoundWave->CompressionName.IsValid() && SoundWave->CompressionName == NAME_OGG)
|
|
{
|
|
return new FVorbisAudioInfo();
|
|
}
|
|
#endif
|
|
static FName NAME_ADPCM(TEXT("ADPCM"));
|
|
if (SoundWave->CompressionName.IsValid() && SoundWave->CompressionName == NAME_ADPCM)
|
|
{
|
|
return new FADPCMAudioInfo();
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/** Check if any background music or sound is playing through the audio device */
|
|
bool FSLESAudioDevice::IsExernalBackgroundSoundActive()
|
|
{
|
|
extern bool AndroidThunkCpp_IsMusicActive();
|
|
return AndroidThunkCpp_IsMusicActive();
|
|
|
|
}
|