Files
UnrealEngine/Engine/Source/Runtime/Windows/AudioMixerWasapi/Private/WasapiDefaultRenderStream.cpp
2025-05-18 13:04:45 +08:00

100 lines
2.9 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "WasapiDefaultRenderStream.h"
#include "AudioMixerWasapiLog.h"
#include "WasapiAudioUtils.h"
namespace Audio
{
bool FWasapiDefaultRenderStream::InitializeHardware(const FWasapiRenderStreamParams& InParams)
{
if (FAudioMixerWasapiRenderStream::InitializeHardware(InParams))
{
NumPartialBuffersToWrite = 1;
const uint32 MinBufferSize = GetMinimumBufferSize(InParams.SampleRate);
if (MinBufferSize > InParams.NumFrames)
{
NumPartialBuffersToWrite = FMath::DivideAndRoundUp(MinBufferSize, InParams.NumFrames);
}
WriteNumFrames = NumPartialBuffersToWrite * InParams.NumFrames;
AudioBufferTotalBytes = WriteNumFrames * AudioFormat.GetFrameSizeInBytes();
PartialBufferNumBytes = InParams.NumFrames * AudioFormat.GetFrameSizeInBytes();
return true;
}
return false;
}
bool FWasapiDefaultRenderStream::TeardownHardware()
{
ReadNextBufferDelegate.Unbind();
return FAudioMixerWasapiRenderStream::TeardownHardware();
}
void FWasapiDefaultRenderStream::DeviceRenderCallback()
{
SCOPED_NAMED_EVENT(FWasapiDefaultRenderStream_DeviceRenderCallback, FColor::Blue);
if (bIsInitialized)
{
uint32 NumFramesPadding = 0;
AudioClient->GetCurrentPadding(&NumFramesPadding);
// NumFramesPerDeviceBuffer is the buffer size WASAPI allocated. It is guaranteed to
// be at least the amount requested. For example, if we request a 1024 frame buffer, WASAPI
// might allocate a 1056 frame buffer. The padding is subtracted from the allocated amount
// to determine how much space is available currently in the buffer.
const int32 NumFramesAvailable = NumFramesPerDeviceBuffer - NumFramesPadding;
if (NumFramesAvailable >= WriteNumFrames)
{
check(RenderBufferView.IsEmpty());
uint8* BufferStartPtr = nullptr;
if (SUCCEEDED(RenderClient->GetBuffer(WriteNumFrames, &BufferStartPtr)))
{
TArrayView<uint8> BufferStartView(BufferStartPtr, AudioBufferTotalBytes);
for (int32 i = 0; i < NumPartialBuffersToWrite; ++i)
{
const SIZE_T ByteOffset = i * PartialBufferNumBytes;
RenderBufferView = BufferStartView.Slice(ByteOffset, AudioBufferTotalBytes - ByteOffset);
if (!ReadNextBufferDelegate.ExecuteIfBound())
{
++CallbackBufferErrors;
}
}
HRESULT Result = RenderClient->ReleaseBuffer(WriteNumFrames, 0 /* flags */);
if (FAILED(Result))
{
++CallbackBufferErrors;
}
RenderBufferView = TArrayView<uint8>();
}
else
{
++CallbackBufferErrors;
}
}
}
}
void FWasapiDefaultRenderStream::SubmitBuffer(const uint8* InBuffer, const SIZE_T InNumFrames)
{
if (RenderBufferView.Num() >= InNumFrames)
{
check(InNumFrames == RenderStreamParams.NumFrames);
const SIZE_T NumBytes = InNumFrames * AudioFormat.GetFrameSizeInBytes();
FMemory::Memcpy(RenderBufferView.GetData(), InBuffer, NumBytes);
}
}
}