Skip to content

Commit

Permalink
Implement controlller touch events.
Browse files Browse the repository at this point in the history
  • Loading branch information
hgaiser committed Jan 26, 2025
1 parent d58d373 commit b48a630
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 14 deletions.
9 changes: 7 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,4 @@ zeroconf = "0.15.0"
ffmpeg = { version = "7.1.0", package = "ffmpeg-next", git = "https://github.com/hgaiser/rust-ffmpeg", branch = "codec-context-settable" }
ffmpeg-sys-next = { version = "7.1.0", git = "https://github.com/hgaiser/rust-ffmpeg-sys", branch = "cuda" }
reed-solomon-erasure = { version = "6.0.0", git = "https://github.com/hgaiser/reed-solomon-erasure", branch = "moonshine" }
inputtino = { version = "0.1.0", path = "../inputtino/bindings/rust" }
inputtino = { version = "0.1.0", path = "../inputtino/bindings/rust/inputtino" }
18 changes: 17 additions & 1 deletion src/rtsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ use tokio::{net::{TcpListener, TcpStream}, io::{AsyncReadExt, AsyncWriteExt}};

use crate::{config::Config, session::{stream::{AudioStreamContext, VideoStreamContext}, manager::SessionManager}};

#[repr(u8)]
enum ServerCapabilities {
_TouchEvents = 0x01,
ControllerTouchEvents = 0x02,
}

#[derive(Clone)]
pub struct RtspServer {
config: Config,
Expand Down Expand Up @@ -62,6 +68,10 @@ impl RtspServer {
server
}

fn capabilities(&self) -> u8 {
ServerCapabilities::ControllerTouchEvents as u8
}

#[allow(clippy::result_unit_err)]
pub fn description(&self) -> String {
// This is a very simple SDP description, the minimal that Moonlight requires.
Expand All @@ -72,7 +82,13 @@ impl RtspServer {
// "a=rtpmap:98 AV1/90000" (For AV1 support)
// "a=fmtp:97 surround-params=<SURROUND PARAMS>"
// "<AUDIO STREAM MAPPING>"
"sprop-parameter-sets=AAAAAU\na=fmtp:96 packetization-mode=1".to_string()
let mut result = String::new();

result.push_str(&format!("a=x-ss-general.featureFlags:{}\n", self.capabilities()));
result.push_str("sprop-parameter-sets=AAAAAU\n");
result.push_str("a=fmtp:96 packetization-mode=1");

result
}

fn handle_options_request(&self, request: &rtsp_types::Request<Vec<u8>>, cseq: i32) -> rtsp_types::Response<Vec<u8>> {
Expand Down
86 changes: 78 additions & 8 deletions src/session/stream/control/input/gamepad.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
use inputtino::{DeviceDefinition, Joypad, JoypadKind, JoypadStickPosition};
use inputtino::{DeviceDefinition, Joypad, JoypadStickPosition, PS5Joypad, SwitchJoypad, XboxOneJoypad};
use strum_macros::FromRepr;

#[derive(Debug, FromRepr)]
#[repr(u8)]
pub enum GamepadKind {
Unknown = 0x00,
Xbox = 0x01,
PlayStation = 0x02,
Nintendo = 0x03,
}

#[derive(Copy, Clone, Debug)]
#[repr(u16)]
Expand Down Expand Up @@ -31,7 +41,7 @@ enum GamepadCapability {
#[derive(Debug)]
pub struct GamepadInfo {
_index: u8,
kind: JoypadKind,
kind: GamepadKind,
capabilities: u16,
_supported_buttons: u32,
}
Expand All @@ -52,7 +62,7 @@ impl GamepadInfo {

Ok(Self {
_index: buffer[0],
kind: JoypadKind::from_repr(buffer[1]).ok_or_else(|| tracing::warn!("Unknown gamepad kind: {}", buffer[1]))?,
kind: GamepadKind::from_repr(buffer[1]).ok_or_else(|| tracing::warn!("Unknown gamepad kind: {}", buffer[1]))?,
capabilities: u16::from_le_bytes(buffer[2..4].try_into().unwrap()),
_supported_buttons: u32::from_le_bytes(buffer[4..8].try_into().unwrap()),
})
Expand All @@ -64,6 +74,47 @@ impl GamepadInfo {
}
}

#[derive(Debug)]
pub struct GamepadTouch {
pub index: u8,
_event_type: u8,
// zero: [u8; 2], // Alignment/reserved
pointer_id: u32,
pub x: f32,
pub y: f32,
pub pressure: f32,
}

impl GamepadTouch {
pub fn from_bytes(buffer: &[u8]) -> Result<Self, ()> {
const EXPECTED_SIZE: usize =
std::mem::size_of::<u8>() // index
+ std::mem::size_of::<u8>() // event_type
+ std::mem::size_of::<u16>() // zero
+ std::mem::size_of::<u32>() // pointer_id
+ std::mem::size_of::<f32>() // x
+ std::mem::size_of::<f32>() // y
+ std::mem::size_of::<f32>() // pressure
;

if buffer.len() < EXPECTED_SIZE {
tracing::warn!("Expected at least {EXPECTED_SIZE} bytes for GamepadTouch, got {} bytes.", buffer.len());
return Err(());
}

Ok(Self {
index: buffer[0],
_event_type: buffer[1],
// zero: u16::from_le_bytes(buffer[2..4].try_into().unwrap()),
pointer_id: u32::from_le_bytes(buffer[4..8].try_into().unwrap()),
x: f32::from_le_bytes(buffer[8..12].try_into().unwrap()),
y: f32::from_le_bytes(buffer[12..16].try_into().unwrap()),
pressure: f32::from_le_bytes(buffer[16..20].try_into().unwrap()),

})
}
}

#[derive(Debug)]
pub struct GamepadUpdate {
pub index: u16,
Expand Down Expand Up @@ -125,12 +176,17 @@ pub struct Gamepad {
impl Gamepad {
pub fn new(info: GamepadInfo) -> Result<Self, ()> {
let definition = match info.kind {
JoypadKind::Unknown | JoypadKind::Xbox => DeviceDefinition::new("Moonshine XOne controller", 0x045e, 0x02dd, 0x0100, "00:11:22:33:44", "00:11:22:33:44"),
JoypadKind::PlayStation => DeviceDefinition::new("Moonshine PS5 controller", 0x054C, 0x0CE6, 0x8111, "00:11:22:33:44", "00:11:22:33:44"),
JoypadKind::Nintendo => DeviceDefinition::new("Moonshine Switch controller", 0x045e, 0x02DD, 0x0100, "00:11:22:33:44", "00:11:22:33:44"),
GamepadKind::Unknown | GamepadKind::Xbox => DeviceDefinition::new("Moonshine XOne controller", 0x045e, 0x02dd, 0x0100, "00:11:22:33:44", "00:11:22:33:44"),
GamepadKind::PlayStation => DeviceDefinition::new("Moonshine PS5 controller", 0x054C, 0x0CE6, 0x8111, "00:11:22:33:44", "00:11:22:33:44"),
GamepadKind::Nintendo => DeviceDefinition::new("Moonshine Switch controller", 0x045e, 0x02DD, 0x0100, "00:11:22:33:44", "00:11:22:33:44"),
};
let gamepad = Joypad::new(&info.kind, &definition)
.map_err(|e| tracing::error!("Failed to create gamepad: {e}"))?;

let gamepad = match info.kind {
GamepadKind::Unknown | GamepadKind::Xbox => Joypad::XboxOne(XboxOneJoypad::new(&definition).map_err(|e| tracing::error!("Failed to create gamepad: {e}"))?),
GamepadKind::PlayStation => Joypad::PS5(PS5Joypad::new(&definition).map_err(|e| tracing::error!("Failed to create gamepad: {e}"))?),
GamepadKind::Nintendo => Joypad::Switch(SwitchJoypad::new(&definition).map_err(|e| tracing::error!("Failed to create gamepad: {e}"))?),
};

Ok(Self { _info: info, gamepad })
}

Expand All @@ -143,4 +199,18 @@ impl Gamepad {
self.gamepad.set_stick(JoypadStickPosition::RS, update.right_stick.0, update.right_stick.1);
self.gamepad.set_triggers(update.left_trigger as i16, update.right_trigger as i16);
}

pub fn touch(&mut self, touch: GamepadTouch) {
if let Joypad::PS5(gamepad) = &self.gamepad {
if touch.pressure > 0.5 {
gamepad.place_finger(
touch.pointer_id,
(touch.x * PS5Joypad::TOUCHPAD_WIDTH as f32) as u16,
(touch.y * PS5Joypad::TOUCHPAD_HEIGHT as f32) as u16,
);
} else {
gamepad.release_finger(touch.pointer_id);
}
}
}
}
14 changes: 13 additions & 1 deletion src/session/stream/control/input/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use self::{
MouseScrollHorizontal,
},
keyboard::{Keyboard, Key},
gamepad::{GamepadInfo, GamepadUpdate}
gamepad::{GamepadInfo, GamepadTouch, GamepadUpdate}
};

mod keyboard;
Expand All @@ -32,6 +32,7 @@ enum InputEventType {
MouseScrollVertical = 0x0000000A,
MouseScrollHorizontal = 0x55000001,
GamepadInfo = 0x55000004, // Called ControllerArrival in Moonlight.
GamepadTouch = 0x55000005,
GamepadUpdate = 0x0000000C,
}

Expand All @@ -47,6 +48,7 @@ enum InputEvent {
MouseScrollVertical(MouseScrollVertical),
MouseScrollHorizontal(MouseScrollHorizontal),
GamepadInfo(GamepadInfo),
GamepadTouch(GamepadTouch),
GamepadUpdate(GamepadUpdate),
}

Expand All @@ -68,6 +70,7 @@ impl InputEvent {
Some(InputEventType::MouseScrollVertical) => Ok(InputEvent::MouseScrollVertical(MouseScrollVertical::from_bytes(&buffer[4..])?)),
Some(InputEventType::MouseScrollHorizontal) => Ok(InputEvent::MouseScrollHorizontal(MouseScrollHorizontal::from_bytes(&buffer[4..])?)),
Some(InputEventType::GamepadInfo) => Ok(InputEvent::GamepadInfo(GamepadInfo::from_bytes(&buffer[4..])?)),
Some(InputEventType::GamepadTouch) => Ok(InputEvent::GamepadTouch(GamepadTouch::from_bytes(&buffer[4..])?)),
Some(InputEventType::GamepadUpdate) => Ok(InputEvent::GamepadUpdate(GamepadUpdate::from_bytes(&buffer[4..])?)),
None => {
tracing::warn!("Received unknown event type: {event_type}");
Expand Down Expand Up @@ -158,6 +161,15 @@ impl InputHandlerInner {
gamepads.push(gamepad);
}
},
InputEvent::GamepadTouch(gamepad_touch) => {
tracing::trace!("Gamepad touch: {gamepad_touch:?}");
if gamepad_touch.index as usize >= gamepads.len() {
tracing::warn!("Received touch for gamepad {}, but we only have {} gamepads.", gamepad_touch.index, gamepads.len());
continue;
}

gamepads[gamepad_touch.index as usize].touch(gamepad_touch);
},
InputEvent::GamepadUpdate(gamepad_update) => {
tracing::trace!("Gamepad update: {gamepad_update:?}");
if gamepad_update.index as usize >= gamepads.len() {
Expand Down
2 changes: 2 additions & 0 deletions src/session/stream/video/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ impl VideoStreamInner {
continue;
}

tracing::info!("Starting video stream.");

// TODO: Make the GPU index configurable.
let cuda_device = cudarc::driver::CudaDevice::new(0)
.map_err(|e| tracing::error!("Failed to initialize CUDA: {e}"))?;
Expand Down
2 changes: 1 addition & 1 deletion src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl State {
let serialized = std::fs::read_to_string(&path)
.map_err(|e| tracing::error!("Failed to read state file: {e}"))?;
inner = toml::from_str(&serialized)
.map_err(|e| tracing::error!("Failed to parse state file: {e}"))?;
.map_err(|e| tracing::error!("Failed to parse state file at '{}': {e}", path.display()))?;

tracing::debug!("Successfully loaded state from {:?}", path);
tracing::trace!("State: {inner:?}");
Expand Down

0 comments on commit b48a630

Please sign in to comment.