AudioCore: Refactor DSP interrupt handling (#7026)
This commit is contained in:
parent
0ce956ba00
commit
72ff0c5337
|
@ -14,7 +14,7 @@
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
namespace Service::DSP {
|
namespace Service::DSP {
|
||||||
class DSP_DSP;
|
enum class InterruptType : u32;
|
||||||
} // namespace Service::DSP
|
} // namespace Service::DSP
|
||||||
|
|
||||||
namespace AudioCore {
|
namespace AudioCore {
|
||||||
|
@ -85,8 +85,9 @@ public:
|
||||||
/// Returns a reference to the array backing DSP memory
|
/// Returns a reference to the array backing DSP memory
|
||||||
virtual std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory() = 0;
|
virtual std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory() = 0;
|
||||||
|
|
||||||
/// Sets the dsp class that we trigger interrupts for
|
/// Sets the handler for the interrupts we trigger
|
||||||
virtual void SetServiceToInterrupt(std::weak_ptr<Service::DSP::DSP_DSP> dsp) = 0;
|
virtual void SetInterruptHandler(
|
||||||
|
std::function<void(Service::DSP::InterruptType type, DspPipe pipe)> handler) = 0;
|
||||||
|
|
||||||
/// Loads the DSP program
|
/// Loads the DSP program
|
||||||
virtual void LoadComponent(std::span<const u8> buffer) = 0;
|
virtual void LoadComponent(std::span<const u8> buffer) = 0;
|
||||||
|
|
|
@ -34,8 +34,7 @@
|
||||||
|
|
||||||
SERIALIZE_EXPORT_IMPL(AudioCore::DspHle)
|
SERIALIZE_EXPORT_IMPL(AudioCore::DspHle)
|
||||||
|
|
||||||
using InterruptType = Service::DSP::DSP_DSP::InterruptType;
|
using InterruptType = Service::DSP::InterruptType;
|
||||||
using Service::DSP::DSP_DSP;
|
|
||||||
|
|
||||||
namespace AudioCore {
|
namespace AudioCore {
|
||||||
|
|
||||||
|
@ -71,7 +70,8 @@ public:
|
||||||
|
|
||||||
std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory();
|
std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory();
|
||||||
|
|
||||||
void SetServiceToInterrupt(std::weak_ptr<DSP_DSP> dsp);
|
void SetInterruptHandler(
|
||||||
|
std::function<void(Service::DSP::InterruptType type, DspPipe pipe)> handler);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ResetPipes();
|
void ResetPipes();
|
||||||
|
@ -105,7 +105,7 @@ private:
|
||||||
|
|
||||||
std::unique_ptr<HLE::DecoderBase> decoder{};
|
std::unique_ptr<HLE::DecoderBase> decoder{};
|
||||||
|
|
||||||
std::weak_ptr<DSP_DSP> dsp_dsp{};
|
std::function<void(Service::DSP::InterruptType type, DspPipe pipe)> interrupt_handler{};
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
void serialize(Archive& ar, const unsigned int) {
|
void serialize(Archive& ar, const unsigned int) {
|
||||||
|
@ -114,7 +114,8 @@ private:
|
||||||
ar& dsp_memory.raw_memory;
|
ar& dsp_memory.raw_memory;
|
||||||
ar& sources;
|
ar& sources;
|
||||||
ar& mixers;
|
ar& mixers;
|
||||||
ar& dsp_dsp;
|
// interrupt_handler is function pointer and cant be serialised, fortunately though, it
|
||||||
|
// should be registerd before the game has started
|
||||||
}
|
}
|
||||||
friend class boost::serialization::access;
|
friend class boost::serialization::access;
|
||||||
};
|
};
|
||||||
|
@ -320,10 +321,8 @@ void DspHle::Impl::PipeWrite(DspPipe pipe_number, std::span<const u8> buffer) {
|
||||||
pipe_data[static_cast<u32>(pipe_number)].resize(sizeof(value));
|
pipe_data[static_cast<u32>(pipe_number)].resize(sizeof(value));
|
||||||
std::memcpy(pipe_data[static_cast<u32>(pipe_number)].data(), &value, sizeof(value));
|
std::memcpy(pipe_data[static_cast<u32>(pipe_number)].data(), &value, sizeof(value));
|
||||||
}
|
}
|
||||||
auto dsp = dsp_dsp.lock();
|
|
||||||
if (dsp) {
|
interrupt_handler(InterruptType::Pipe, DspPipe::Binary);
|
||||||
dsp->SignalInterrupt(InterruptType::Pipe, DspPipe::Binary);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -338,8 +337,9 @@ std::array<u8, Memory::DSP_RAM_SIZE>& DspHle::Impl::GetDspMemory() {
|
||||||
return dsp_memory.raw_memory;
|
return dsp_memory.raw_memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DspHle::Impl::SetServiceToInterrupt(std::weak_ptr<DSP_DSP> dsp) {
|
void DspHle::Impl::SetInterruptHandler(
|
||||||
dsp_dsp = std::move(dsp);
|
std::function<void(Service::DSP::InterruptType type, DspPipe pipe)> handler) {
|
||||||
|
interrupt_handler = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DspHle::Impl::ResetPipes() {
|
void DspHle::Impl::ResetPipes() {
|
||||||
|
@ -386,9 +386,7 @@ void DspHle::Impl::AudioPipeWriteStructAddresses() {
|
||||||
WriteU16(DspPipe::Audio, addr);
|
WriteU16(DspPipe::Audio, addr);
|
||||||
}
|
}
|
||||||
// Signal that we have data on this pipe.
|
// Signal that we have data on this pipe.
|
||||||
if (auto service = dsp_dsp.lock()) {
|
interrupt_handler(InterruptType::Pipe, DspPipe::Audio);
|
||||||
service->SignalInterrupt(InterruptType::Pipe, DspPipe::Audio);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t DspHle::Impl::CurrentRegionIndex() const {
|
size_t DspHle::Impl::CurrentRegionIndex() const {
|
||||||
|
@ -464,9 +462,7 @@ bool DspHle::Impl::Tick() {
|
||||||
void DspHle::Impl::AudioTickCallback(s64 cycles_late) {
|
void DspHle::Impl::AudioTickCallback(s64 cycles_late) {
|
||||||
if (Tick()) {
|
if (Tick()) {
|
||||||
// TODO(merry): Signal all the other interrupts as appropriate.
|
// TODO(merry): Signal all the other interrupts as appropriate.
|
||||||
if (auto service = dsp_dsp.lock()) {
|
interrupt_handler(InterruptType::Pipe, DspPipe::Audio);
|
||||||
service->SignalInterrupt(InterruptType::Pipe, DspPipe::Audio);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reschedule recurrent event
|
// Reschedule recurrent event
|
||||||
|
@ -505,9 +501,10 @@ std::array<u8, Memory::DSP_RAM_SIZE>& DspHle::GetDspMemory() {
|
||||||
return impl->GetDspMemory();
|
return impl->GetDspMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DspHle::SetServiceToInterrupt(std::weak_ptr<DSP_DSP> dsp) {
|
void DspHle::SetInterruptHandler(
|
||||||
impl->SetServiceToInterrupt(std::move(dsp));
|
std::function<void(Service::DSP::InterruptType type, DspPipe pipe)> handler) {
|
||||||
}
|
impl->SetInterruptHandler(handler);
|
||||||
|
};
|
||||||
|
|
||||||
void DspHle::LoadComponent(std::span<const u8> component_data) {
|
void DspHle::LoadComponent(std::span<const u8> component_data) {
|
||||||
// HLE doesn't need DSP program. Only log some info here
|
// HLE doesn't need DSP program. Only log some info here
|
||||||
|
|
|
@ -34,7 +34,8 @@ public:
|
||||||
|
|
||||||
std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory() override;
|
std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory() override;
|
||||||
|
|
||||||
void SetServiceToInterrupt(std::weak_ptr<Service::DSP::DSP_DSP> dsp) override;
|
void SetInterruptHandler(
|
||||||
|
std::function<void(Service::DSP::InterruptType type, DspPipe pipe)> handler) override;
|
||||||
|
|
||||||
void LoadComponent(std::span<const u8> buffer) override;
|
void LoadComponent(std::span<const u8> buffer) override;
|
||||||
void UnloadComponent() override;
|
void UnloadComponent() override;
|
||||||
|
|
|
@ -408,29 +408,24 @@ std::array<u8, Memory::DSP_RAM_SIZE>& DspLle::GetDspMemory() {
|
||||||
return impl->teakra.GetDspMemory();
|
return impl->teakra.GetDspMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DspLle::SetServiceToInterrupt(std::weak_ptr<Service::DSP::DSP_DSP> dsp) {
|
void DspLle::SetInterruptHandler(
|
||||||
impl->teakra.SetRecvDataHandler(0, [this, dsp]() {
|
std::function<void(Service::DSP::InterruptType type, DspPipe pipe)> handler) {
|
||||||
|
impl->teakra.SetRecvDataHandler(0, [this, handler]() {
|
||||||
if (!impl->loaded)
|
if (!impl->loaded)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::lock_guard lock(HLE::g_hle_lock);
|
std::lock_guard lock(HLE::g_hle_lock);
|
||||||
if (auto locked = dsp.lock()) {
|
handler(Service::DSP::InterruptType::Zero, static_cast<DspPipe>(0));
|
||||||
locked->SignalInterrupt(Service::DSP::DSP_DSP::InterruptType::Zero,
|
|
||||||
static_cast<DspPipe>(0));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
impl->teakra.SetRecvDataHandler(1, [this, dsp]() {
|
impl->teakra.SetRecvDataHandler(1, [this, handler]() {
|
||||||
if (!impl->loaded)
|
if (!impl->loaded)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::lock_guard lock(HLE::g_hle_lock);
|
std::lock_guard lock(HLE::g_hle_lock);
|
||||||
if (auto locked = dsp.lock()) {
|
handler(Service::DSP::InterruptType::One, static_cast<DspPipe>(0));
|
||||||
locked->SignalInterrupt(Service::DSP::DSP_DSP::InterruptType::One,
|
|
||||||
static_cast<DspPipe>(0));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
auto ProcessPipeEvent = [this, dsp](bool event_from_data) {
|
auto ProcessPipeEvent = [this, handler](bool event_from_data) {
|
||||||
if (!impl->loaded)
|
if (!impl->loaded)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -456,10 +451,7 @@ void DspLle::SetServiceToInterrupt(std::weak_ptr<Service::DSP::DSP_DSP> dsp) {
|
||||||
impl->GetPipeReadableSize(static_cast<u8>(pipe)));
|
impl->GetPipeReadableSize(static_cast<u8>(pipe)));
|
||||||
} else {
|
} else {
|
||||||
std::lock_guard lock(HLE::g_hle_lock);
|
std::lock_guard lock(HLE::g_hle_lock);
|
||||||
if (auto locked = dsp.lock()) {
|
handler(Service::DSP::InterruptType::Pipe, static_cast<DspPipe>(pipe));
|
||||||
locked->SignalInterrupt(Service::DSP::DSP_DSP::InterruptType::Pipe,
|
|
||||||
static_cast<DspPipe>(pipe));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -468,14 +460,6 @@ void DspLle::SetServiceToInterrupt(std::weak_ptr<Service::DSP::DSP_DSP> dsp) {
|
||||||
impl->teakra.SetSemaphoreHandler([ProcessPipeEvent]() { ProcessPipeEvent(false); });
|
impl->teakra.SetSemaphoreHandler([ProcessPipeEvent]() { ProcessPipeEvent(false); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void DspLle::SetSemaphoreHandler(std::function<void()> handler) {
|
|
||||||
impl->teakra.SetSemaphoreHandler(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DspLle::SetRecvDataHandler(u8 index, std::function<void()> handler) {
|
|
||||||
impl->teakra.SetRecvDataHandler(index, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DspLle::LoadComponent(std::span<const u8> buffer) {
|
void DspLle::LoadComponent(std::span<const u8> buffer) {
|
||||||
impl->LoadComponent(buffer);
|
impl->LoadComponent(buffer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,10 +27,8 @@ public:
|
||||||
|
|
||||||
std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory() override;
|
std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory() override;
|
||||||
|
|
||||||
void SetServiceToInterrupt(std::weak_ptr<Service::DSP::DSP_DSP> dsp) override;
|
void SetInterruptHandler(
|
||||||
|
std::function<void(Service::DSP::InterruptType type, DspPipe pipe)> handler) override;
|
||||||
void SetSemaphoreHandler(std::function<void()> handler);
|
|
||||||
void SetRecvDataHandler(u8 index, std::function<void()> handler);
|
|
||||||
|
|
||||||
void LoadComponent(const std::span<const u8> buffer) override;
|
void LoadComponent(const std::span<const u8> buffer) override;
|
||||||
void UnloadComponent() override;
|
void UnloadComponent() override;
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include "core/hle/service/dsp/dsp_dsp.h"
|
#include "core/hle/service/dsp/dsp_dsp.h"
|
||||||
|
|
||||||
using DspPipe = AudioCore::DspPipe;
|
using DspPipe = AudioCore::DspPipe;
|
||||||
using InterruptType = Service::DSP::DSP_DSP::InterruptType;
|
using InterruptType = Service::DSP::InterruptType;
|
||||||
|
|
||||||
SERIALIZE_EXPORT_IMPL(Service::DSP::DSP_DSP)
|
SERIALIZE_EXPORT_IMPL(Service::DSP::DSP_DSP)
|
||||||
SERVICE_CONSTRUCT_IMPL(Service::DSP::DSP_DSP)
|
SERVICE_CONSTRUCT_IMPL(Service::DSP::DSP_DSP)
|
||||||
|
@ -235,7 +235,8 @@ void DSP_DSP::RegisterInterruptEvents(Kernel::HLERequestContext& ctx) {
|
||||||
const u32 channel = rp.Pop<u32>();
|
const u32 channel = rp.Pop<u32>();
|
||||||
auto event = rp.PopObject<Kernel::Event>();
|
auto event = rp.PopObject<Kernel::Event>();
|
||||||
|
|
||||||
ASSERT_MSG(interrupt < NUM_INTERRUPT_TYPE && channel < AudioCore::num_dsp_pipe,
|
ASSERT_MSG(interrupt < static_cast<u32>(InterruptType::Count) &&
|
||||||
|
channel < AudioCore::num_dsp_pipe,
|
||||||
"Invalid type or pipe: interrupt = {}, channel = {}", interrupt, channel);
|
"Invalid type or pipe: interrupt = {}, channel = {}", interrupt, channel);
|
||||||
|
|
||||||
const InterruptType type = static_cast<InterruptType>(interrupt);
|
const InterruptType type = static_cast<InterruptType>(interrupt);
|
||||||
|
@ -326,6 +327,9 @@ std::shared_ptr<Kernel::Event>& DSP_DSP::GetInterruptEvent(InterruptType type, D
|
||||||
ASSERT(pipe_index < AudioCore::num_dsp_pipe);
|
ASSERT(pipe_index < AudioCore::num_dsp_pipe);
|
||||||
return pipes[pipe_index];
|
return pipes[pipe_index];
|
||||||
}
|
}
|
||||||
|
case InterruptType::Count:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
UNREACHABLE_MSG("Invalid interrupt type = {}", type);
|
UNREACHABLE_MSG("Invalid interrupt type = {}", type);
|
||||||
}
|
}
|
||||||
|
@ -401,7 +405,12 @@ void InstallInterfaces(Core::System& system) {
|
||||||
auto& service_manager = system.ServiceManager();
|
auto& service_manager = system.ServiceManager();
|
||||||
auto dsp = std::make_shared<DSP_DSP>(system);
|
auto dsp = std::make_shared<DSP_DSP>(system);
|
||||||
dsp->InstallAsService(service_manager);
|
dsp->InstallAsService(service_manager);
|
||||||
system.DSP().SetServiceToInterrupt(std::move(dsp));
|
system.DSP().SetInterruptHandler(
|
||||||
|
[dsp_ref = std::weak_ptr<DSP_DSP>(dsp)](InterruptType type, DspPipe pipe) {
|
||||||
|
if (auto locked = dsp_ref.lock()) {
|
||||||
|
locked->SignalInterrupt(type, pipe);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::DSP
|
} // namespace Service::DSP
|
||||||
|
|
|
@ -19,15 +19,14 @@ class System;
|
||||||
|
|
||||||
namespace Service::DSP {
|
namespace Service::DSP {
|
||||||
|
|
||||||
|
/// There are three types of interrupts
|
||||||
|
enum class InterruptType : u32 { Zero = 0, One = 1, Pipe = 2, Count };
|
||||||
|
|
||||||
class DSP_DSP final : public ServiceFramework<DSP_DSP> {
|
class DSP_DSP final : public ServiceFramework<DSP_DSP> {
|
||||||
public:
|
public:
|
||||||
explicit DSP_DSP(Core::System& system);
|
explicit DSP_DSP(Core::System& system);
|
||||||
~DSP_DSP();
|
~DSP_DSP();
|
||||||
|
|
||||||
/// There are three types of interrupts
|
|
||||||
static constexpr std::size_t NUM_INTERRUPT_TYPE = 3;
|
|
||||||
enum class InterruptType : u32 { Zero = 0, One = 1, Pipe = 2 };
|
|
||||||
|
|
||||||
/// Actual service implementation only has 6 'slots' for interrupts.
|
/// Actual service implementation only has 6 'slots' for interrupts.
|
||||||
static constexpr std::size_t max_number_of_interrupt_events = 6;
|
static constexpr std::size_t max_number_of_interrupt_events = 6;
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ TEST_CASE("DSP LLE vs HLE", "[audio_core][hle]") {
|
||||||
AudioCore::DspHle hle(hle_memory, hle_core_timing);
|
AudioCore::DspHle hle(hle_memory, hle_core_timing);
|
||||||
AudioCore::DspLle lle(lle_memory, lle_core_timing, true);
|
AudioCore::DspLle lle(lle_memory, lle_core_timing, true);
|
||||||
|
|
||||||
// Initialiase LLE
|
// Initialise LLE
|
||||||
{
|
{
|
||||||
FileUtil::SetUserPath();
|
FileUtil::SetUserPath();
|
||||||
// see tests/audio_core/lle/lle.cpp for details on dspaudio.cdc
|
// see tests/audio_core/lle/lle.cpp for details on dspaudio.cdc
|
||||||
|
@ -41,25 +41,15 @@ TEST_CASE("DSP LLE vs HLE", "[audio_core][hle]") {
|
||||||
std::vector<u8> firm_file_buf(firm_file.GetSize());
|
std::vector<u8> firm_file_buf(firm_file.GetSize());
|
||||||
firm_file.ReadArray(firm_file_buf.data(), firm_file_buf.size());
|
firm_file.ReadArray(firm_file_buf.data(), firm_file_buf.size());
|
||||||
lle.LoadComponent(firm_file_buf);
|
lle.LoadComponent(firm_file_buf);
|
||||||
lle.SetSemaphoreHandler([&lle]() {
|
lle.SetInterruptHandler([](Service::DSP::InterruptType type, AudioCore::DspPipe pipe) {
|
||||||
u16 slot = lle.RecvData(2);
|
fmt::print("LLE SetInterruptHandler type={} pipe={}\n", type, pipe);
|
||||||
u16 side = slot % 2;
|
});
|
||||||
u16 pipe = slot / 2;
|
}
|
||||||
fmt::print("SetSemaphoreHandler slot={}\n", slot);
|
// Initialise HLE
|
||||||
if (pipe > 15)
|
{
|
||||||
return;
|
hle.SetInterruptHandler([](Service::DSP::InterruptType type, AudioCore::DspPipe pipe) {
|
||||||
if (side != 0)
|
fmt::print("HLE SetInterruptHandler type={} pipe={}\n", type, pipe);
|
||||||
return;
|
|
||||||
if (pipe == 0) {
|
|
||||||
// pipe 0 is for debug. 3DS automatically drains this pipe and discards the
|
|
||||||
// data
|
|
||||||
lle.PipeRead(static_cast<AudioCore::DspPipe>(pipe),
|
|
||||||
lle.GetPipeReadableSize(static_cast<AudioCore::DspPipe>(pipe)));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
lle.SetRecvDataHandler(0, []() { fmt::print("SetRecvDataHandler 0\n"); });
|
|
||||||
lle.SetRecvDataHandler(1, []() { fmt::print("SetRecvDataHandler 1\n"); });
|
|
||||||
lle.SetRecvDataHandler(2, []() { fmt::print("SetRecvDataHandler 2\n"); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Initialise Audio Pipe") {
|
SECTION("Initialise Audio Pipe") {
|
||||||
|
|
|
@ -37,26 +37,11 @@ TEST_CASE("DSP LLE Sanity", "[audio_core][lle]") {
|
||||||
std::vector<u8> firm_file_buf(firm_file.GetSize());
|
std::vector<u8> firm_file_buf(firm_file.GetSize());
|
||||||
firm_file.ReadArray(firm_file_buf.data(), firm_file_buf.size());
|
firm_file.ReadArray(firm_file_buf.data(), firm_file_buf.size());
|
||||||
lle.LoadComponent(firm_file_buf);
|
lle.LoadComponent(firm_file_buf);
|
||||||
}
|
|
||||||
lle.SetSemaphoreHandler([&lle]() {
|
lle.SetInterruptHandler([](Service::DSP::InterruptType type, AudioCore::DspPipe pipe) {
|
||||||
u16 slot = lle.RecvData(2);
|
fmt::print("SetInterruptHandler type={} pipe={}\n", type, pipe);
|
||||||
u16 side = slot % 2;
|
|
||||||
u16 pipe = slot / 2;
|
|
||||||
fmt::print("SetSemaphoreHandler slot={}\n", slot);
|
|
||||||
if (pipe > 15)
|
|
||||||
return;
|
|
||||||
if (side != 0)
|
|
||||||
return;
|
|
||||||
if (pipe == 0) {
|
|
||||||
// pipe 0 is for debug. 3DS automatically drains this pipe and discards the
|
|
||||||
// data
|
|
||||||
lle.PipeRead(static_cast<AudioCore::DspPipe>(pipe),
|
|
||||||
lle.GetPipeReadableSize(static_cast<AudioCore::DspPipe>(pipe)));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
lle.SetRecvDataHandler(0, []() { fmt::print("SetRecvDataHandler 0\n"); });
|
}
|
||||||
lle.SetRecvDataHandler(1, []() { fmt::print("SetRecvDataHandler 1\n"); });
|
|
||||||
lle.SetRecvDataHandler(2, []() { fmt::print("SetRecvDataHandler 2\n"); });
|
|
||||||
SECTION("Initialise Audio Pipe") {
|
SECTION("Initialise Audio Pipe") {
|
||||||
std::vector<u8> buffer(4, 0);
|
std::vector<u8> buffer(4, 0);
|
||||||
buffer[0] = 0;
|
buffer[0] = 0;
|
||||||
|
|
Loading…
Reference in New Issue