-
Notifications
You must be signed in to change notification settings - Fork 0
/
streamsession.pyx
192 lines (159 loc) · 7.79 KB
/
streamsession.pyx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
from libchiaki cimport *
from libc.stdio cimport printf
from libc.stdint cimport uint8_t
import numpy as np
cpdef enum JoyButtons:
CROSS = ChiakiControllerButton.CHIAKI_CONTROLLER_BUTTON_CROSS,
MOON = ChiakiControllerButton.CHIAKI_CONTROLLER_BUTTON_MOON,
BOX = ChiakiControllerButton.CHIAKI_CONTROLLER_BUTTON_BOX,
PYRAMID = ChiakiControllerButton.CHIAKI_CONTROLLER_BUTTON_PYRAMID,
DPAD_LEFT = ChiakiControllerButton.CHIAKI_CONTROLLER_BUTTON_DPAD_LEFT,
DPAD_RIGHT = ChiakiControllerButton.CHIAKI_CONTROLLER_BUTTON_DPAD_RIGHT,
DPAD_UP = ChiakiControllerButton.CHIAKI_CONTROLLER_BUTTON_DPAD_UP,
DPAD_DOWN = ChiakiControllerButton.CHIAKI_CONTROLLER_BUTTON_DPAD_DOWN,
L1 = ChiakiControllerButton.CHIAKI_CONTROLLER_BUTTON_L1,
R1 = ChiakiControllerButton.CHIAKI_CONTROLLER_BUTTON_R1,
L3 = ChiakiControllerButton.CHIAKI_CONTROLLER_BUTTON_L3,
R3 = ChiakiControllerButton.CHIAKI_CONTROLLER_BUTTON_R3,
OPTIONS = ChiakiControllerButton.CHIAKI_CONTROLLER_BUTTON_OPTIONS,
SHARE = ChiakiControllerButton.CHIAKI_CONTROLLER_BUTTON_SHARE,
TOUCHPAD = ChiakiControllerButton.CHIAKI_CONTROLLER_BUTTON_TOUCHPAD,
PS = ChiakiControllerButton.CHIAKI_CONTROLLER_BUTTON_PS
cpdef enum JoyAxes:
RX,
RY,
RZ,
LX,
LY,
LZ
cdef class ChiakiStreamSession:
cdef ChiakiLog log
cdef ChiakiSession session
cdef ChiakiTarget target
cdef bint is_ps5
cdef ChiakiControllerState controller_state
cdef ChiakiControllerState keyboard_state
cdef char* regkey
cdef char* rpkey
cdef char* host
cdef public bint connected
cdef void* python_haptics_callback
@property
def controller_state(self):
return self.controller_state
@controller_state.setter
def controller_state(self, value):
self.controller_state = value
def __cinit__(self, host=None, regkey = None, rpkey = None):
self.regkey = <char*> regkey
self.rpkey = <char*> rpkey
temphost = host.encode('UTF-8')
self.host = <char *> temphost
self.python_haptics_callback = NULL
self.connected = False
self.target = CHIAKI_TARGET_PS5_1
self.is_ps5 = True #FIXME: Support PS4s at some point. But these controller-only remoteplay hax are primarily for PS5
chiaki_log_init(&self.log, CHIAKI_LOG_ERROR, chiaki_log_cb_print, NULL)
chiaki_controller_state_set_idle(&self.controller_state)
chiaki_controller_state_set_idle(&self.keyboard_state)
cdef ChiakiConnectVideoProfile vid_profile
chiaki_connect_video_profile_preset(&vid_profile, CHIAKI_VIDEO_RESOLUTION_PRESET_360p, CHIAKI_VIDEO_FPS_PRESET_30)
cdef ChiakiConnectInfo connect_info
connect_info.ps5 = chiaki_target_is_ps5(self.target)
connect_info.host = self.host
connect_info.enable_keyboard = False #Pretty sure this means disabling sending of keyboard events to the PS5, not "do not handle local keyboard"
connect_info.video_profile = vid_profile
connect_info.video_profile_auto_downgrade = True
connect_info.morning = self.rpkey
connect_info.regist_key = self.regkey
connect_info.enable_dualsense = True
connect_info.holepunch_session = NULL
err = chiaki_session_init(&self.session, &connect_info, &self.log)
if(err != CHIAKI_ERR_SUCCESS):
raise Exception("Chiaki Session Init failed: " + chiaki_error_string(err))
cdef ChiakiAudioSink haptics_sink
haptics_sink.user = <void*> self
haptics_sink.frame_cb = self.haptics_frame_cb
chiaki_session_set_haptics_sink(&self.session, &haptics_sink)
chiaki_session_set_event_cb(&self.session, <ChiakiEventCallback> self.event_cb, <void*> self)
def __del__(self):
chiaki_session_join(&self.session)
chiaki_session_fini(&self.session)
cpdef void Start(self):
cdef ChiakiErrorCode err = chiaki_session_start(&self.session)
if(err != CHIAKI_ERR_SUCCESS):
chiaki_session_fini(&self.session)
raise Exception("Session start failed")
else:
printf("Session start succeeded!\n")
cpdef void Stop(self):
chiaki_session_stop(&self.session)
cpdef void GoToBed(self):
chiaki_session_goto_bed(&self.session)
def HandleAxisEvent(self, axis, value):
if(axis == JoyAxes.RX):
self.controller_state.right_x = value
elif(axis == JoyAxes.RY):
self.controller_state.right_y = value
elif(axis == JoyAxes.RZ):
self.controller_state.r2_state = value
elif(axis == JoyAxes.LX):
self.controller_state.left_x = value
elif(axis == JoyAxes.LY):
self.controller_state.left_y = value
elif(axis == JoyAxes.LZ):
self.controller_state.l2_state = value
# self.SendFeedbackState()
def HandleButtonEvent(self, key, pressed):
cdef ChiakiControllerButton button = key
if(pressed):
self.controller_state.buttons |= button
else:
self.controller_state.buttons &= ~button
# if(sendImm):
# self.SendFeedbackState()
def SendFeedbackState(self):
cdef ChiakiControllerState state
chiaki_controller_state_set_idle(&state)
chiaki_controller_state_or(&state, &state, &self.controller_state)
chiaki_controller_state_or(&state, &state, &self.keyboard_state)
chiaki_session_set_controller_state(&self.session, &state)
def set_haptics_callback(self, func):
self.python_haptics_callback = <void*>func
'''
It does not appear that we can pass a native Python class method to C. So we pass a staticmethod. Fortunately Chiaki's callbacks support passing user data,
so we pass a pointer to "self" as user data to the callback, and dereference it inside of the function.
Also used for our event callback
haptics_frame_cb calls Python code so "with gil" is absolutely mandatory. Otherwise any attempt to call Python code segfaults.
'''
@staticmethod
cdef void haptics_frame_cb(uint8_t *buf, size_t buf_size, void *selfref) noexcept with gil:
self = <ChiakiStreamSession> selfref
'''
TODO: Figure out what to do if we ever get an odd buf_size - this should never happen though! Not sure how frombuffer will handle things for an odd size
The Cython documentation is really unclear as to how to derefence a buffer pointer to something that Python functions will accept. Most documentation talks about
memoryviews of Python objects, not the other way around. It turns out that you need to use Python's slicing syntax - see buf[:buf_size]
'''
myarr = np.frombuffer(buf[:buf_size], dtype='int16', count=-1)
myarr = myarr.view(myarr.dtype.newbyteorder('<'))
#https://github.com/cython/cython/tree/master/Demos/callback
if(self.python_haptics_callback != NULL):
(<object>self.python_haptics_callback)(myarr)
@staticmethod
cdef void event_cb(ChiakiEvent *event, void *selfref) noexcept:
self = <ChiakiStreamSession> selfref
printf("Event callback received\n")
if(event.type == CHIAKI_EVENT_CONNECTED):
printf("Connected event received\n")
self.connected = True
elif(event.type == CHIAKI_EVENT_QUIT):
self.connected = False
printf("Session quit, reason: %s\n", event.quit.reason_str)
elif(event.type == CHIAKI_EVENT_LOGIN_PIN_REQUEST):
printf("Login PIN request received - handling this is not implemented\n")
elif(event.type == CHIAKI_EVENT_RUMBLE):
printf("Rumble signal received\n")
elif(event.type == CHIAKI_EVENT_TRIGGER_EFFECTS):
printf("Trigger effects received\n")
else:
printf("Unkown event received")