embed demo player

This commit is contained in:
Leandro Moreira
2024-02-03 17:19:26 -03:00
parent cf63b8e144
commit e3ee981d3d
12 changed files with 220 additions and 105 deletions

2
.gitignore vendored
View File

@@ -17,3 +17,5 @@ donut
tags
.DS_Store
.vscode

View File

@@ -1,10 +1,18 @@
# Moving player to static
## Date: 2/3/24
### Hypothesis: It's easy to do experimentation with local player
### Summary
Copy and adapt code from https://github.com/flavioribeiro/donut-video into static/demo/
# Investigating a potential memory leak
## Date: 2/2/24
### Hyphotesis: There's a memory leak happening
### Hypothesis: There's a memory leak happening
### Signs: pprof/allocs
![allocs profile print screen 1](imgs/entry_memory_leak/allocs_pprof001.svg "allocs profile print screen 1")
### Sumary
### Summary
* Start the donut `make run`,
* Check the general profiling http://localhost:6060/debug/pprof/?debug=1

View File

@@ -26,7 +26,7 @@ func NewStreamingController(c *entities.Config, l *zap.SugaredLogger) *Streaming
}
}
func (c *StreamingController) Stream(sp entities.StreamParameters) {
func (c *StreamingController) Stream(sp *entities.StreamParameters) {
r, w := io.Pipe()
defer r.Close()
@@ -78,7 +78,7 @@ func (c *StreamingController) Stream(sp entities.StreamParameters) {
}
}
func (c *StreamingController) writeMpegtsToWebRTC(mpegTSDemuxData *astits.DemuxerData, h264PID uint16, err error, sp entities.StreamParameters, eia608Reader *EIA608Reader) error {
func (c *StreamingController) writeMpegtsToWebRTC(mpegTSDemuxData *astits.DemuxerData, h264PID uint16, err error, sp *entities.StreamParameters, eia608Reader *EIA608Reader) error {
if mpegTSDemuxData.PID == h264PID && mpegTSDemuxData.PES != nil {
if err = sp.VideoTrack.WriteSample(media.Sample{Data: mpegTSDemuxData.PES.Data, Duration: time.Second / 30}); err != nil {

View File

@@ -1,67 +0,0 @@
/* eslint-env browser */
// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT
const pc = new RTCPeerConnection({
iceServers: [{
urls: 'stun:stun.l.google.com:19302'
}]
})
const log = msg => {
document.getElementById('div').innerHTML += msg + '<br>'
}
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)
}
}

View File

@@ -1,30 +0,0 @@
<!--
SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
SPDX-License-Identifier: MIT
-->
Browser Session Description
<br/>
<textarea id="localSessionDescription" readonly="true"></textarea>
<br/>
<button onclick="window.copySessionDescription()">Copy browser Session Description to clipboard</button>
<br/>
<br/>
<br/>
Remote Session Description
<br/>
<textarea id="remoteSessionDescription"></textarea>
<br/>
<button onclick="window.startSession()">Start Session</button>
<br/>
<br/>
Video
<br/>
<div id="remoteVideos"></div> <br />
Logs
<br/>
<div id="div"></div>

View File

@@ -1 +0,0 @@
Initially copied from https://github.com/pion/webrtc/tree/master/examples/play-from-disk/jsfiddle

View File

@@ -81,7 +81,7 @@ func (h *SignalingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) err
metadataSender, err := h.webRTCController.CreateDataChannel(peer, entities.MetadataChannelID)
if err != nil {
h.l.Errorw("error while createing a web rtc data channel",
h.l.Errorw("error while creating a web rtc data channel",
"error", err,
)
return err
@@ -110,7 +110,7 @@ func (h *SignalingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) err
return err
}
go h.streamingController.Stream(entities.StreamParameters{
go h.streamingController.Stream(&entities.StreamParameters{
Cancel: cancel,
Ctx: ctx,
WebRTCConn: peer,

View File

@@ -20,8 +20,11 @@ func NewServeMux(
mux := http.NewServeMux()
mux.Handle("/", index)
fs := http.FileServer(http.Dir("./static"))
mux.Handle("/demo/", http.StripPrefix("/demo/", fs))
mux.Handle("/doSignaling", setCors(errorHandler(l, signaling)))
mux.Handle("/demo", http.FileServer(http.Dir("./demo")))
return mux
}

View File

@@ -3,4 +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 \
-c:a aac -b:a 128k \
-f mpegts "udp://${SRT_INPUT_HOST}:${SRT_INPUT_PORT}?pkt_size=${PKT_SIZE}"

133
static/demo.js Normal file
View File

@@ -0,0 +1,133 @@
// just to avoid adding dup messages
window.metadataMessages = {}
window.startSession = () => {
let srtHost = document.getElementById('srt-host').value;
let srtPort = document.getElementById('srt-port').value;
let srtStreamId = document.getElementById('srt-stream-id').value;
setupWebRTC((pc, offer) => {
let srtFullAddress = JSON.stringify({
"srtHost": srtHost,
"srtPort": srtPort,
"srtStreamId": srtStreamId,
offer
});
// sending localSDP,SRT params, and fetching remote SDP
fetchRemoteDescription(srtFullAddress).then(remoteOffer => {
log("receiving remote sdp offer: " + JSON.stringify(remoteOffer));
if (remoteOffer === undefined) {
log("error while fetching remote");
return;
}
pc.setRemoteDescription(remoteOffer);
}).catch(log, "error");
});
}
const setupWebRTC = (setRemoteSDPfn) => {
log("setting up web rtc");
const pc = new RTCPeerConnection({
iceServers: [{
urls: 'stun:stun.l.google.com:19302'
}]
});
// offer to (only) receive 1 audio, and 1 video track
pc.addTransceiver('video', {
direction: 'recvonly'
});
pc.addTransceiver('audio', {
direction: 'recvonly'
});
// once a track arrives, add it to the remoteVideos div
// with auto play.
pc.ontrack = function (event) {
const el = document.createElement(event.track.kind);
el.srcObject = event.streams[0];
el.autoplay = true
el.controls = true;
el.width = "640";
el.height = "360";
document.getElementById('remoteVideos').appendChild(el);
}
pc.createDataChannel('metadata');
// once the metadata arrives, add it to the metadata div
pc.ondatachannel = (e) => {
log("ondatachannel: " + e);
e.channel.onmessage = (event) => {
let msg = JSON.parse(event.data)
if (msg.Message in metadataMessages) {
// avoid logging dup messages
return;
}
const el = document.createElement("p")
el.innerText = msg.Type.padEnd(8, ' ') + ": " + msg.Message
let metadata = document.getElementById('metadata');
metadata.insertBefore(el, metadata.firstChild);
metadataMessages[msg.Message] = true;
};
};
pc.oniceconnectionstatechange = e => log("ice state change: " + pc.iceConnectionState);
pc.onicegatheringstatechange = e => log("gathering state change: " + pc.iceGatheringState);
pc.onsignalingstatechange = e => log("signaling state change: " + pc.signalingState);
// creating a local sdp offer
pc.createOffer()
.then(offer => {
pc.setLocalDescription(offer);
setRemoteSDPfn(pc, offer);
}).catch(log, "error");
}
const fetchRemoteDescription = async (bodyRequest) => {
log("requesting remote sdp offer for: " + bodyRequest)
const res = await fetch('/doSignaling', {
method: 'post',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json'
},
body: bodyRequest
});
if (res.status !== 200) {
res.text().then(err => {
log(err, "error");
window.alert(err);
});
return;
}
return res.json();
}
const formattedNow = () => {
let now = new Date();
let minutes = now.getMinutes().toString().padStart(2, '0');
let seconds = now.getSeconds().toString().padStart(2, '0');
let ms = now.getMilliseconds().toString().padStart(3, '0');
return minutes + ":" + seconds + ":" + ms;
}
const log = (msg, level = "info") => {
const el = document.createElement("p")
if (level === "error") {
el.style = "color: red;background-color: yellow;";
}
el.innerText = "[[" + level.toUpperCase().padEnd(5, ' ') + "]] " + formattedNow() + " : " + msg
let logEl = document.getElementById('log');
logEl.insertBefore(el, logEl.firstChild);
}

66
static/index.html Normal file
View File

@@ -0,0 +1,66 @@
<html>
<head>
<title>donut</title>
<script src="demo.js"></script>
<style src="demo.css"></style>
</head>
<body>
<h1>SRT Config</h1>
<b> SRT Host </b>
<input type="text" id="srt-host" value="srt"> <br />
<b> SRT Port </b>
<input type="text" id="srt-port" value="40052" /> <br />
<b> SRT Stream ID </b>
<input type="text" id="srt-stream-id" value="stream-id" /> <br />
<button onclick="onConnect()"> Connect </button>
<h1>Video</h1>
<div id="remoteVideos"></div>
<h1>Metadata</h1>
<div id="metadata"></div>
<h1>Logs</h1>
<div id="log"></div>
</body>
<script>
function docReady(fn) {
if (document.readyState === "complete" || document.readyState === "interactive") {
setTimeout(fn, 1);
} else {
document.addEventListener("DOMContentLoaded", fn);
}
}
docReady(function () {
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
window.onConnect = () => {
window.startSession();
}
if (urlParams.has('srtHost')) {
document.getElementById('srt-host').value = urlParams.get('srtHost');
}
if (urlParams.has('srtPort')) {
document.getElementById('srt-port').value = urlParams.get('srtPort');
}
if (urlParams.has('srtStreamId')) {
document.getElementById('srt-stream-id').value = urlParams.get('srtStreamId');
}
if (urlParams.get('autoplay') === "true") {
onConnect();
}
});
</script>
</html>