From 1d5310c38c93766b294afdd380e6fb05170aaad5 Mon Sep 17 00:00:00 2001 From: Sean DuBois Date: Fri, 20 Sep 2019 00:31:15 -0700 Subject: Initial commit --- main.go | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 main.go (limited to 'main.go') diff --git a/main.go b/main.go new file mode 100644 index 0000000..8e6befc --- /dev/null +++ b/main.go @@ -0,0 +1,236 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "log" + "net/http" + "strconv" + + "github.com/gorilla/websocket" + "github.com/pion/rtwatch/gst" + "github.com/pion/webrtc/v2" +) + +const homeHTML = ` + + + synced-playback + + + + +
+ + + + +
+ + + + +` + +var ( + upgrader = websocket.Upgrader{ + ReadBufferSize: 1024, + WriteBufferSize: 1024, + } + + peerConnectionConfig = webrtc.Configuration{} + + audioTrack = &webrtc.Track{} + videoTrack = &webrtc.Track{} + pipeline = &gst.Pipeline{} +) + +type websocketMessage struct { + Event string `json:"event"` + Data string `json:"data"` +} + +func main() { + containerPath := "" + httpListenAddress := "" + flag.StringVar(&containerPath, "container-path", "", "path to the media file you want to playback") + flag.StringVar(&httpListenAddress, "http-listen-address", ":8080", "address for HTTP server to listen on") + flag.Parse() + + if containerPath == "" { + panic("-container-path must be specified") + } + + pc, err := webrtc.NewPeerConnection(webrtc.Configuration{ + ICEServers: []webrtc.ICEServer{ + { + URLs: []string{"stun:stun.l.google.com:19302"}, + }, + }, + }) + if err != nil { + log.Fatal(err) + } + + videoTrack, err = pc.NewTrack(webrtc.DefaultPayloadTypeH264, 5000, "synced-video", "synced-video") + if err != nil { + log.Fatal(err) + } + + audioTrack, err = pc.NewTrack(webrtc.DefaultPayloadTypeOpus, 5001, "synced-video", "synced-video") + if err != nil { + log.Fatal(err) + } + + pipeline = gst.CreatePipeline(containerPath, audioTrack, videoTrack) + pipeline.Start() + + http.HandleFunc("/", serveHome) + http.HandleFunc("/ws", serveWs) + + fmt.Println(fmt.Sprintf("Video file '%s' is now available on '%s', have fun!", containerPath, httpListenAddress)) + log.Fatal(http.ListenAndServe(httpListenAddress, nil)) +} + +func handleWebsocketMessage(pc *webrtc.PeerConnection, ws *websocket.Conn, message *websocketMessage) error { + switch message.Event { + case "play": + pipeline.Play() + case "pause": + pipeline.Pause() + case "seek": + i, err := strconv.ParseInt(message.Data, 0, 64) + if err != nil { + log.Print(err) + } + pipeline.SeekToTime(i) + case "offer": + offer := webrtc.SessionDescription{} + if err := json.Unmarshal([]byte(message.Data), &offer); err != nil { + return err + } + + if err := pc.SetRemoteDescription(offer); err != nil { + return err + } + + answer, err := pc.CreateAnswer(nil) + if err != nil { + return err + } + if err := pc.SetLocalDescription(answer); err != nil { + return err + } + + answerString, err := json.Marshal(answer) + if err != nil { + return err + } + + if err = ws.WriteJSON(&websocketMessage{ + Event: "answer", + Data: string(answerString), + }); err != nil { + return err + } + } + return nil +} + +func serveWs(w http.ResponseWriter, r *http.Request) { + ws, err := upgrader.Upgrade(w, r, nil) + if err != nil { + if _, ok := err.(websocket.HandshakeError); !ok { + log.Println(err) + } + return + } + + peerConnection, err := webrtc.NewPeerConnection(peerConnectionConfig) + if err != nil { + log.Print(err) + return + } else if _, err = peerConnection.AddTrack(audioTrack); err != nil { + log.Print(err) + return + } else if _, err = peerConnection.AddTrack(videoTrack); err != nil { + log.Print(err) + return + } + + defer func() { + if err := peerConnection.Close(); err != nil { + log.Println(err) + } + }() + + message := &websocketMessage{} + for { + _, msg, err := ws.ReadMessage() + if err != nil { + break + } else if err := json.Unmarshal(msg, &message); err != nil { + log.Print(err) + return + } + + if err := handleWebsocketMessage(peerConnection, ws, message); err != nil { + log.Print(err) + } + } +} + +func serveHome(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + fmt.Fprintf(w, homeHTML) +} -- cgit v1.2.3