From b5e95f5ff7f4606ff882e333a22605986d475991 Mon Sep 17 00:00:00 2001 From: Gliniak Date: Sat, 30 Jul 2022 10:35:32 +0200 Subject: [PATCH] Initial files related to microphone support --- premake5.lua | 2 + src/xenia/app/premake5.lua | 2 + src/xenia/app/xenia_main.cc | 29 ++++- src/xenia/emulator.cc | 31 ++++- src/xenia/emulator.h | 12 +- src/xenia/gpu/trace_dump.cc | 2 +- src/xenia/gpu/trace_viewer.cc | 2 +- src/xenia/hid/controller/hid_demo.cc | 4 +- src/xenia/hid/controller/sdl/sdl_hid.cc | 2 + src/xenia/hid/controller/sdl/sdl_hid.h | 3 +- src/xenia/hid/microphone/microphone.h | 59 +++++++++ src/xenia/hid/microphone/microphone_driver.h | 48 ++++++++ src/xenia/hid/microphone/microphone_system.cc | 76 ++++++++++++ src/xenia/hid/microphone/microphone_system.h | 41 +++++++ src/xenia/hid/microphone/premake5.lua | 14 +++ src/xenia/hid/microphone/sdl/premake5.lua | 17 +++ src/xenia/hid/microphone/sdl/sdl_hid.cc | 26 ++++ src/xenia/hid/microphone/sdl/sdl_hid.h | 30 +++++ .../microphone/sdl/sdl_microphone_driver.cc | 116 ++++++++++++++++++ .../microphone/sdl/sdl_microphone_driver.h | 43 +++++++ src/xenia/kernel/premake5.lua | 1 + src/xenia/kernel/xam/xam_input.cc | 7 +- src/xenia/kernel/xboxkrnl/xboxkrnl_misc.cc | 67 ++++++++++ src/xenia/xbox.h | 1 + 24 files changed, 624 insertions(+), 11 deletions(-) create mode 100644 src/xenia/hid/microphone/microphone.h create mode 100644 src/xenia/hid/microphone/microphone_driver.h create mode 100644 src/xenia/hid/microphone/microphone_system.cc create mode 100644 src/xenia/hid/microphone/microphone_system.h create mode 100644 src/xenia/hid/microphone/premake5.lua create mode 100644 src/xenia/hid/microphone/sdl/premake5.lua create mode 100644 src/xenia/hid/microphone/sdl/sdl_hid.cc create mode 100644 src/xenia/hid/microphone/sdl/sdl_hid.h create mode 100644 src/xenia/hid/microphone/sdl/sdl_microphone_driver.cc create mode 100644 src/xenia/hid/microphone/sdl/sdl_microphone_driver.h diff --git a/premake5.lua b/premake5.lua index 21da4cc17a..bfacba35d6 100644 --- a/premake5.lua +++ b/premake5.lua @@ -291,6 +291,7 @@ workspace("xenia") include("src/xenia/gpu/vulkan") include("src/xenia/hid/controller") include("src/xenia/hid/controller/nop") + include("src/xenia/hid/microphone") include("src/xenia/kernel") include("src/xenia/ui") include("src/xenia/ui/vulkan") @@ -300,6 +301,7 @@ workspace("xenia") include("src/xenia/apu/sdl") include("src/xenia/helper/sdl") include("src/xenia/hid/controller/sdl") + include("src/xenia/hid/microphone/sdl") end if os.istarget("windows") then diff --git a/src/xenia/app/premake5.lua b/src/xenia/app/premake5.lua index 02b183511d..2e0aacea9e 100644 --- a/src/xenia/app/premake5.lua +++ b/src/xenia/app/premake5.lua @@ -16,6 +16,7 @@ project("xenia-app") "xenia-gpu-vulkan", "xenia-hid-controller", "xenia-hid-controller-nop", + "xenia-hid-microphone", "xenia-kernel", "xenia-ui", "xenia-ui-vulkan", @@ -94,6 +95,7 @@ project("xenia-app") "xenia-debug-ui", "xenia-helper-sdl", "xenia-hid-controller-sdl", + "xenia-hid-microphone-sdl", }) filter("platforms:Linux") diff --git a/src/xenia/app/xenia_main.cc b/src/xenia/app/xenia_main.cc index c3312ae1fd..1070e4b963 100644 --- a/src/xenia/app/xenia_main.cc +++ b/src/xenia/app/xenia_main.cc @@ -54,6 +54,7 @@ #include "xenia/hid/controller/nop/nop_hid.h" #if !XE_PLATFORM_ANDROID #include "xenia/hid/controller/sdl/sdl_hid.h" +#include "xenia/hid/microphone/sdl/sdl_hid.h" #endif // !XE_PLATFORM_ANDROID #if XE_PLATFORM_WIN32 #include "xenia/hid/controller/winkey/winkey_hid.h" @@ -214,6 +215,8 @@ class EmulatorApp final : public xe::ui::WindowedApp { static std::unique_ptr CreateGraphicsSystem(); static std::vector> CreateInputDrivers( ui::Window* window); + static std::vector> + CreateMicrophoneDrivers(); void EmulatorThread(); void ShutdownEmulatorThreadFromUIThread(); @@ -357,7 +360,7 @@ std::vector> EmulatorApp::CreateInputDrivers( factory.Add("xinput", xe::hid::xinput::Create); #endif // XE_PLATFORM_WIN32 #if !XE_PLATFORM_ANDROID - factory.Add("sdl", xe::hid::sdl::Create); + factory.Add("sdl", xe::hid::sdl::controller::Create); #endif // !XE_PLATFORM_ANDROID #if XE_PLATFORM_WIN32 // WinKey input driver should always be the last input driver added! @@ -378,6 +381,27 @@ std::vector> EmulatorApp::CreateInputDrivers( return drivers; } +std::vector> +EmulatorApp::CreateMicrophoneDrivers() { + std::vector> drivers; + Factory factory; + #if !XE_PLATFORM_ANDROID + factory.Add("sdl", xe::hid::microphone::sdl::Create); + #endif // !XE_PLATFORM_ANDROID + for (auto& driver : + factory.CreateAll("sdl")) { + if (XSUCCEEDED(driver->Setup())) { + drivers.emplace_back(std::move(driver)); + } + } + if (drivers.empty()) { + // Fallback to nop if none created. + //drivers.emplace_back( + // xe::hid::nop::Create(window, EmulatorWindow::kZOrderHidInput)); + } + return drivers; +} + bool EmulatorApp::OnInitialize() { Profiler::Initialize(); Profiler::ThreadEnter("Main"); @@ -486,7 +510,8 @@ void EmulatorApp::EmulatorThread() { // (unsupported system, memory issues, etc) this will fail early. X_STATUS result = emulator_->Setup( emulator_window_->window(), emulator_window_->imgui_drawer(), true, - CreateAudioSystem, CreateGraphicsSystem, CreateInputDrivers); + CreateAudioSystem, CreateGraphicsSystem, CreateInputDrivers, + CreateMicrophoneDrivers); if (XFAILED(result)) { XELOGE("Failed to setup emulator: {:08X}", result); app_context().RequestDeferredQuit(); diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index f8a6aa3508..a1af862134 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -33,6 +33,8 @@ #include "xenia/gpu/graphics_system.h" #include "xenia/hid/controller/input_driver.h" #include "xenia/hid/controller/input_system.h" +#include "xenia/hid/microphone/microphone_driver.h" +#include "xenia/hid/microphone/microphone_system.h" #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/user_module.h" #include "xenia/kernel/util/gameinfo_utils.h" @@ -96,6 +98,7 @@ Emulator::Emulator(const std::filesystem::path& command_line, audio_system_(), graphics_system_(), input_system_(), + microphone_system_(), export_resolver_(), file_system_(), kernel_state_(), @@ -119,6 +122,7 @@ Emulator::~Emulator() { input_system_.reset(); graphics_system_.reset(); audio_system_.reset(); + microphone_system_.reset(); kernel_state_.reset(); file_system_.reset(); @@ -138,7 +142,9 @@ X_STATUS Emulator::Setup( std::function()> graphics_system_factory, std::function>(ui::Window*)> - input_driver_factory) { + input_driver_factory, + std::function>()> + microphone_driver_factory) { X_STATUS result = X_STATUS_UNSUCCESSFUL; display_window_ = display_window; @@ -203,7 +209,7 @@ X_STATUS Emulator::Setup( return X_STATUS_NOT_IMPLEMENTED; } - // Initialize the HID. + // Initialize the HID controller. input_system_ = std::make_unique(display_window_); if (!input_system_) { return X_STATUS_NOT_IMPLEMENTED; @@ -223,6 +229,27 @@ X_STATUS Emulator::Setup( return result; } + // Initialize the HID microphone + microphone_system_ = std::make_unique(); + + if (!microphone_system_) { + return X_STATUS_NOT_IMPLEMENTED; + } + if (microphone_driver_factory) { + auto input_drivers = microphone_driver_factory(); + for (size_t i = 0; i < input_drivers.size(); ++i) { + auto& input_driver = input_drivers[i]; + input_driver->set_is_active_callback( + []() -> bool { return !xe::kernel::xam::xeXamIsUIActive(); }); + microphone_system_->AddDriver(std::move(input_driver)); + } + } + + result = microphone_system_->Setup(); + if (result) { + return result; + } + // Bring up the virtual filesystem used by the kernel. file_system_ = std::make_unique(); diff --git a/src/xenia/emulator.h b/src/xenia/emulator.h index a0dbeff252..439e7c22dc 100644 --- a/src/xenia/emulator.h +++ b/src/xenia/emulator.h @@ -39,6 +39,8 @@ class GraphicsSystem; namespace hid { class InputDriver; class InputSystem; +class MicrophoneDriver; +class MicrophoneSystem; } // namespace hid namespace ui { class ImGuiDrawer; @@ -142,6 +144,11 @@ class Emulator { // Human-interface Device (HID) adapters for controllers. hid::InputSystem* input_system() const { return input_system_.get(); } + // Human-interface Device (HID) adapters for microphones + hid::MicrophoneSystem* microphone_system() const { + return microphone_system_.get(); + } + // Kernel function export table used to resolve exports when JITing code. cpu::ExportResolver* export_resolver() const { return export_resolver_.get(); @@ -167,7 +174,9 @@ class Emulator { std::function()> graphics_system_factory, std::function>(ui::Window*)> - input_driver_factory); + input_driver_factory, + std::function>()> + microphone_driver_factory); // Terminates the currently running title. X_STATUS TerminateTitle(); @@ -235,6 +244,7 @@ class Emulator { std::unique_ptr audio_system_; std::unique_ptr graphics_system_; std::unique_ptr input_system_; + std::unique_ptr microphone_system_; std::unique_ptr export_resolver_; std::unique_ptr file_system_; diff --git a/src/xenia/gpu/trace_dump.cc b/src/xenia/gpu/trace_dump.cc index 4cf774c42e..21061d1edc 100644 --- a/src/xenia/gpu/trace_dump.cc +++ b/src/xenia/gpu/trace_dump.cc @@ -97,7 +97,7 @@ bool TraceDump::Setup() { emulator_ = std::make_unique("", "", "", ""); X_STATUS result = emulator_->Setup( nullptr, nullptr, false, nullptr, - [this]() { return CreateGraphicsSystem(); }, nullptr); + [this]() { return CreateGraphicsSystem(); }, nullptr, nullptr); if (XFAILED(result)) { XELOGE("Failed to setup emulator: {:08X}", result); return false; diff --git a/src/xenia/gpu/trace_viewer.cc b/src/xenia/gpu/trace_viewer.cc index 0d43b0a5e5..5875ec8e6c 100644 --- a/src/xenia/gpu/trace_viewer.cc +++ b/src/xenia/gpu/trace_viewer.cc @@ -132,7 +132,7 @@ bool TraceViewer::Setup() { emulator_ = std::make_unique("", "", "", ""); X_STATUS result = emulator_->Setup( window_.get(), nullptr, false, nullptr, - [this]() { return CreateGraphicsSystem(); }, nullptr); + [this]() { return CreateGraphicsSystem(); }, nullptr, nullptr); if (XFAILED(result)) { XELOGE("Failed to setup emulator: {:08X}", result); return false; diff --git a/src/xenia/hid/controller/hid_demo.cc b/src/xenia/hid/controller/hid_demo.cc index 648170a4a9..3c3e3403b9 100644 --- a/src/xenia/hid/controller/hid_demo.cc +++ b/src/xenia/hid/controller/hid_demo.cc @@ -127,7 +127,7 @@ std::vector> HidDemoApp::CreateInputDrivers( drivers.emplace_back(xe::hid::nop::Create(window, kZOrderHidInput)); #if !XE_PLATFORM_ANDROID } else if (cvars::hid.compare("sdl") == 0) { - auto driver = xe::hid::sdl::Create(window, kZOrderHidInput); + auto driver = xe::hid::sdl::controller::Create(window, kZOrderHidInput); if (XSUCCEEDED(driver->Setup())) { drivers.emplace_back(std::move(driver)); } @@ -146,7 +146,7 @@ std::vector> HidDemoApp::CreateInputDrivers( #endif // XE_PLATFORM_WIN32 } else { #if !XE_PLATFORM_ANDROID - auto sdl_driver = xe::hid::sdl::Create(window, kZOrderHidInput); + auto sdl_driver = xe::hid::sdl::controller::Create(window, kZOrderHidInput); if (sdl_driver && XSUCCEEDED(sdl_driver->Setup())) { drivers.emplace_back(std::move(sdl_driver)); } diff --git a/src/xenia/hid/controller/sdl/sdl_hid.cc b/src/xenia/hid/controller/sdl/sdl_hid.cc index 9521829ab6..b8c5ff9ed7 100644 --- a/src/xenia/hid/controller/sdl/sdl_hid.cc +++ b/src/xenia/hid/controller/sdl/sdl_hid.cc @@ -14,12 +14,14 @@ namespace xe { namespace hid { namespace sdl { +namespace controller { std::unique_ptr Create(xe::ui::Window* window, size_t window_z_order) { return std::make_unique(window, window_z_order); } +} // namespace controller } // namespace sdl } // namespace hid } // namespace xe diff --git a/src/xenia/hid/controller/sdl/sdl_hid.h b/src/xenia/hid/controller/sdl/sdl_hid.h index 742c77dfb0..6afdc69035 100644 --- a/src/xenia/hid/controller/sdl/sdl_hid.h +++ b/src/xenia/hid/controller/sdl/sdl_hid.h @@ -17,10 +17,11 @@ namespace xe { namespace hid { namespace sdl { +namespace controller { std::unique_ptr Create(xe::ui::Window* window, size_t window_z_order); - +} // namespace controller } // namespace sdl } // namespace hid } // namespace xe diff --git a/src/xenia/hid/microphone/microphone.h b/src/xenia/hid/microphone/microphone.h new file mode 100644 index 0000000000..6a4593bc9f --- /dev/null +++ b/src/xenia/hid/microphone/microphone.h @@ -0,0 +1,59 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2022 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#pragma once + +#include "xenia/base/assert.h" +#include "xenia/base/byte_order.h" + +namespace xe { +namespace hid { + +/* States of microphone + 0 - Not connected + 1 - Connected, not initialized for user_index 0 + 2 - Connected, not initialized for user_index 1 + 3 - Connected, not initialized for user_index 2 + 4 - Connected, not initialized for user_index 3 + 5 - Ready (for user_index 0?) +*/ + +typedef struct { + xe::be request_type; + xe::be user_index; + xe::be state; // 8 + + xe::be unk1; // 16 + xe::be unk2; // 24 +} XMICINFO; + +typedef struct { + xe::be features; + xe::be format_tag; + xe::be channels; + xe::be sample_rates; + xe::be bits_per_sample; + xe::be frame_length; // 0xE + xe::be mic_color; // 0x10 + xe::be vendor_id; + xe::be product_id; + xe::be revision; + xe::be device_id; + +} XMICCAPABILITIES; +static_assert_size(XMICCAPABILITIES, 0x1C); + +typedef struct { + XMICINFO info; + XMICCAPABILITIES capabilities; + +} X_MIC_DEVICE; + +} // namespace hid +} // namespace xe \ No newline at end of file diff --git a/src/xenia/hid/microphone/microphone_driver.h b/src/xenia/hid/microphone/microphone_driver.h new file mode 100644 index 0000000000..fdd59c72ce --- /dev/null +++ b/src/xenia/hid/microphone/microphone_driver.h @@ -0,0 +1,48 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2022 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_HID_MICROPHONE_DRIVER_H_ +#define XENIA_HID_MICROPHONE_DRIVER_H_ + +#include "xenia/xbox.h" + +namespace xe { +namespace hid { + +class MicrophoneSystem; + +class MicrophoneDriver { + public: + virtual ~MicrophoneDriver() = default; + + virtual X_STATUS Setup() = 0; + + virtual X_RESULT GetCapabilities(uint32_t user_index, uint32_t flags, + void* out_caps) = 0; + virtual X_RESULT GetState(uint32_t user_index, uint32_t* out_state) = 0; + virtual X_RESULT GetData(uint32_t user_index, void* out_ptr) = 0; + + void set_is_active_callback(std::function is_active_callback) { + is_active_callback_ = is_active_callback; + } + + protected: + explicit MicrophoneDriver() {} + + bool is_active() const { + return !is_active_callback_ || is_active_callback_(); + } + +private: + std::function is_active_callback_ = nullptr; +}; +} +} // namespace xe + +#endif // XENIA_HID_MICROPHONE_DRIVER_H_ \ No newline at end of file diff --git a/src/xenia/hid/microphone/microphone_system.cc b/src/xenia/hid/microphone/microphone_system.cc new file mode 100644 index 0000000000..e412c83d98 --- /dev/null +++ b/src/xenia/hid/microphone/microphone_system.cc @@ -0,0 +1,76 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2022 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/hid/microphone/microphone_system.h" +#include "xenia/hid/microphone/microphone_driver.h" + +#include "xenia/base/profiling.h" + +namespace xe { +namespace hid { +MicrophoneSystem::MicrophoneSystem() {} +MicrophoneSystem::~MicrophoneSystem() = default; + +X_STATUS MicrophoneSystem::Setup() { return X_STATUS_SUCCESS; } + +void MicrophoneSystem::AddDriver(std::unique_ptr driver) { + drivers_.push_back(std::move(driver)); +} + +X_RESULT MicrophoneSystem::GetCapabilities(uint32_t user_index, uint32_t flags, + XMICCAPABILITIES* out_caps) { + SCOPE_profile_cpu_f("hid"); + + bool any_connected = false; + for (auto& driver : drivers_) { + X_RESULT result = driver->GetCapabilities(user_index, flags, out_caps); + if (result != X_ERROR_DEVICE_NOT_CONNECTED) { + any_connected = true; + } + if (result == X_ERROR_SUCCESS) { + return result; + } + } + return any_connected ? X_ERROR_EMPTY : X_ERROR_DEVICE_NOT_CONNECTED; +} + +X_RESULT MicrophoneSystem::GetState(uint32_t user_index, uint32_t* out_state) { + SCOPE_profile_cpu_f("hid"); + + bool any_connected = false; + for (auto& driver : drivers_) { + X_RESULT result = driver->GetState(user_index, out_state); + if (result != X_ERROR_DEVICE_NOT_CONNECTED) { + any_connected = true; + } + if (result == X_ERROR_SUCCESS) { + return result; + } + } + return any_connected ? X_ERROR_EMPTY : X_ERROR_DEVICE_NOT_CONNECTED; +} + +X_RESULT MicrophoneSystem::GetData(uint32_t user_index, void* out_keystroke) { + SCOPE_profile_cpu_f("hid"); + + bool any_connected = false; + for (auto& driver : drivers_) { + X_RESULT result = driver->GetData(user_index, out_keystroke); + if (result != X_ERROR_DEVICE_NOT_CONNECTED) { + any_connected = true; + } + if (result == X_ERROR_SUCCESS || result == X_ERROR_EMPTY) { + return result; + } + } + return any_connected ? X_ERROR_EMPTY : X_ERROR_DEVICE_NOT_CONNECTED; +} + +} // namespace hid +} // namespace xe \ No newline at end of file diff --git a/src/xenia/hid/microphone/microphone_system.h b/src/xenia/hid/microphone/microphone_system.h new file mode 100644 index 0000000000..5fe9829811 --- /dev/null +++ b/src/xenia/hid/microphone/microphone_system.h @@ -0,0 +1,41 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2022 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_HID_MICROPHONE_SYSTEM_H_ +#define XENIA_HID_MICROPHONE_SYSTEM_H_ + +#include "xenia/xbox.h" + +#include "xenia/hid/microphone/microphone.h" +#include "xenia/hid/microphone/microphone_driver.h" + +namespace xe { +namespace hid { + +class MicrophoneSystem { + public: + explicit MicrophoneSystem(); + ~MicrophoneSystem(); + + X_STATUS Setup(); + + void AddDriver(std::unique_ptr driver); + X_RESULT GetCapabilities(uint32_t user_index, uint32_t flags, + XMICCAPABILITIES* out_caps); + X_RESULT GetState(uint32_t user_index, uint32_t* out_state); + X_RESULT GetData(uint32_t user_index, void* out_ptr); + + private: + std::vector> drivers_; +}; + +} // namespace hid +} // namespace xe + +#endif // XENIA_HID_MICROPHONE_SYSTEM_H_ \ No newline at end of file diff --git a/src/xenia/hid/microphone/premake5.lua b/src/xenia/hid/microphone/premake5.lua new file mode 100644 index 0000000000..0dd0497500 --- /dev/null +++ b/src/xenia/hid/microphone/premake5.lua @@ -0,0 +1,14 @@ +project_root = "../../../.." +include(project_root.."/tools/build") + +group("src") +project("xenia-hid-microphone") + uuid("84b15cca-79fd-41ad-b386-4fedaf878e96") + kind("StaticLib") + language("C++") + links({ + "xenia-base", + }) + defines({ + }) + local_platform_files() \ No newline at end of file diff --git a/src/xenia/hid/microphone/sdl/premake5.lua b/src/xenia/hid/microphone/sdl/premake5.lua new file mode 100644 index 0000000000..597a190ee3 --- /dev/null +++ b/src/xenia/hid/microphone/sdl/premake5.lua @@ -0,0 +1,17 @@ +project_root = "../../../../.." +include(project_root.."/tools/build") + +group("src") +project("xenia-hid-microphone-sdl") + uuid("89c75eac-8209-4b10-b5b8-d3be990b24f0") + kind("StaticLib") + language("C++") + links({ + "xenia-base", + "xenia-helper-sdl", + "SDL2", + }) + defines({ + }) + local_platform_files() + sdl2_include() \ No newline at end of file diff --git a/src/xenia/hid/microphone/sdl/sdl_hid.cc b/src/xenia/hid/microphone/sdl/sdl_hid.cc new file mode 100644 index 0000000000..39e1e6edba --- /dev/null +++ b/src/xenia/hid/microphone/sdl/sdl_hid.cc @@ -0,0 +1,26 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2020 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/hid/microphone/sdl/sdl_hid.h" + +#include "xenia/hid/microphone/sdl/sdl_microphone_driver.h" + +namespace xe { +namespace hid { +namespace microphone { +namespace sdl { + +std::unique_ptr Create() { + return std::make_unique(); +} + +} // namespace microphone +} // namespace sdl +} // namespace hid +} // namespace xe diff --git a/src/xenia/hid/microphone/sdl/sdl_hid.h b/src/xenia/hid/microphone/sdl/sdl_hid.h new file mode 100644 index 0000000000..cbb0c3227e --- /dev/null +++ b/src/xenia/hid/microphone/sdl/sdl_hid.h @@ -0,0 +1,30 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2022 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_HID_MICROPHONE_SDL_SDL_HID_H_ +#define XENIA_HID_MICROPHONE_SDL_SDL_HID_H_ + +#include + +#include "xenia/hid/microphone/microphone_system.h" + +namespace xe { +namespace hid { +namespace microphone { +namespace sdl { + + +std::unique_ptr Create(); + +} // namespace controller +} // namespace sdl +} // namespace hid +} // namespace xe + +#endif // XENIA_HID_MICROPHONE_SDL_SDL_HID_H_ diff --git a/src/xenia/hid/microphone/sdl/sdl_microphone_driver.cc b/src/xenia/hid/microphone/sdl/sdl_microphone_driver.cc new file mode 100644 index 0000000000..353708fd08 --- /dev/null +++ b/src/xenia/hid/microphone/sdl/sdl_microphone_driver.cc @@ -0,0 +1,116 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2020 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/base/logging.h" + +#include "xenia/hid/microphone/sdl/sdl_microphone_driver.h" +#include "xenia/helper/sdl/sdl_helper.h" + +namespace xe { +namespace hid { +namespace microphone { +namespace sdl { +SDLMicrophoneDriver::SDLMicrophoneDriver() : MicrophoneDriver(){}; + +SDLMicrophoneDriver::~SDLMicrophoneDriver(){}; + +X_STATUS SDLMicrophoneDriver::Setup() { + // for (int i = 0; i < SDL_GetNumAudioDevices((int)true); i++) { + // std::string name = SDL_GetAudioDeviceName(i, (int)true); + // XELOGE("{} - Audio capture device: {}", i, name); + //} + + SDL_version ver = {}; + SDL_GetVersion(&ver); + if ((ver.major < 2) || (ver.major == 2 && ver.minor == 0 && ver.patch < 8)) { + XELOGW( + "SDL library version {}.{}.{} is outdated. " + "You may experience choppy audio.", + ver.major, ver.minor, ver.patch); + } + + if (!xe::helper::sdl::SDLHelper::Prepare()) { + return false; + } + if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { + return false; + } + + + SDL_AudioSpec desired_spec = {}; + desired_spec.freq = 48000; + desired_spec.format = AUDIO_F32; + desired_spec.channels = 1; + desired_spec.samples = 1; + desired_spec.callback = nullptr; + desired_spec.userdata = this; + + SDL_AudioSpec obtained_spec; + + int capture_devices_amount = SDL_GetNumAudioDevices(SDL_TRUE); + XELOGI("Connected Microphones:"); + for (int i = 0; i < capture_devices_amount; i++) { + std::string name = SDL_GetAudioDeviceName(i, SDL_TRUE); + XELOGE("{} - Audio capture device: {}", i, name); + } + + for (int i = 0; i < capture_devices_amount; i++) { + std::string device_name = SDL_GetAudioDeviceName(i, SDL_TRUE); + sdl_device_id_ = SDL_OpenAudioDevice( + device_name.c_str(), SDL_TRUE, &desired_spec, + &obtained_spec, SDL_FALSE); + if (sdl_device_id_ <= 0) { + XELOGE("SDL_OpenAudioDevice() failed."); + return false; + } + + if (sdl_device_id_ <= 0) { + XELOGE("Failed to get a compatible SDL Audio Device."); + return false; + } + sdl_device_channels_ = obtained_spec.channels; + } + + SDL_PauseAudioDevice(sdl_device_id_, 0); + microphone_state_ = 0; + return true; +} + +X_RESULT SDLMicrophoneDriver::GetCapabilities(uint32_t user_index, + uint32_t flags, void* out_caps) { + return X_STATUS_SUCCESS; +} + +X_RESULT SDLMicrophoneDriver::GetState(uint32_t user_index, + uint32_t* out_state) { + *out_state = microphone_state_; + if (microphone_state_ == 3) { + microphone_state_ = 5; + } + + if (microphone_state_ < 3 && microphone_state_ > 0) { + microphone_state_++; + } + if (microphone_state_ > 5) { + microphone_state_ = 5; + } + if (!microphone_state_) { + microphone_state_ = user_index + 1; + } + return X_STATUS_SUCCESS; +} + +X_RESULT SDLMicrophoneDriver::GetData(uint32_t user_index, void* out_ptr) { + return X_STATUS_SUCCESS; +} + +} // namespace sdl +} // namespace microphone +} // namespace hid +} // namespace xe \ No newline at end of file diff --git a/src/xenia/hid/microphone/sdl/sdl_microphone_driver.h b/src/xenia/hid/microphone/sdl/sdl_microphone_driver.h new file mode 100644 index 0000000000..1eb6e19b65 --- /dev/null +++ b/src/xenia/hid/microphone/sdl/sdl_microphone_driver.h @@ -0,0 +1,43 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2022 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#pragma once +#include "xenia/hid/microphone/microphone_driver.h" +#include "SDL.h" + +namespace xe { +namespace hid { +namespace microphone { +namespace sdl { + +class SDLMicrophoneDriver final : public MicrophoneDriver { + public: + explicit SDLMicrophoneDriver(); + ~SDLMicrophoneDriver() override; + + X_STATUS Setup() override; + + X_RESULT GetCapabilities(uint32_t user_index, uint32_t flags, + void* out_caps) override; + X_RESULT GetState(uint32_t user_index, uint32_t* out_state) override; + // X_RESULT SetState(uint32_t user_index, void* vibration) override; + X_RESULT GetData(uint32_t user_index, void* out_keystroke) override; + + protected: + SDL_AudioDeviceID sdl_device_id_ = -1; + bool sdl_initialized_ = false; + uint8_t sdl_device_channels_ = 0; + + uint32_t microphone_state_ = 0; +}; + +} // namespace sdl +} // namespace microphone +} // namespace hid +} // namespace xe \ No newline at end of file diff --git a/src/xenia/kernel/premake5.lua b/src/xenia/kernel/premake5.lua index 8b22397375..033825ee02 100644 --- a/src/xenia/kernel/premake5.lua +++ b/src/xenia/kernel/premake5.lua @@ -13,6 +13,7 @@ project("xenia-kernel") "xenia-base", "xenia-cpu", "xenia-hid-controller", + "xenia-hid-microphone", "xenia-vfs", }) defines({ diff --git a/src/xenia/kernel/xam/xam_input.cc b/src/xenia/kernel/xam/xam_input.cc index 69e9d8bda0..07692b6c6f 100644 --- a/src/xenia/kernel/xam/xam_input.cc +++ b/src/xenia/kernel/xam/xam_input.cc @@ -180,13 +180,18 @@ dword_result_t XamInputGetKeystrokeEx_entry( DECLARE_XAM_EXPORT1(XamInputGetKeystrokeEx, kInput, kImplemented); X_HRESULT_result_t XamUserGetDeviceContext_entry(dword_t user_index, - dword_t unk, + dword_t device_type, lpdword_t out_ptr) { // Games check the result - usually with some masking. // If this function fails they assume zero, so let's fail AND // set zero just to be safe. *out_ptr = 0; if (!user_index || (user_index & 0xFF) == 0xFF) { + if (device_type == 4) { // Microphone + // Check if microphone is connected + // Then set *out_ptr = 6 << 28; + *out_ptr = 6 << 28; + } return X_E_SUCCESS; } else { return X_E_DEVICE_NOT_CONNECTED; diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_misc.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_misc.cc index 7a100665a9..b4b1e8cd91 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_misc.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_misc.cc @@ -8,11 +8,14 @@ */ #include "xenia/base/logging.h" +#include "xenia/hid/microphone/microphone.h" +#include "xenia/hid/microphone/microphone_system.h" #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/xboxkrnl/xboxkrnl_private.h" #include "xenia/kernel/xthread.h" #include "xenia/xbox.h" +#include "xenia/emulator.h" namespace xe { namespace kernel { @@ -23,6 +26,70 @@ void KeEnableFpuExceptions_entry(dword_t enabled) { } DECLARE_XBOXKRNL_EXPORT1(KeEnableFpuExceptions, kNone, kStub); +dword_result_t MicDeviceRequest_entry(pointer_t device_ptr) { + // Device_ptr + 4 is status + // Status list: + // < 1 or 6 - Not Connected + // 1 to 3 - Connected (Not initialized) + // 5 - Initialization + // Any other value (including 4) - Error + + if (!device_ptr) { + return X_STATUS_INVALID_PARAMETER; + } + XELOGE("MicDeviceRequest State: {:08X} Action: {:08X} USER: {:08X}", + device_ptr->info.state, device_ptr->info.request_type, + device_ptr->info.user_index); + // Some of fields are already filled correctly. + // One example is user_index, because there would be no other way to determine + // for which user certain microphone is assigned That means that every user + // must have their one personal microphone class device should at start have + // (somewhere user index) in form of user_index | mask (0x04000000) + if (device_ptr->info.user_index > 4) { + return X_STATUS_INVALID_PARAMETER; + } + + if (device_ptr->info.request_type > 0xB) { + return X_STATUS_INVALID_DEVICE_REQUEST; + } + + auto microphone_system = kernel_state()->emulator()->microphone_system(); + + if (!device_ptr->info.request_type) { + uint32_t new_state = device_ptr->info.state; + X_RESULT status = + microphone_system->GetState(device_ptr->info.user_index, &new_state); + + if (status) { + device_ptr->info.state = 0; + return X_STATUS_INVALID_DEVICE_REQUEST; + } + + XELOGE("MicDeviceRequest New State: {:08X}", new_state); + device_ptr->info.state = new_state; + } + + switch (device_ptr->info.request_type) { + case 1: + // GAIN + break; + case 7: + // Getting data. IO_PENDING + return X_STATUS_PENDING; + case 9: + device_ptr->capabilities.features = 0x100; + device_ptr->capabilities.format_tag = 1; + device_ptr->capabilities.mic_color = 0; + break; + default: + // 0 Seems like initialization! + break; + } + return X_ERROR_SUCCESS; + // return X_STATUS_PENDING; +} +DECLARE_XBOXKRNL_EXPORT1(MicDeviceRequest, kNone, kStub); + } // namespace xboxkrnl } // namespace kernel } // namespace xe diff --git a/src/xenia/xbox.h b/src/xenia/xbox.h index 574501788e..c04051b8d0 100644 --- a/src/xenia/xbox.h +++ b/src/xenia/xbox.h @@ -50,6 +50,7 @@ typedef uint32_t X_STATUS; #define X_STATUS_INVALID_HANDLE ((X_STATUS)0xC0000008L) #define X_STATUS_INVALID_PARAMETER ((X_STATUS)0xC000000DL) #define X_STATUS_NO_SUCH_FILE ((X_STATUS)0xC000000FL) +#define X_STATUS_INVALID_DEVICE_REQUEST ((X_STATUS)0xC0000010L) #define X_STATUS_END_OF_FILE ((X_STATUS)0xC0000011L) #define X_STATUS_NO_MEMORY ((X_STATUS)0xC0000017L) #define X_STATUS_ALREADY_COMMITTED ((X_STATUS)0xC0000021L)