Skip to content

Commit

Permalink
Tmp: add Libretro kbrd hndlr .....
Browse files Browse the repository at this point in the history
  • Loading branch information
sergystepanov committed Feb 17, 2024
1 parent 2636fe8 commit 79530fb
Show file tree
Hide file tree
Showing 14 changed files with 331 additions and 67 deletions.
54 changes: 33 additions & 21 deletions pkg/network/webrtc/webrtc.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ import (
)

type Peer struct {
api *ApiFactory
conn *webrtc.PeerConnection
log *logger.Logger
OnMessage func(data []byte)
api *ApiFactory
conn *webrtc.PeerConnection
log *logger.Logger
OnMessage func(data []byte)
OnKeyboard func(data []byte)

a *webrtc.TrackLocalStaticSample
v *webrtc.TrackLocalStaticSample
Expand Down Expand Up @@ -82,11 +83,32 @@ func (p *Peer) NewCall(vCodec, aCodec string, onICECandidate func(ice any)) (sdp
p.a = audio

// plug in the [data] channel (in and out)
if err = p.addDataChannel("data"); err != nil {
dChan, err := p.addDataChannel("data")
if err != nil {
return "", err
}
dChan.OnMessage(func(m webrtc.DataChannelMessage) {
if len(m.Data) == 0 {
return
}
if p.OnMessage != nil {
p.OnMessage(m.Data)
}
})
p.d = dChan
p.log.Debug().Msg("Added [data] chan")

kChan, err := p.addDataChannel("keyboard")
if err != nil {
return "", err
}
kChan.OnMessage(func(m webrtc.DataChannelMessage) {
if p.OnKeyboard != nil {
p.OnKeyboard(m.Data)
}
})
p.log.Debug().Msg("Added [keyboard] chan")

p.conn.OnICEConnectionStateChange(p.handleICEState(func() { p.log.Info().Msg("Connected") }))
// Stream provider supposes to send offer
offer, err := p.conn.CreateOffer(nil)
Expand Down Expand Up @@ -232,29 +254,19 @@ func (p *Peer) Disconnect() {
p.log.Debug().Msg("WebRTC stop")
}

// addDataChannel creates a new WebRTC data channel for user input.
// addDataChannel creates new WebRTC data channel.
// Default params -- ordered: true, negotiated: false.
func (p *Peer) addDataChannel(label string) error {
func (p *Peer) addDataChannel(label string) (*webrtc.DataChannel, error) {
ch, err := p.conn.CreateDataChannel(label, nil)
if err != nil {
return err
return nil, err
}
ch.OnOpen(func() {
p.log.Debug().Str("label", ch.Label()).Uint16("id", *ch.ID()).
Msg("Data channel [input] opened")
p.log.Debug().Uint16("id", *ch.ID()).Msgf("Data channel [%v] opened", ch.Label())
})
ch.OnError(p.logx)
ch.OnMessage(func(m webrtc.DataChannelMessage) {
if len(m.Data) == 0 {
return
}
if p.OnMessage != nil {
p.OnMessage(m.Data)
}
})
p.d = ch
ch.OnClose(func() { p.log.Debug().Msg("Data channel [input] has been closed") })
return nil
ch.OnClose(func() { p.log.Debug().Msgf("Data channel [%v] has been closed", ch.Label()) })
return ch, nil
}

func (p *Peer) logx(err error) { p.log.Error().Err(err) }
1 change: 1 addition & 0 deletions pkg/worker/caged/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type App interface {
SetVideoCb(func(Video))
SetDataCb(func([]byte))
SendControl(port int, data []byte)
SendKeyboardKey(port int, down bool, key uint)
}

type Audio struct {
Expand Down
25 changes: 13 additions & 12 deletions pkg/worker/caged/libretro/caged.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,16 @@ func (c *Caged) EnableCloudStorage(uid string, storage cloud.Storage) {
}
}

func (c *Caged) AspectEnabled() bool { return c.base.nano.Aspect }
func (c *Caged) AspectRatio() float32 { return c.base.AspectRatio() }
func (c *Caged) PixFormat() uint32 { return c.Emulator.PixFormat() }
func (c *Caged) Rotation() uint { return c.Emulator.Rotation() }
func (c *Caged) AudioSampleRate() int { return c.Emulator.AudioSampleRate() }
func (c *Caged) ViewportSize() (int, int) { return c.base.ViewportSize() }
func (c *Caged) Scale() float64 { return c.Emulator.Scale() }
func (c *Caged) SendControl(port int, data []byte) { c.base.Input(port, data) }
func (c *Caged) Start() { go c.Emulator.Start() }
func (c *Caged) SetSaveOnClose(v bool) { c.base.SaveOnClose = v }
func (c *Caged) SetSessionId(name string) { c.base.SetSessionId(name) }
func (c *Caged) Close() { c.Emulator.Close() }
func (c *Caged) AspectEnabled() bool { return c.base.nano.Aspect }
func (c *Caged) AspectRatio() float32 { return c.base.AspectRatio() }
func (c *Caged) PixFormat() uint32 { return c.Emulator.PixFormat() }
func (c *Caged) Rotation() uint { return c.Emulator.Rotation() }
func (c *Caged) AudioSampleRate() int { return c.Emulator.AudioSampleRate() }
func (c *Caged) ViewportSize() (int, int) { return c.base.ViewportSize() }
func (c *Caged) Scale() float64 { return c.Emulator.Scale() }
func (c *Caged) SendControl(port int, data []byte) { c.base.Input(port, data) }
func (c *Caged) SendKeyboardKey(port int, down bool, key uint) { c.base.KeyboardEvent(down, key, 0, 0) }
func (c *Caged) Start() { go c.Emulator.Start() }
func (c *Caged) SetSaveOnClose(v bool) { c.base.SaveOnClose = v }
func (c *Caged) SetSessionId(name string) { c.base.SetSessionId(name) }
func (c *Caged) Close() { c.Emulator.Close() }
7 changes: 6 additions & 1 deletion pkg/worker/caged/libretro/frontend.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type Emulator interface {
Input(player int, data []byte)
// Scale returns set video scale factor
Scale() float64
KeyboardEvent(down bool, keycode uint, character uint32, keyModifiers uint16)
}

type Frontend struct {
Expand Down Expand Up @@ -83,7 +84,7 @@ type (
)

const (
maxPort = 4
maxPort = 8
dpadAxes = 4
)

Expand Down Expand Up @@ -402,6 +403,10 @@ func (f *Frontend) autosave(periodSec int) {
}
}

func (f *Frontend) KeyboardEvent(down bool, keycode uint, character uint32, keyModifiers uint16) {
f.nano.KeyboardEvent(down, keycode, character, keyModifiers)
}

func NewGameSessionInput() InputState { return [maxPort]State{} }

// setInput sets input state for some player in a game session.
Expand Down
5 changes: 5 additions & 0 deletions pkg/worker/caged/libretro/nanoarch/input.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package nanoarch

const RetroDeviceTypeShift = 8

func RetroDeviceSubclass(base, id int) int { return ((id + 1) << RetroDeviceTypeShift) | base }
4 changes: 4 additions & 0 deletions pkg/worker/caged/libretro/nanoarch/nanoarch.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ void bridge_clear_all_thread_waits_cb(void *data) {
*(retro_environment_t *)data = clear_all_thread_waits_cb;
}

void bridge_retro_keyboard_callback(void *cb, bool down, unsigned keycode, uint32_t character, uint16_t keyModifiers) {
(*(retro_keyboard_event_t *) cb)(down, keycode, character, keyModifiers);
}

bool core_environment_cgo(unsigned cmd, void *data) {
bool coreEnvironment(unsigned, void *);
return coreEnvironment(cmd, data);
Expand Down
60 changes: 42 additions & 18 deletions pkg/worker/caged/libretro/nanoarch/nanoarch.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ var (

type Nanoarch struct {
Handlers
Callbacks
LastFrameTime int64
LibCo bool
meta Metadata
Expand Down Expand Up @@ -81,6 +82,10 @@ type Handlers struct {
OnSystemAvInfo func()
}

type Callbacks struct {
KeyboardEvent func(down bool, keycode uint, character uint32, keyModifiers uint16)
}

type FrameInfo struct {
W uint
H uint
Expand Down Expand Up @@ -128,6 +133,9 @@ var Nan0 = Nanoarch{
OnAudio: func(unsafe.Pointer, int) {},
OnVideo: func([]byte, int32, FrameInfo) {},
},
Callbacks: Callbacks{
KeyboardEvent: func(bool, uint, uint32, uint16) {},
},
}

// init provides a global single instance lock
Expand Down Expand Up @@ -596,31 +604,33 @@ func coreInputPoll() {}

//export coreInputState
func coreInputState(port C.unsigned, device C.unsigned, index C.unsigned, id C.unsigned) C.int16_t {
if uint(port) >= uint(MaxPort) {
return KeyReleased
}

if device == C.RETRO_DEVICE_ANALOG {
if index > C.RETRO_DEVICE_INDEX_ANALOG_RIGHT || id > C.RETRO_DEVICE_ID_ANALOG_Y {
return 0
}
axis := index*2 + id
value := Nan0.Handlers.OnDpad(uint(port), uint(axis))
if value != 0 {
//Nan0.log.Debug().Msgf("%v %v %v %v", port, device, index, id)

//if uint(port) >= uint(MaxPort) {
// return KeyReleased
//}

switch device {
case C.RETRO_DEVICE_JOYPAD:
return C.int16_t(Nan0.Handlers.OnKeyPress(uint(port), int(id))) // 0 1
case C.RETRO_DEVICE_ANALOG:
switch index {
case C.RETRO_DEVICE_INDEX_ANALOG_LEFT:
value := Nan0.Handlers.OnDpad(uint(port), uint(index*2+id))
//Nan0.log.Debug().Msgf(">>> analog: %v", value)
return (C.int16_t)(value)
case C.RETRO_DEVICE_INDEX_ANALOG_RIGHT:
case C.RETRO_DEVICE_INDEX_ANALOG_BUTTON:
}
}

key := int(id)
if key > lastKey || index > 0 || device != C.RETRO_DEVICE_JOYPAD {
return KeyReleased
}
if Nan0.Handlers.OnKeyPress(uint(port), key) == KeyPressed {
return KeyPressed
}
return KeyReleased
}

//func retroKeyboardEvent(down C.bool, keycode C.unsigned, uint32_t character, uint16_t key_modifiers) {
// retroKeyboardEvent(down, keycode, character, key_modifiers)
//}

//export coreAudioSample
func coreAudioSample(l, r C.int16_t) {
frame := []C.int16_t{l, r}
Expand Down Expand Up @@ -779,6 +789,20 @@ func coreEnvironment(cmd C.unsigned, data unsafe.Pointer) C.bool {
Nan0.log.Debug().Msgf("%v", cInfo.String())
}
return true
case C.RETRO_ENVIRONMENT_GET_INPUT_MAX_USERS:
*(*C.unsigned)(data) = C.unsigned(4)
Nan0.log.Debug().Msgf(">>> set max users: %v", 4)
return true
//case C.RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK:
// Nan0.log.Debug().Msgf("Keyboard event callback was set")
// cb := (*C.struct_retro_keyboard_callback)(data)
// Nan0.Callbacks.KeyboardEvent = func(down bool, keycode uint, character uint32, keyModifiers uint16) {
// C.bridge_retro_keyboard_callback(unsafe.Pointer(&cb.callback), C.bool(down), C.unsigned(keycode), C.uint32_t(character), C.uint16_t(keyModifiers))
// }
// return true
case C.RETRO_ENVIRONMENT_GET_INPUT_BITMASKS:
Nan0.log.Debug().Msgf(">>> Set input bitmasks")
return false
case C.RETRO_ENVIRONMENT_GET_CLEAR_ALL_THREAD_WAITS_CB:
C.bridge_clear_all_thread_waits_cb(data)
return true
Expand Down
1 change: 1 addition & 0 deletions pkg/worker/caged/libretro/nanoarch/nanoarch.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ void bridge_retro_set_input_poll(void *f, void *callback);
void bridge_retro_set_input_state(void *f, void *callback);
void bridge_retro_set_video_refresh(void *f, void *callback);
void bridge_clear_all_thread_waits_cb(void *f);
void bridge_retro_keyboard_callback(void *f, bool down, unsigned keycode, uint32_t character, uint16_t keyModifiers);

bool core_environment_cgo(unsigned cmd, void *data);
int16_t core_input_state_cgo(unsigned port, unsigned device, unsigned index, unsigned id);
Expand Down
10 changes: 9 additions & 1 deletion pkg/worker/coordinatorhandlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package worker

import (
"encoding/base64"
"encoding/binary"

"github.com/giongto35/cloud-game/v3/pkg/api"
"github.com/giongto35/cloud-game/v3/pkg/com"
Expand Down Expand Up @@ -169,7 +170,14 @@ func (c *coordinator) HandleGameStart(rq api.StartGameRequest[com.Uid], w *Worke
}

c.log.Debug().Msg("Start session input poll")
room.WithWebRTC(user.Session).OnMessage = func(data []byte) { r.App().SendControl(user.Index, data) }
s := room.WithWebRTC(user.Session)
s.OnMessage = func(data []byte) { r.App().SendControl(user.Index, data) }
s.OnKeyboard = func(data []byte) {
press := data[4] == 1
key := uint(binary.LittleEndian.Uint32(data))
c.log.Debug().Msgf(">>> got %v, %v, %v", data, press, key)
r.App().SendKeyboardKey(0, press, key)
}

c.RegisterRoom(r.Id())

Expand Down
1 change: 1 addition & 0 deletions web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ <h1>Options</h1>
<script src="js/gui/message.js?v=2"></script>
<script src="js/log.js?v=5"></script>
<script src="js/event/event.js?v=5"></script>
<script src="js/input/libretro.js?v=1"></script>
<script src="js/input/keys.js?v=3"></script>
<script src="js/settings/opts.js?v=2"></script>
<script src="js/settings/settings.js?v=4"></script>
Expand Down
33 changes: 29 additions & 4 deletions web/js/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@
if (KEY.HELP === data.key) helpScreen.show(true, event);
}

state.keyPress(data.key);
state.keyPress(data.key, data.code);
};

// pre-state key release handler
Expand All @@ -241,7 +241,7 @@
// change app state if settings
if (KEY.SETTINGS === data.key) setState(app.state.settings);

state.keyRelease(data.key);
state.keyRelease(data.key, data.code);
};

const updatePlayerIndex = (idx, not_game = false) => {
Expand Down Expand Up @@ -367,8 +367,33 @@
..._default,
name: 'game',
axisChanged: (id, value) => input.setAxisChanged(id, value),
keyPress: key => input.setKeyState(key, true),
keyRelease: function (key) {
keyPress: (key, code) => {
let buffer = new ArrayBuffer(5);
let dv = new DataView(buffer)

dv.setUint8(4, 1)
const k = libretro.map(key, code);
dv.setUint32(0, k, true)

console.log("code", code, k)

webrtc.keyboard(buffer);
input.setKeyState(key, true);
},
keyRelease: function (key, code) {

let buffer = new ArrayBuffer(5);
let dv = new DataView(buffer)

dv.setUint8(4, 0)
const k = libretro.map(key, code);
dv.setUint32(0, k, true)

console.log("code", code, k)


webrtc.keyboard(buffer);

input.setKeyState(key, false);

switch (key) {
Expand Down
2 changes: 1 addition & 1 deletion web/js/input/keyboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ const keyboard = (() => {
return
}
}
event.pub(evt, {key: key})
event.pub(evt, {key: key, code: code})
}

event.sub(DPAD_TOGGLE, (data) => onDpadToggle(data.checked));
Expand Down
Loading

0 comments on commit 79530fb

Please sign in to comment.