Files
UnrealEngine/Engine/Source/Runtime/IOS/IOSAudio/Public/IOSAudioDevice.h
2025-05-18 13:04:45 +08:00

266 lines
8.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
IOSAudioDevice.h: Unreal IOSAudio audio interface object.
=============================================================================*/
#pragma once
#include "CoreMinimal.h"
#include "AudioEffect.h"
#include "AudioDevice.h"
#include "Sound/SoundWave.h"
#include "DSP/ParamInterpolator.h"
#include "DSP/OnePole.h"
/*------------------------------------------------------------------------------------
Audio Framework system headers
------------------------------------------------------------------------------------*/
#include <AudioToolbox/AudioToolbox.h>
#include <AudioUnit/AudioUnit.h>
#include <AVFoundation/AVAudioSession.h>
#define AudioSampleType SInt16
DECLARE_LOG_CATEGORY_EXTERN(LogIOSAudio, Log, All);
/*------------------------------------------------------------------------------------
Dependencies, helpers & forward declarations.
------------------------------------------------------------------------------------*/
#define CHANNELS_PER_BUS 2
#define AudioCallbackFrameSize (8 * 1024) // This needs to be known ahead of time to allocate appropriate buffers
struct FWaveInstance;
class FIOSAudioDevice;
class FIOSAudioEffectsManager;
class ICompressedAudioInfo;
enum ESoundFormat
{
SoundFormat_Invalid,
SoundFormat_LPCM,
SoundFormat_ADPCM
};
/**
* IOSAudio implementation of FSoundBuffer, containing the wave data and format information.
*/
class FIOSAudioSoundBuffer : public FSoundBuffer
{
public:
FIOSAudioSoundBuffer(FIOSAudioDevice* InAudioDevice, USoundWave* InWave, bool InStreaming, bool InProcedural);
virtual ~FIOSAudioSoundBuffer(void);
/**
* Static function used to create a buffer.
*
* @param InWave USoundWave to use as template and wave source
* @param AudioDevice audio device to attach created buffer to
* @return FIOSAudioSoundBuffer pointer if buffer creation succeeded, NULL otherwise
*/
static FIOSAudioSoundBuffer* Init(FIOSAudioDevice* IOSAudioDevice, USoundWave* InWave);
/**
* Returns the size of this buffer in bytes.
*
* @return Size in bytes
*/
virtual int32 GetSize(void) override;
// These are used by the streaming engine to manage loading/unloading of chunks
virtual int32 GetCurrentChunkIndex() const override;
virtual int32 GetCurrentChunkOffset() const override;
/**
* Read the compressed info (i.e. parse header and open up a file handle) from the given sound wave.
*/
virtual bool ReadCompressedInfo(USoundWave* SoundWave) override;
/**
* Decompresses a chunk of compressed audio to the destination memory
*
* @param Destination Memory to decompress to
* @param bLooping Whether to loop the sound seamlessly, or pad with zeroes
* @return Whether the sound looped or not
*/
virtual bool ReadCompressedData( uint8* Destination, int32 NumFramesToDecode, bool bLooping ) override;
bool ReleaseCurrentChunk();
int32 RenderCallbackBufferSize;
int32 SampleRate;
int32 SoundFormat;
int16* SampleData;
uint32 BufferSize;
/** Wrapper to assist in the bookkeeping of uncompressed data when streaming */
ICompressedAudioInfo* DecompressionState;
bool bStreaming;
bool bIsProcedural;
};
/**
* IOSAudio implementation of FSoundSource, the interface used to play, stop and update sources
*/
class FIOSAudioSoundSource : public FSoundSource
{
public:
/**
* Constructor
*
* @param InAudioDevice audio device this source is attached to
*/
FIOSAudioSoundSource(FIOSAudioDevice* InAudioDevice, uint32 InBusNumber);
/**
* Destructor
*/
~FIOSAudioSoundSource(void);
/**
* Initializes a source with a given wave instance and prepares it for playback.
*
* @param WaveInstance wave instance being primed for playback
* @return true if initialization was successful, false otherwise
*/
virtual bool Init(FWaveInstance* WaveInstance) override;
/**
* Updates the source specific parameter like e.g. volume and pitch based on the associated
* wave instance.
*/
virtual void Update(void) override;
/** Plays the current wave instance. */
virtual void Play(void) override;
/** Stops the current wave instance and detaches it from the source. */
virtual void Stop(void) override;
/** Pauses playback of current wave instance. */
virtual void Pause(void) override;
/**
* Queries the status of the currently associated wave instance.
*
* @return true if the wave instance/ source has finished playback and false if it is
* currently playing or paused.
*/
virtual bool IsFinished(void) override;
/** Calculates the audio unit element of the input channel relative to the base bus number */
AudioUnitElement GetAudioUnitElement(int32 Channel);
TArray<Audio::FOnePoleLPF> LowpassFilterBank;
TArray<Audio::FParam> LPFParamBank;
int32 SampleRate;
// Cached version of Source->LPFFrequency.
float SourceLPFFrequency;
protected:
bool AttachToAUGraph();
bool DetachFromAUGraph();
FIOSAudioDevice* IOSAudioDevice;
/** Cached sound buffer associated with currently bound wave instance. */
/** Do not shadow the declaration of Buffer in the parent class since that member gets used by the streaming engine */
FIOSAudioSoundBuffer* IOSBuffer;
uint32 BusNumber;
int32 CallbackLock;
bool bChannel0Finished;
bool bAllChannelsFinished;
private:
static OSStatus IOSAudioRenderCallback(void *InRefCon, AudioUnitRenderActionFlags *IOActionFlags,
const AudioTimeStamp *InTimeStamp, UInt32 InBusNumber,
UInt32 InNumberFrames, AudioBufferList *IOData);
void CleanupAudioBuffer();
friend class FIOSAudioDevice;
};
/**
* IOSAudio implementation of an Unreal audio device.
*/
class FIOSAudioDevice : public FAudioDevice
{
public:
FIOSAudioDevice();
virtual ~FIOSAudioDevice() { }
AUGraph GetAudioUnitGraph() const { return AudioUnitGraph; }
AUNode GetMixerNode() const { return MixerNode; }
AudioUnit GetMixerUnit() const { return MixerUnit; }
AudioUnit GetOutputUnit() const { return OutputUnit; }
/** Thread context management */
virtual void ResumeContext();
virtual void SuspendContext();
virtual bool Exec( UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar = *GLog ) override;
virtual void UpdateDeviceDeltaTime() override;
static void IncrementSuspendCounter();
static void DecrementSuspendCounter();
protected:
/** Starts up any platform specific hardware/APIs */
virtual bool InitializeHardware() override;
/** Shuts down any platform specific hardware/APIs */
virtual void TeardownHardware() override;
/** Lets the platform any tick actions */
virtual void UpdateHardware() override;
/** Creates a new platform specific sound source */
virtual FAudioEffectsManager* CreateEffectsManager() override;
/** Creates a new platform specific sound source */
virtual FSoundSource* CreateSoundSource() override;
/** Audio Session management */
void GetHardwareSampleRate(double& OutSampleRate);
bool SetHardwareSampleRate(const double& InSampleRate);
bool SetAudioSessionActive(bool bActive);
/** Check if any background music or sound is playing through the audio device */
virtual bool IsExernalBackgroundSoundActive() override;
/** Retrieves the platform settings */
virtual FAudioPlatformSettings GetPlatformSettings() const override;
private:
// Used to support adpcm streaming
virtual bool HasCompressedAudioInfoClass(USoundWave* SoundWave) override { return true; }
virtual bool SupportsRealtimeDecompression() const override { return true; }
void HandleError(const TCHAR* InLogOutput, bool bTeardown = false);
AudioStreamBasicDescription MixerFormat;
AUGraph AudioUnitGraph;
AUNode OutputNode;
AudioUnit OutputUnit;
AUNode MixerNode;
AudioUnit MixerUnit;
FVector PlayerLocation;
FVector PlayerFacing;
FVector PlayerUp;
FVector PlayerRight;
int32 NextBusNumber;
friend class FIOSAudioSoundBuffer;
friend class FIOSAudioSoundSource;
};