android: Play vibrations asynchronously

This commit is contained in:
t895 2024-02-23 16:00:48 -05:00
parent 975d6f1ec4
commit 0369c65870
4 changed files with 44 additions and 17 deletions

View file

@ -3,6 +3,7 @@
#include <set> #include <set>
#include <common/settings_input.h> #include <common/settings_input.h>
#include <common/thread.h>
#include <jni.h> #include <jni.h>
#include "common/android/android_common.h" #include "common/android/android_common.h"
#include "common/android/id_cache.h" #include "common/android/id_cache.h"
@ -10,7 +11,18 @@
namespace InputCommon { namespace InputCommon {
Android::Android(std::string input_engine_) : InputEngine(std::move(input_engine_)) {} Android::Android(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
vibration_thread = std::jthread([this](std::stop_token token) {
Common::SetCurrentThreadName("Android_Vibration");
auto env = Common::Android::GetEnvForThread();
using namespace std::chrono_literals;
while (!token.stop_requested()) {
SendVibrations(env, token);
}
});
}
Android::~Android() = default;
void Android::RegisterController(jobject j_input_device) { void Android::RegisterController(jobject j_input_device) {
auto env = Common::Android::GetEnvForThread(); auto env = Common::Android::GetEnvForThread();
@ -57,18 +69,12 @@ void Android::SetMotionState(std::string guid, size_t port, u64 delta_timestamp,
Common::Input::DriverResult Android::SetVibration( Common::Input::DriverResult Android::SetVibration(
[[maybe_unused]] const PadIdentifier& identifier, [[maybe_unused]] const PadIdentifier& identifier,
[[maybe_unused]] const Common::Input::VibrationStatus& vibration) { [[maybe_unused]] const Common::Input::VibrationStatus& vibration) {
auto device = input_devices.find(identifier); vibration_queue.Push(VibrationRequest{
if (device != input_devices.end()) { .identifier = identifier,
Common::Android::RunJNIOnFiber<void>([&](JNIEnv* env) { .vibration = vibration,
float average_intensity =
static_cast<float>((vibration.high_amplitude + vibration.low_amplitude) / 2.0);
env->CallVoidMethod(device->second, Common::Android::GetYuzuDeviceVibrate(),
average_intensity);
}); });
return Common::Input::DriverResult::Success; return Common::Input::DriverResult::Success;
} }
return Common::Input::DriverResult::NotSupported;
}
bool Android::IsVibrationEnabled([[maybe_unused]] const PadIdentifier& identifier) { bool Android::IsVibrationEnabled([[maybe_unused]] const PadIdentifier& identifier) {
auto device = input_devices.find(identifier); auto device = input_devices.find(identifier);
@ -347,4 +353,15 @@ PadIdentifier Android::GetIdentifier(const std::string& guid, size_t port) const
}; };
} }
void Android::SendVibrations(JNIEnv* env, std::stop_token token) {
VibrationRequest request = vibration_queue.PopWait(token);
auto device = input_devices.find(request.identifier);
if (device != input_devices.end()) {
float average_intensity = static_cast<float>(
(request.vibration.high_amplitude + request.vibration.low_amplitude) / 2.0);
env->CallVoidMethod(device->second, Common::Android::GetYuzuDeviceVibrate(),
average_intensity);
}
}
} // namespace InputCommon } // namespace InputCommon

View file

@ -4,6 +4,7 @@
#pragma once #pragma once
#include <set> #include <set>
#include <common/threadsafe_queue.h>
#include <jni.h> #include <jni.h>
#include "input_common/input_engine.h" #include "input_common/input_engine.h"
@ -16,6 +17,8 @@ class Android final : public InputEngine {
public: public:
explicit Android(std::string input_engine_); explicit Android(std::string input_engine_);
~Android() override;
/** /**
* Registers controller number to accept new inputs. * Registers controller number to accept new inputs.
* @param j_input_device YuzuInputDevice object from the Android frontend to register. * @param j_input_device YuzuInputDevice object from the Android frontend to register.
@ -89,6 +92,9 @@ private:
/// Returns the correct identifier corresponding to the player index /// Returns the correct identifier corresponding to the player index
PadIdentifier GetIdentifier(const std::string& guid, size_t port) const; PadIdentifier GetIdentifier(const std::string& guid, size_t port) const;
/// Takes all vibrations from the queue and sends the command to the controller
void SendVibrations(JNIEnv* env, std::stop_token token);
static constexpr s32 AXIS_X = 0; static constexpr s32 AXIS_X = 0;
static constexpr s32 AXIS_Y = 1; static constexpr s32 AXIS_Y = 1;
static constexpr s32 AXIS_Z = 11; static constexpr s32 AXIS_Z = 11;
@ -133,6 +139,10 @@ private:
redmagic_vid, backbone_labs_vid, xbox_vid}; redmagic_vid, backbone_labs_vid, xbox_vid};
const std::vector<std::string> flipped_xy_vids{sony_vid, razer_vid, redmagic_vid, const std::vector<std::string> flipped_xy_vids{sony_vid, razer_vid, redmagic_vid,
backbone_labs_vid, xbox_vid}; backbone_labs_vid, xbox_vid};
/// Queue of vibration request to controllers
Common::SPSCQueue<VibrationRequest> vibration_queue;
std::jthread vibration_thread;
}; };
} // namespace InputCommon } // namespace InputCommon

View file

@ -69,11 +69,6 @@ public:
bool IsVibrationEnabled(const PadIdentifier& identifier) override; bool IsVibrationEnabled(const PadIdentifier& identifier) override;
private: private:
struct VibrationRequest {
PadIdentifier identifier;
Common::Input::VibrationStatus vibration;
};
void InitJoystick(int joystick_index); void InitJoystick(int joystick_index);
void CloseJoystick(SDL_Joystick* sdl_joystick); void CloseJoystick(SDL_Joystick* sdl_joystick);

View file

@ -46,6 +46,11 @@ enum class EngineInputType {
Nfc, Nfc,
}; };
struct VibrationRequest {
PadIdentifier identifier;
Common::Input::VibrationStatus vibration;
};
namespace std { namespace std {
// Hash used to create lists from PadIdentifier data // Hash used to create lists from PadIdentifier data
template <> template <>