diff --git a/internal/controllers/media_controller.go b/internal/controllers/streaming_controller.go similarity index 100% rename from internal/controllers/media_controller.go rename to internal/controllers/streaming_controller.go diff --git a/internal/web/demo/demo.css b/internal/web/demo/demo.css new file mode 100644 index 0000000..78566e9 --- /dev/null +++ b/internal/web/demo/demo.css @@ -0,0 +1,8 @@ +/* + SPDX-FileCopyrightText: 2023 The Pion community + SPDX-License-Identifier: MIT +*/ +textarea { + width: 500px; + min-height: 75px; +} \ No newline at end of file diff --git a/internal/web/demo/demo.js b/internal/web/demo/demo.js new file mode 100644 index 0000000..1ea6c5d --- /dev/null +++ b/internal/web/demo/demo.js @@ -0,0 +1,67 @@ +/* eslint-env browser */ + +// SPDX-FileCopyrightText: 2023 The Pion community +// SPDX-License-Identifier: MIT + +const pc = new RTCPeerConnection({ + iceServers: [{ + urls: 'stun:stun.l.google.com:19302' + }] + }) + const log = msg => { + document.getElementById('div').innerHTML += msg + '
' + } + + pc.ontrack = function (event) { + const el = document.createElement(event.track.kind) + el.srcObject = event.streams[0] + el.autoplay = true + el.controls = true + + document.getElementById('remoteVideos').appendChild(el) + } + + pc.oniceconnectionstatechange = e => log(pc.iceConnectionState) + pc.onicecandidate = event => { + if (event.candidate === null) { + document.getElementById('localSessionDescription').value = btoa(JSON.stringify(pc.localDescription)) + } + } + + // Offer to receive 1 audio, and 1 video track + pc.addTransceiver('video', { + direction: 'sendrecv' + }) + pc.addTransceiver('audio', { + direction: 'sendrecv' + }) + + pc.createOffer().then(d => pc.setLocalDescription(d)).catch(log) + + window.startSession = () => { + const sd = document.getElementById('remoteSessionDescription').value + if (sd === '') { + return alert('Session Description must not be empty') + } + + try { + pc.setRemoteDescription(JSON.parse(atob(sd))) + } catch (e) { + alert(e) + } + } + + window.copySessionDescription = () => { + const browserSessionDescription = document.getElementById('localSessionDescription') + + browserSessionDescription.focus() + browserSessionDescription.select() + + try { + const successful = document.execCommand('copy') + const msg = successful ? 'successful' : 'unsuccessful' + log('Copying SessionDescription was ' + msg) + } catch (err) { + log('Oops, unable to copy SessionDescription ' + err) + } + } \ No newline at end of file diff --git a/internal/web/demo/index.html b/internal/web/demo/index.html new file mode 100644 index 0000000..d73d0e1 --- /dev/null +++ b/internal/web/demo/index.html @@ -0,0 +1,30 @@ + +Browser Session Description +
+ +
+ + + +
+
+
+ +Remote Session Description +
+ +
+ +
+
+ +Video +
+

+ +Logs +
+
\ No newline at end of file diff --git a/internal/web/demo/readme.txt b/internal/web/demo/readme.txt new file mode 100644 index 0000000..b29ccca --- /dev/null +++ b/internal/web/demo/readme.txt @@ -0,0 +1 @@ +Initially copied from https://github.com/pion/webrtc/tree/master/examples/play-from-disk/jsfiddle \ No newline at end of file diff --git a/internal/web/handlers/signaling.go b/internal/web/handlers/signaling.go index 8da0574..c964844 100644 --- a/internal/web/handlers/signaling.go +++ b/internal/web/handlers/signaling.go @@ -35,21 +35,31 @@ func NewSignalingHandler( func (h *SignalingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { + h.l.Sugar().Errorw("unexpected method") SetError(w, entities.ErrHTTPPostOnly) return } params := entities.RequestParams{} if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil { + h.l.Sugar().Errorw("error while decoding request params json", + "error", err, + ) SetError(w, err) return } if err := params.Valid(); err != nil { + h.l.Sugar().Errorw("invalid params", + "error", err, + ) SetError(w, err) return } if err := h.webRTCController.SetupPeerConnection(); err != nil { + h.l.Sugar().Errorw("error while setting up web rtc connection", + "error", err, + ) SetError(w, err) return } @@ -62,34 +72,52 @@ func (h *SignalingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { }, "video", params.SRTStreamID, ) if err != nil { + h.l.Sugar().Errorw("error while creating a web rtc track", + "error", err, + ) SetError(w, err) return } metadataSender, err := h.webRTCController.CreateDataChannel(entities.MetadataChannelID) if err != nil { + h.l.Sugar().Errorw("error while createing a web rtc data channel", + "error", err, + ) SetError(w, err) } if err = h.webRTCController.SetRemoteDescription(params.Offer); err != nil { + h.l.Sugar().Errorw("error while setting a remote web rtc description", + "error", err, + ) SetError(w, err) return } localDescription, err := h.webRTCController.GatheringWebRTC() if err != nil { + h.l.Sugar().Errorw("error while preparing a local web rtc description", + "error", err, + ) SetError(w, err) return } localOfferDescription, err := json.Marshal(*localDescription) if err != nil { + h.l.Sugar().Errorw("error while encoding a local web rtc description", + "error", err, + ) SetError(w, err) return } srtConnection, err := h.srtController.Connect(¶ms) if err != nil { + h.l.Sugar().Errorw("error while connecting to an srt server", + "error", err, + ) SetError(w, err) return } @@ -97,6 +125,9 @@ func (h *SignalingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { go h.streamingController.Stream(srtConnection, videoTrack, metadataSender) if _, err := w.Write(localOfferDescription); err != nil { + h.l.Sugar().Errorw("error responding the local web rtc offer description", + "error", err, + ) SetError(w, err) return } diff --git a/internal/web/router.go b/internal/web/router.go index 96aac24..a9daf88 100644 --- a/internal/web/router.go +++ b/internal/web/router.go @@ -15,6 +15,7 @@ func NewServeMux( mux.Handle("/", index) mux.Handle("/doSignaling", setCors(signaling)) + mux.Handle("/demo", http.FileServer(http.Dir("./demo"))) return mux } diff --git a/scripts/ffmpeg_srt_live_listener.sh b/scripts/ffmpeg_srt_live_listener.sh index f4d8c82..8c7235c 100755 --- a/scripts/ffmpeg_srt_live_listener.sh +++ b/scripts/ffmpeg_srt_live_listener.sh @@ -3,5 +3,5 @@ ffmpeg -hide_banner -loglevel verbose \ -f lavfi -i "sine=frequency=1000:sample_rate=44100" \ -c:v libx264 -preset veryfast -tune zerolatency -profile:v baseline \ -b:v 1000k -bufsize 2000k -x264opts keyint=30:min-keyint=30:scenecut=-1 \ - -f mpegts "srt://${SRT_LISTENING_HOST}:${SRT_LISTENING_PORT}?mode=listener&latency=${SRT_LISTENING_LATENCY_US}" + -f mpegts "srt://${SRT_LISTENING_HOST}:${SRT_LISTENING_PORT}?mode=listener&latency=${SRT_LISTENING_LATENCY_US}&smoother=live&transtype=live"