Files
UnrealEngine/Engine/Source/Runtime/Windows/AudioMixerXAudio2/Private/AudioMixerPlatformXAudio2.h
2025-05-18 13:04:45 +08:00

204 lines
8.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "AudioMixer.h"
#include "Windows/AllowWindowsPlatformTypes.h"
// Notes on how the headers and libs are used in UE XAudio2 implementation:
// Intel Windows:
// Use the MS XAudio2.9 redist header/library/DLL to guarantee 2.9 on any Windows version
// Arm64 Windows:
// Must use the system XAudio2_9.dll. We could use the Win10 SDK's verison of xaudio2.h, however
// UE includes a copy of the DirectX SDK headers, which will interfere with finding the SDK version.
// The redist header is usable, however, even tho we are not using the redist libraries. We do not
// need to manually load the DLL because linking with the SDK arm64 .lib, without a DELAYLOAD,
// will make the OS automatically load the DLL correctly.
// Consoles:
// Similar to the Arm64 above, except the copy of DirectX SDK headers are not used, so consoles
// can use the xaudio2.h from the SDK
#define USE_REDIST_HEADER PLATFORM_WINDOWS
#define USE_REDIST_LIB PLATFORM_WINDOWS && !PLATFORM_CPU_ARM_FAMILY
#if USE_REDIST_HEADER
#include <xaudio2redist.h>
#else
#include <xaudio2.h>
#endif
#include "Windows/HideWindowsPlatformTypes.h"
#include "Async/Future.h"
#ifndef XAUDIO_SUPPORTS_DEVICE_DETAILS
#define XAUDIO_SUPPORTS_DEVICE_DETAILS 1
#endif //XAUDIO_SUPPORTS_DEVICE_DETAILS
// Any platform defines
namespace Audio
{
class FMixerPlatformXAudio2;
/**
* FXAudio2VoiceCallback
* XAudio2 implementation of IXAudio2VoiceCallback
* This callback class is used to get event notifications on buffer end (when a buffer has finished processing).
* This is used to signal the I/O thread that it can request another buffer from the user callback.
*/
class FXAudio2VoiceCallback final : public IXAudio2VoiceCallback
{
public:
FXAudio2VoiceCallback() {}
~FXAudio2VoiceCallback() {}
private:
void STDCALL OnVoiceProcessingPassStart(UINT32 BytesRequired) {}
void STDCALL OnVoiceProcessingPassEnd() {}
void STDCALL OnStreamEnd() {}
void STDCALL OnBufferStart(void* BufferContext) {}
void STDCALL OnLoopEnd(void* BufferContext) {}
void STDCALL OnVoiceError(void* BufferContext, HRESULT Error) {}
void STDCALL OnBufferEnd(void* BufferContext);
};
struct FXAudio2DeviceSwapContext : public FDeviceSwapContext
{
FXAudio2DeviceSwapContext() = delete;
FXAudio2DeviceSwapContext(const FString& InRequestedDeviceID, const FString& InReason) :
FDeviceSwapContext(InRequestedDeviceID, InReason)
{}
bool bUseDefaultDevice = false;
IXAudio2* PreviousSystem = nullptr;
IXAudio2MasteringVoice* PreviousMasteringVoice = nullptr;
IXAudio2SourceVoice* PreviousSourceVoice = nullptr;
FXAudio2VoiceCallback* Callbacks = nullptr;
uint32 RenderingSampleRate = 0;
};
struct FXAudio2DeviceSwapResult : public FDeviceSwapResult
{
virtual bool IsNewDeviceReady() const override
{
return NewSystem && NewMasteringVoice && NewSourceVoice;
}
IXAudio2* NewSystem = nullptr;
IXAudio2MasteringVoice* NewMasteringVoice = nullptr;
IXAudio2SourceVoice* NewSourceVoice = nullptr;
};
class FMixerPlatformXAudio2 : public FAudioMixerPlatformSwappable,
public IXAudio2EngineCallback
{
public:
FMixerPlatformXAudio2();
virtual ~FMixerPlatformXAudio2() override;
//~ Begin IAudioMixerPlatformInterface
virtual FString GetPlatformApi() const override { return TEXT("XAudio2"); }
virtual bool InitializeHardware() override;
virtual bool CheckAudioDeviceChange() override;
virtual bool TeardownHardware() override;
virtual bool IsInitialized() const override;
virtual bool GetNumOutputDevices(uint32& OutNumOutputDevices) override;
virtual bool GetOutputDeviceInfo(const uint32 InDeviceIndex, FAudioPlatformDeviceInfo& OutInfo) override;
virtual FString GetCurrentDeviceName() const override;
virtual bool GetDefaultOutputDeviceIndex(uint32& OutDefaultDeviceIndex) const override;
virtual bool OpenAudioStream(const FAudioMixerOpenStreamParams& Params) override;
virtual bool CloseAudioStream() override;
virtual bool StartAudioStream() override;
virtual bool StopAudioStream() override;
virtual bool MoveAudioStreamToNewAudioDevice() override;
virtual FAudioPlatformDeviceInfo GetPlatformDeviceInfo() const override;
virtual void SubmitBuffer(const uint8* Buffer) override;
virtual bool DisablePCMAudioCaching() const override;
virtual FString GetDefaultDeviceName() override;
virtual FAudioPlatformSettings GetPlatformSettings() const override;
virtual void OnHardwareUpdate() override;
virtual IAudioPlatformDeviceInfoCache* GetDeviceInfoCache() const override;
virtual bool IsDeviceInfoValid(const FAudioPlatformDeviceInfo& InDeviceInfo) const override;
virtual bool ShouldUseDeviceInfoCache() const override { return true; }
//~ End IAudioMixerPlatformInterface
//~ Begin IAudioMixerDeviceChangedListener
virtual void RegisterDeviceChangedListener() override;
virtual void UnregisterDeviceChangedListener() override;
virtual void OnDefaultCaptureDeviceChanged(const EAudioDeviceRole InAudioDeviceRole, const FString& DeviceId) override;
virtual void OnDefaultRenderDeviceChanged(const EAudioDeviceRole InAudioDeviceRole, const FString& DeviceId) override;
virtual void OnDeviceAdded(const FString& DeviceId, bool bIsRenderDevice) override;
virtual void OnDeviceRemoved(const FString& DeviceId, bool bIsRenderDevice) override;
virtual void OnDeviceStateChanged(const FString& DeviceId, const EAudioDeviceState InState, bool bIsRenderDevice) override;
virtual void OnSessionDisconnect(Audio::IAudioMixerDeviceChangedListener::EDisconnectReason InReason) override;
virtual FString GetDeviceId() const override;
//~ End IAudioMixerDeviceChangedListener
//~ Begin FAudioMixerPlatformSwappable
virtual bool InitializeDeviceSwapContext(const FString& InRequestedDeviceID, const TCHAR* InReason) override;
virtual bool CheckThreadedDeviceSwap() override;
virtual bool PreDeviceSwap() override;
virtual void EnqueueAsyncDeviceSwap() override;
virtual void SynchronousDeviceSwap() override;
virtual bool PostDeviceSwap() override;
//~ End FAudioMixerPlatformSwappable
protected:
virtual uint32 GetCreateFlags() const { return 0; }
virtual bool ShouldUseDefaultDevice() const { return false; }
static IXAudio2MasteringVoice* CreateMasteringVoice(IXAudio2& InXAudio2System, const FAudioPlatformDeviceInfo& NewDevice, bool bUseDefaultDevice);
//~ Begin IXAudio2EngineCallback
virtual void OnCriticalError(HRESULT Error) override;
virtual void OnProcessingPassStart() override;
virtual void OnProcessingPassEnd() override;
//~ End IXAudio2EngineCallback
// Used to teardown and reinitialize XAudio2.
// This must be done to repopulate the playback device list in XAudio 2.7.
bool ResetXAudio2System();
/** Can be used by subclasses to initialize a device swap context by supplying a specific
* FAudioPlatformDeviceInfo rather than looking it up via the requested device Id.
*/
bool InitDeviceSwapContextInternal(const FString& InRequestedDeviceID, const TCHAR* InReason, const TOptional<FAudioPlatformDeviceInfo>& InDeviceInfo);
// Handle to XAudio2DLL
HMODULE XAudio2Dll;
// Bool indicating that the default audio device changed
// And that we need to restart the audio device.
UE_DEPRECATED(5.6, "bDeviceChanged has been deprecated.")
FThreadSafeBool bDeviceChanged;
IXAudio2* XAudio2System;
IXAudio2MasteringVoice* OutputAudioStreamMasteringVoice;
IXAudio2SourceVoice* OutputAudioStreamSourceVoice;
FXAudio2VoiceCallback OutputVoiceCallback;
// When we are running the null device,
// we check whether a new audio device was connected every second or so.
float TimeSinceNullDeviceWasLastChecked;
bool FirstBufferSubmitted{false};
TUniquePtr<IAudioPlatformDeviceInfoCache> DeviceInfoCache;
uint32 bIsInitialized : 1;
uint32 bIsDeviceOpen : 1;
private:
/** Context object holding state used during device swap. */
TUniquePtr<FXAudio2DeviceSwapContext> DeviceSwapContext;
/** Performs a device swap with the given context. Static method enforces no other state sharing occurs. */
static TUniquePtr<FDeviceSwapResult> PerformDeviceSwap(TUniquePtr<FXAudio2DeviceSwapContext>&& InDeviceContext);
};
}