Add input

This commit is contained in:
giongto35 2019-04-02 01:18:57 +08:00
parent 4224066b5d
commit 21c4f7aa5c
7 changed files with 168 additions and 103 deletions

View file

@ -6,13 +6,8 @@ textarea {
height: 50px;
}
</style>
<div>
<a href="https://github.com/poi5305/go-yuv2webRTC">https://github.com/poi5305/go-yuv2webRTC</a>
<br />
<a href="https://github.com/pions/webrtc/tree/v1.2.0/examples/gstreamer-send/jsfiddle">https://github.com/pions/webrtc/tree/v1.2.0/examples/gstreamer-send/jsfiddle</a>
</div>
<div id="remoteVideos"></div> <br />
<div id="remoteVideos" ></div> <br />
Browser base64 Session Description <br /><textarea id="localSessionDescription" readonly="true"></textarea> <br />
Golang base64 Session Description: <br /><textarea id="remoteSessionDescription"> </textarea> <br/>
@ -37,6 +32,7 @@ function postSession(session) {
xhttp.open("POST", "/session", true);
xhttp.setRequestHeader("Content-type", "text/plain");
xhttp.send(session);
}
let pc = new RTCPeerConnection({
@ -50,6 +46,11 @@ let log = msg => {
document.getElementById('div').innerHTML += msg + '<br>'
}
let inputChannel = pc.createDataChannel('foo')
inputChannel.onclose = () => console.log('inputChannel has closed')
inputChannel.onopen = () => console.log('inputChannel has opened')
inputChannel.onmessage = e => log(`Message from DataChannel '${inputChannel.label}' payload '${e.data}'`)
pc.ontrack = function (event) {
var el = document.createElement(event.track.kind)
el.srcObject = event.streams[0]
@ -70,6 +71,14 @@ pc.onicecandidate = event => {
pc.createOffer({offerToReceiveVideo: true, offerToReceiveAudio: true}).then(d => pc.setLocalDescription(d)).catch(log)
document.body.onkeydown = function(e){
inputChannel.send(e.keyCode)
};
document.body.onkeyup = function(e){
inputChannel.send(-e.keyCode)
};
window.startSession = () => {
let sd = document.getElementById('remoteSessionDescription').value
if (sd === '') {
@ -84,4 +93,4 @@ window.startSession = () => {
}
</script>
</html>
</html>

10
main.go
View file

@ -11,9 +11,9 @@ import (
"time"
"github.com/giongto35/game-online/ui"
"github.com/giongto35/game-online/webrtc"
"github.com/gorilla/mux"
"github.com/poi5305/go-yuv2webRTC/screenshot"
"github.com/poi5305/go-yuv2webRTC/webrtc"
)
var webRTC *webrtc.WebRTC
@ -23,11 +23,12 @@ var height = 240
func init() {
}
func startGame(path string, imageChannel chan *image.RGBA) {
ui.Run([]string{path}, imageChannel)
func startGame(path string, imageChannel chan *image.RGBA, inputChannel chan int) {
ui.Run([]string{path}, imageChannel, inputChannel)
}
func main() {
imageChannel := make(chan *image.RGBA, 2)
fmt.Println("http://localhost:8000")
webRTC = webrtc.NewWebRTC()
@ -38,9 +39,8 @@ func main() {
go http.ListenAndServe(":8000", router)
// start screenshot loop, wait for connection
imageChannel := make(chan *image.RGBA, 2)
go screenshotLoop(imageChannel)
startGame("games/supermariobros.rom", imageChannel)
startGame("games/supermariobros.rom", imageChannel, webRTC.InputChannel)
time.Sleep(time.Minute)
}

View file

@ -22,13 +22,15 @@ type Director struct {
menuView View
timestamp float64
imageChannel chan *image.RGBA
inputChannel chan int
}
func NewDirector(window *glfw.Window, audio *Audio, imageChannel chan *image.RGBA) *Director {
func NewDirector(window *glfw.Window, audio *Audio, imageChannel chan *image.RGBA, inputChannel chan int) *Director {
director := Director{}
director.window = window
director.audio = audio
director.imageChannel = imageChannel
director.inputChannel = inputChannel
return &director
}
@ -85,7 +87,7 @@ func (d *Director) PlayGame(path string) {
if err != nil {
log.Fatalln(err)
}
d.SetView(NewGameView(d, console, path, hash, d.imageChannel))
d.SetView(NewGameView(d, console, path, hash, d.imageChannel, d.inputChannel))
}
func (d *Director) ShowMenu() {

View file

@ -11,19 +11,37 @@ import (
const padding = 0
type GameView struct {
director *Director
console *nes.Console
title string
hash string
texture uint32
record bool
frames []image.Image
director *Director
console *nes.Console
title string
hash string
texture uint32
record bool
frames []image.Image
keyPressed []bool
imageChannel chan *image.RGBA
inputChannel chan int
}
func NewGameView(director *Director, console *nes.Console, title, hash string, imageChannel chan *image.RGBA) View {
func NewGameView(director *Director, console *nes.Console, title, hash string, imageChannel chan *image.RGBA, inputChannel chan int) View {
texture := createTexture()
return &GameView{director, console, title, hash, texture, false, nil, imageChannel}
gameview := &GameView{director, console, title, hash, texture, false, nil, make([]bool, 255), imageChannel, inputChannel}
go gameview.ListenToInputChannel()
return gameview
}
func (view *GameView) ListenToInputChannel() {
for {
key := <-view.inputChannel
if key < 0 {
view.keyPressed[-key] = false
} else {
view.keyPressed[key] = true
}
}
}
func (view *GameView) Enter() {
@ -75,7 +93,8 @@ func (view *GameView) Update(t, dt float64) {
if readKey(window, glfw.KeyEscape) {
view.director.ShowMenu()
}
updateControllers(window, console)
//updateControllers(window, console)
view.updateControllers()
console.StepSeconds(dt)
gl.BindTexture(gl.TEXTURE_2D, view.texture)
setTexture(console.Buffer())
@ -140,3 +159,17 @@ func updateControllers(window *glfw.Window, console *nes.Console) {
console.SetButtons1(combineButtons(k1, j1))
console.SetButtons2(j2)
}
func (view *GameView) updateControllers() {
// TODO: switch case
var buttons [8]bool
buttons[nes.ButtonLeft] = view.keyPressed[37]
buttons[nes.ButtonUp] = view.keyPressed[38]
buttons[nes.ButtonRight] = view.keyPressed[39]
buttons[nes.ButtonDown] = view.keyPressed[40]
buttons[nes.ButtonA] = view.keyPressed[32]
buttons[nes.ButtonB] = view.keyPressed[17]
buttons[nes.ButtonStart] = view.keyPressed[13]
buttons[nes.ButtonSelect] = view.keyPressed[16]
view.console.Controller1.SetButtons(buttons)
}

View file

@ -25,7 +25,7 @@ func init() {
runtime.LockOSThread()
}
func Run(paths []string, imageChannel chan *image.RGBA) {
func Run(paths []string, imageChannel chan *image.RGBA, inputChannel chan int) {
// initialize audio
portaudio.Initialize()
defer portaudio.Terminate()
@ -58,6 +58,6 @@ func Run(paths []string, imageChannel chan *image.RGBA) {
gl.Enable(gl.TEXTURE_2D)
// run director
director := NewDirector(window, audio, imageChannel)
director := NewDirector(window, audio, imageChannel, inputChannel)
director.Start(paths)
}

View file

@ -1,77 +0,0 @@
package webrtc
import (
"bytes"
"compress/gzip"
"encoding/base64"
"encoding/json"
"io/ioutil"
)
func zip(in []byte) []byte {
var b bytes.Buffer
gz := gzip.NewWriter(&b)
_, err := gz.Write(in)
if err != nil {
panic(err)
}
err = gz.Flush()
if err != nil {
panic(err)
}
err = gz.Close()
if err != nil {
panic(err)
}
return b.Bytes()
}
func unzip(in []byte) []byte {
var b bytes.Buffer
_, err := b.Write(in)
if err != nil {
panic(err)
}
r, err := gzip.NewReader(&b)
if err != nil {
panic(err)
}
res, err := ioutil.ReadAll(r)
if err != nil {
panic(err)
}
return res
}
// Encode encodes the input in base64
// It can optionally zip the input before encoding
func Encode(obj interface{}) string {
b, err := json.Marshal(obj)
if err != nil {
panic(err)
}
if compress {
b = zip(b)
}
return base64.StdEncoding.EncodeToString(b)
}
// Decode decodes the input from base64
// It can optionally unzip the input after decoding
func Decode(in string, obj interface{}) {
b, err := base64.StdEncoding.DecodeString(in)
if err != nil {
panic(err)
}
if compress {
b = unzip(b)
}
err = json.Unmarshal(b, obj)
if err != nil {
panic(err)
}
}

View file

@ -1,8 +1,14 @@
package webrtc
import (
"bytes"
"compress/gzip"
"encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
"math/rand"
"strconv"
"time"
"github.com/pions/webrtc"
@ -15,10 +21,84 @@ var config = webrtc.Configuration{ICEServers: []webrtc.ICEServer{{URLs: []string
// Allows compressing offer/answer to bypass terminal input limits.
const compress = false
func init() {
//api.mediaEngine.RegisterDefaultCodecs()
//webrtc.RegisterDefaultCodecs()
}
func zip(in []byte) []byte {
var b bytes.Buffer
gz := gzip.NewWriter(&b)
_, err := gz.Write(in)
if err != nil {
panic(err)
}
err = gz.Flush()
if err != nil {
panic(err)
}
err = gz.Close()
if err != nil {
panic(err)
}
return b.Bytes()
}
func unzip(in []byte) []byte {
var b bytes.Buffer
_, err := b.Write(in)
if err != nil {
panic(err)
}
r, err := gzip.NewReader(&b)
if err != nil {
panic(err)
}
res, err := ioutil.ReadAll(r)
if err != nil {
panic(err)
}
return res
}
// Encode encodes the input in base64
// It can optionally zip the input before encoding
func Encode(obj interface{}) string {
b, err := json.Marshal(obj)
if err != nil {
panic(err)
}
if compress {
b = zip(b)
}
return base64.StdEncoding.EncodeToString(b)
}
// Decode decodes the input from base64
// It can optionally unzip the input after decoding
func Decode(in string, obj interface{}) {
b, err := base64.StdEncoding.DecodeString(in)
if err != nil {
panic(err)
}
if compress {
b = unzip(b)
}
err = json.Unmarshal(b, obj)
if err != nil {
panic(err)
}
}
// NewWebRTC create
func NewWebRTC() *WebRTC {
w := &WebRTC{
ImageChannel: make(chan []byte, 2),
InputChannel: make(chan int, 2),
}
return w
}
@ -30,6 +110,7 @@ type WebRTC struct {
isConnected bool
// for yuvI420 image
ImageChannel chan []byte
InputChannel chan int
}
// StartClient start webrtc
@ -83,6 +164,23 @@ func (w *WebRTC) StartClient(remoteSession string, width, height int) (string, e
w.StopClient()
}
})
//w.listenInputChannel()
// Data channel
w.connection.OnDataChannel(func(d *webrtc.DataChannel) {
fmt.Printf("New DataChannel %s %d\n", d.Label(), d.ID())
// Register channel opening handling
d.OnOpen(func() {
fmt.Printf("Data channel '%s'-'%d' open.\n", d.Label(), d.ID())
})
// Register text message handling
d.OnMessage(func(msg webrtc.DataChannelMessage) {
fmt.Printf("Message from DataChannel '%s': '%s' byte '%b'\n", d.Label(), string(msg.Data), msg.Data)
i, _ := strconv.Atoi(string(msg.Data))
w.InputChannel <- i
})
})
offer := webrtc.SessionDescription{}
Decode(remoteSession, &offer)