webrtc-streamer 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +316 -240
- package/docs/api.md +11 -0
- package/html/admin.html +2 -2
- package/html/help.html +3 -3
- package/html/index.html +2 -2
- package/html/{janusvideoroom.json → janusconfig.js} +0 -0
- package/html/janustest.html +2 -2
- package/html/janusvideoroom.html +10 -21
- package/html/jitsiroom.html +1 -1
- package/html/jitsitest.html +2 -2
- package/html/libs/adapter.min.js +40 -6
- package/html/libs/blazeface +17 -0
- package/html/libs/lib-jitsi-meet.min.js +2 -25
- package/html/map.html +1 -1
- package/html/sendstream.html +17 -22
- package/html/tensorflow.js +45 -12
- package/html/webrtc-streamer-algo-element.js +1 -0
- package/html/webrtc-streamer-element.html +1 -0
- package/html/webrtc-streamer-element.js +23 -9
- package/html/webrtc-streamer-footer-element.js +1 -1
- package/html/{webrtcstreamer.json → webrtcconfig.js} +0 -0
- package/html/webrtcstreamer.html +1 -1
- package/html/webrtcstreamer.js +34 -40
- package/html/whipclient.html +76 -0
- package/html/{xmppvideoroom.json → xmppconfig.js} +0 -0
- package/html/xmppvideoroom.html +2 -2
- package/libv4l2cpp/README.md +6 -6
- package/libv4l2cpp/inc/V4l2Access.h +8 -9
- package/libv4l2cpp/inc/V4l2Capture.h +2 -2
- package/libv4l2cpp/inc/V4l2Device.h +20 -12
- package/libv4l2cpp/inc/V4l2MmapDevice.h +2 -2
- package/libv4l2cpp/inc/V4l2Output.h +4 -4
- package/libv4l2cpp/main.cpp +118 -0
- package/libv4l2cpp/src/V4l2Capture.cpp +4 -4
- package/libv4l2cpp/src/V4l2Device.cpp +7 -7
- package/libv4l2cpp/src/V4l2MmapDevice.cpp +2 -2
- package/libv4l2cpp/src/V4l2Output.cpp +6 -6
- package/package.json +1 -1
package/html/map.html
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
z-index: 1;
|
|
16
16
|
}
|
|
17
17
|
</style>
|
|
18
|
-
<script src="./
|
|
18
|
+
<script src="./webrtcconfig.js"></script>
|
|
19
19
|
<script type="module" src="./webrtc-streamer-element.js"></script>
|
|
20
20
|
<script src="https://maps.googleapis.com/maps/api/js?v=3"></script>
|
|
21
21
|
<script src="./htmlmapmarker.js"></script>
|
package/html/sendstream.html
CHANGED
|
@@ -3,40 +3,35 @@
|
|
|
3
3
|
<link rel="stylesheet" type="text/css" href="styles.css">
|
|
4
4
|
<script src="libs/adapter.min.js" ></script>
|
|
5
5
|
<script src="webrtcstreamer.js" ></script>
|
|
6
|
-
<script src="
|
|
6
|
+
<script src="webrtcconfig.js" ></script>
|
|
7
7
|
<script>
|
|
8
|
+
let video = "";
|
|
9
|
+
let options = webrtcConfig.options;
|
|
8
10
|
if (location.search.slice(1)) {
|
|
9
|
-
var url = { video:location.search.slice(1) };
|
|
10
|
-
var options = webrtcConfig.options;
|
|
11
11
|
if (typeof URLSearchParams != 'undefined') {
|
|
12
12
|
var params = new URLSearchParams(location.search);
|
|
13
|
-
if (params.has("video")
|
|
14
|
-
|
|
13
|
+
if (params.has("video")) {
|
|
14
|
+
video = params.get("video");
|
|
15
15
|
}
|
|
16
16
|
if (params.has("options")) {
|
|
17
17
|
options = params.get("options");
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
+
}
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
var videoElement = document.getElementById("localvideo");
|
|
26
|
-
videoElement.src = URL.createObjectURL(stream);
|
|
27
|
-
videoElement.play();
|
|
22
|
+
window.onload = function() {
|
|
23
|
+
this.webRtcServer = new WebRtcStreamer("remotevideo", webrtcConfig.url);
|
|
24
|
+
navigator.mediaDevices.getUserMedia({video: true, audio: true}).then(stream => {
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
alert("WebRTC stream name to connect is missing\n\nUsage :" + window.location + "?video=<WebRTC video stream name>&audio=<WebRTC audio stream name>&options=<WebRTC options>")
|
|
36
|
-
} else {
|
|
37
|
-
alert("WebRTC stream name to connect is missing\n\nUsage :" + window.location + "?<WebRTC video stream name>")
|
|
26
|
+
var videoElement = document.getElementById("localvideo");
|
|
27
|
+
videoElement.srcObject = stream;
|
|
28
|
+
videoElement.play();
|
|
29
|
+
|
|
30
|
+
this.webRtcServer.connect(video, "", options, stream)
|
|
31
|
+
})
|
|
38
32
|
}
|
|
39
|
-
|
|
33
|
+
window.onbeforeunload = function() { this.webRtcServer.disconnect() }
|
|
34
|
+
|
|
40
35
|
</script>
|
|
41
36
|
</head>
|
|
42
37
|
<body>
|
package/html/tensorflow.js
CHANGED
|
@@ -24,9 +24,11 @@ window.runDetect = (model, video, canvas) => {
|
|
|
24
24
|
predictions[i].bbox[1] > 10 ? predictions[i].bbox[1] - 5 : 10);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
window.setTimeout(() => {
|
|
28
|
+
if (model.run) {
|
|
29
|
+
model.run(model, video, canvas);
|
|
30
|
+
}
|
|
31
|
+
}, 120);
|
|
30
32
|
});
|
|
31
33
|
}
|
|
32
34
|
|
|
@@ -70,9 +72,11 @@ window.runPosenet = (model, video, canvas) => {
|
|
|
70
72
|
|
|
71
73
|
});
|
|
72
74
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
window.setTimeout(() => {
|
|
76
|
+
if (model.run) {
|
|
77
|
+
model.run(model, video, canvas);
|
|
78
|
+
}
|
|
79
|
+
}, 120);
|
|
76
80
|
});
|
|
77
81
|
}
|
|
78
82
|
|
|
@@ -113,9 +117,11 @@ window.runDeeplab = (model, video, canvas) => {
|
|
|
113
117
|
cnt++
|
|
114
118
|
});
|
|
115
119
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
120
|
+
window.setTimeout(() => {
|
|
121
|
+
if (model.run) {
|
|
122
|
+
model.run(model, video, canvas);
|
|
123
|
+
}
|
|
124
|
+
}, 120);
|
|
119
125
|
});
|
|
120
126
|
}
|
|
121
127
|
|
|
@@ -135,9 +141,36 @@ window.runbodyPix = (model, video, canvas) => {
|
|
|
135
141
|
bodyPix.drawMask(canvas, video, coloredPartImageData, 0.3);
|
|
136
142
|
}
|
|
137
143
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
144
|
+
window.setTimeout(() => {
|
|
145
|
+
if (model.run) {
|
|
146
|
+
model.run(model, video, canvas);
|
|
147
|
+
}
|
|
148
|
+
}, 120);
|
|
141
149
|
});
|
|
142
150
|
}
|
|
143
151
|
|
|
152
|
+
window.runblazeface = (model, video, canvas) => {
|
|
153
|
+
|
|
154
|
+
console.time('runblazeface');
|
|
155
|
+
model.estimateFaces(video, false).then(predictions => {
|
|
156
|
+
console.timeEnd('runblazeface');
|
|
157
|
+
|
|
158
|
+
console.log('predictions: ', predictions);
|
|
159
|
+
|
|
160
|
+
const ctx = canvas.getContext('2d');
|
|
161
|
+
context.clearRect(0, 0, canvas.width, canvas.height);
|
|
162
|
+
for (let i = 0; i < predictions.length; i++) {
|
|
163
|
+
const start = predictions[i].topLeft;
|
|
164
|
+
const end = predictions[i].bottomRight;
|
|
165
|
+
const size = [end[0] - start[0], end[1] - start[1]];
|
|
166
|
+
|
|
167
|
+
ctx.rect(start[0], start[1], size[0], size[1]);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
window.setTimeout(() => {
|
|
171
|
+
if (model.run) {
|
|
172
|
+
model.run(model, video, canvas);
|
|
173
|
+
}
|
|
174
|
+
}, 120);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
<script src="libs/posenet"> </script>
|
|
11
11
|
<script src="libs/deeplab"> </script>
|
|
12
12
|
<script src="libs/body-pix"></script>
|
|
13
|
+
<script src="libs/blazeface"></script>
|
|
13
14
|
<script type="module" src="webrtc-streamer-element.js"></script>
|
|
14
15
|
<script type="module" src="webrtc-streamer-footer-element.js"></script>
|
|
15
16
|
<script type="module" src="webrtc-streamer-menu-element.js"></script>
|
|
@@ -22,7 +22,7 @@ class WebRTCStreamerElement extends HTMLElement {
|
|
|
22
22
|
this.titleElement = this.shadowDOM.getElementById("title");
|
|
23
23
|
this.videoElement = this.shadowDOM.getElementById("video");
|
|
24
24
|
this.canvasElement = this.shadowDOM.getElementById("canvas");
|
|
25
|
-
this.modelLoaded =
|
|
25
|
+
this.modelLoaded = {};
|
|
26
26
|
}
|
|
27
27
|
connectedCallback() {
|
|
28
28
|
this.connectStream(true);
|
|
@@ -96,13 +96,14 @@ class WebRTCStreamerElement extends HTMLElement {
|
|
|
96
96
|
imgLoaded = new Promise( (resolve) => resolve() );
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
const algo = this.getAttribute("algo")
|
|
100
|
+
let modelLoaded = this.getModelPromise(algo);
|
|
100
101
|
|
|
101
102
|
Promise.all([imgLoaded, modelLoaded]).then(([event,model]) => {
|
|
102
103
|
this.setVideoSize(this.videoElement.videoWidth, this.videoElement.videoHeight)
|
|
103
104
|
|
|
104
|
-
|
|
105
|
-
|
|
105
|
+
model.run = this.getModelRunFunction(algo);
|
|
106
|
+
if (model.run) {
|
|
106
107
|
model.run(model, this.videoElement, this.canvasElement)
|
|
107
108
|
modelLoaded.model = model;
|
|
108
109
|
}
|
|
@@ -117,7 +118,6 @@ class WebRTCStreamerElement extends HTMLElement {
|
|
|
117
118
|
this.canvasElement.width = width;
|
|
118
119
|
this.canvasElement.height = height;
|
|
119
120
|
}
|
|
120
|
-
|
|
121
121
|
getModelPromise(algo) {
|
|
122
122
|
let modelLoaded;
|
|
123
123
|
if (this.modelLoaded[algo]) {
|
|
@@ -126,16 +126,14 @@ class WebRTCStreamerElement extends HTMLElement {
|
|
|
126
126
|
else {
|
|
127
127
|
if (algo === "posenet") {
|
|
128
128
|
modelLoaded = posenet.load();
|
|
129
|
-
modelLoaded.run = runPosenet;
|
|
130
129
|
} else if (algo === "deeplab") {
|
|
131
130
|
modelLoaded = deeplab.load()
|
|
132
|
-
modelLoaded.run = runDeeplab;
|
|
133
131
|
} else if (algo === "cocossd") {
|
|
134
132
|
modelLoaded = cocoSsd.load();
|
|
135
|
-
modelLoaded.run = runDetect;
|
|
136
133
|
} else if (algo === "bodyPix") {
|
|
137
134
|
modelLoaded = bodyPix.load();
|
|
138
|
-
|
|
135
|
+
} else if (algo === "blazeface") {
|
|
136
|
+
modelLoaded = blazeface.load();
|
|
139
137
|
} else {
|
|
140
138
|
modelLoaded = new Promise( (resolve) => resolve() );
|
|
141
139
|
}
|
|
@@ -143,6 +141,22 @@ class WebRTCStreamerElement extends HTMLElement {
|
|
|
143
141
|
}
|
|
144
142
|
return modelLoaded;
|
|
145
143
|
}
|
|
144
|
+
|
|
145
|
+
getModelRunFunction(algo) {
|
|
146
|
+
let modelFunction;
|
|
147
|
+
if (algo === "posenet") {
|
|
148
|
+
modelFunction = runPosenet;
|
|
149
|
+
} else if (algo === "deeplab") {
|
|
150
|
+
modelFunction = runDeeplab;
|
|
151
|
+
} else if (algo === "cocossd") {
|
|
152
|
+
modelFunction = runDetect;
|
|
153
|
+
} else if (algo === "bodyPix") {
|
|
154
|
+
modelFunction = runbodyPix;
|
|
155
|
+
} else if (algo === "blazeface") {
|
|
156
|
+
modelFunction = runblazeface;
|
|
157
|
+
}
|
|
158
|
+
return modelFunction;
|
|
159
|
+
}
|
|
146
160
|
}
|
|
147
161
|
|
|
148
162
|
customElements.define('webrtc-streamer', WebRTCStreamerElement);
|
|
@@ -28,7 +28,7 @@ class WebRTCStreamerFooterElement extends HTMLElement {
|
|
|
28
28
|
let footerElement = this.shadowDOM.getElementById("footer");
|
|
29
29
|
const webrtcurl = this.getAttribute("webrtcurl") || "";
|
|
30
30
|
fetch(webrtcurl + "/api/version").then(r => r.text()).then( function (response) {
|
|
31
|
-
footerElement.innerHTML = "<p><a href='https://github.com/mpromonet/webrtc-streamer'>WebRTC-Streamer</a> " +
|
|
31
|
+
footerElement.innerHTML = "<p><a href='https://github.com/mpromonet/webrtc-streamer'>WebRTC-Streamer</a> " + response.split(" ")[0] + "</p>";
|
|
32
32
|
});
|
|
33
33
|
|
|
34
34
|
}
|
|
File without changes
|
package/html/webrtcstreamer.html
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<head>
|
|
3
3
|
<link rel="stylesheet" type="text/css" href="styles.css">
|
|
4
4
|
<script src="libs/adapter.min.js" ></script>
|
|
5
|
-
<script src="
|
|
5
|
+
<script src="webrtcconfig.js" ></script>
|
|
6
6
|
<script src="webrtcstreamer.js" ></script>
|
|
7
7
|
<script>
|
|
8
8
|
if (location.search.slice(1)) {
|
package/html/webrtcstreamer.js
CHANGED
|
@@ -45,7 +45,7 @@ WebRtcStreamer.prototype.connect = function(videourl, audiourl, options, localst
|
|
|
45
45
|
fetch(this.srvurl + "/api/getIceServers")
|
|
46
46
|
.then(this._handleHttpErrors)
|
|
47
47
|
.then( (response) => (response.json()) )
|
|
48
|
-
.then( (response) => this.onReceiveGetIceServers
|
|
48
|
+
.then( (response) => this.onReceiveGetIceServers(response, videourl, audiourl, options, localstream))
|
|
49
49
|
.catch( (error) => this.onError("getIceServers " + error ))
|
|
50
50
|
|
|
51
51
|
} else {
|
|
@@ -64,7 +64,7 @@ WebRtcStreamer.prototype.disconnect = function() {
|
|
|
64
64
|
});
|
|
65
65
|
}
|
|
66
66
|
if (this.pc) {
|
|
67
|
-
fetch(this.srvurl + "/api/hangup?peerid="+this.pc.peerid)
|
|
67
|
+
fetch(this.srvurl + "/api/hangup?peerid=" + this.pc.peerid)
|
|
68
68
|
.then(this._handleHttpErrors)
|
|
69
69
|
.catch( (error) => this.onError("hangup " + error ))
|
|
70
70
|
|
|
@@ -88,7 +88,7 @@ WebRtcStreamer.prototype.onReceiveGetIceServers = function(iceServers, videourl,
|
|
|
88
88
|
try {
|
|
89
89
|
this.createPeerConnection();
|
|
90
90
|
|
|
91
|
-
var callurl = this.srvurl + "/api/call?peerid="+ this.pc.peerid+"&url="+encodeURIComponent(videourl);
|
|
91
|
+
var callurl = this.srvurl + "/api/call?peerid=" + this.pc.peerid + "&url=" + encodeURIComponent(videourl);
|
|
92
92
|
if (audiourl) {
|
|
93
93
|
callurl += "&audiourl="+encodeURIComponent(audiourl);
|
|
94
94
|
}
|
|
@@ -104,25 +104,23 @@ WebRtcStreamer.prototype.onReceiveGetIceServers = function(iceServers, videourl,
|
|
|
104
104
|
this.earlyCandidates.length = 0;
|
|
105
105
|
|
|
106
106
|
// create Offer
|
|
107
|
-
|
|
108
|
-
this.pc.createOffer(this.mediaConstraints).then(function(sessionDescription) {
|
|
107
|
+
this.pc.createOffer(this.mediaConstraints).then((sessionDescription) => {
|
|
109
108
|
console.log("Create offer:" + JSON.stringify(sessionDescription));
|
|
110
109
|
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
this.pc.setLocalDescription(sessionDescription)
|
|
111
|
+
.then(() => {
|
|
113
112
|
fetch(callurl, { method: "POST", body: JSON.stringify(sessionDescription) })
|
|
114
|
-
.then(
|
|
113
|
+
.then(this._handleHttpErrors)
|
|
115
114
|
.then( (response) => (response.json()) )
|
|
116
|
-
.catch( (error) =>
|
|
117
|
-
.then( (response) =>
|
|
118
|
-
.catch( (error) =>
|
|
115
|
+
.catch( (error) => this.onError("call " + error ))
|
|
116
|
+
.then( (response) => this.onReceiveCall(response) )
|
|
117
|
+
.catch( (error) => this.onError("call " + error ))
|
|
119
118
|
|
|
120
|
-
}
|
|
121
|
-
, function(error) {
|
|
119
|
+
}, (error) => {
|
|
122
120
|
console.log ("setLocalDescription error:" + JSON.stringify(error));
|
|
123
|
-
}
|
|
121
|
+
});
|
|
124
122
|
|
|
125
|
-
},
|
|
123
|
+
}, (error) => {
|
|
126
124
|
alert("Create offer error:" + JSON.stringify(error));
|
|
127
125
|
});
|
|
128
126
|
|
|
@@ -137,8 +135,8 @@ WebRtcStreamer.prototype.getIceCandidate = function() {
|
|
|
137
135
|
fetch(this.srvurl + "/api/getIceCandidate?peerid=" + this.pc.peerid)
|
|
138
136
|
.then(this._handleHttpErrors)
|
|
139
137
|
.then( (response) => (response.json()) )
|
|
140
|
-
.then( (response) => this.onReceiveCandidate
|
|
141
|
-
.catch( (error) =>
|
|
138
|
+
.then( (response) => this.onReceiveCandidate(response))
|
|
139
|
+
.catch( (error) => this.onError("getIceCandidate " + error ))
|
|
142
140
|
}
|
|
143
141
|
|
|
144
142
|
/*
|
|
@@ -150,22 +148,21 @@ WebRtcStreamer.prototype.createPeerConnection = function() {
|
|
|
150
148
|
var pc = this.pc;
|
|
151
149
|
pc.peerid = Math.random();
|
|
152
150
|
|
|
153
|
-
|
|
154
|
-
pc.
|
|
155
|
-
pc.
|
|
156
|
-
pc.oniceconnectionstatechange = function(evt) {
|
|
151
|
+
pc.onicecandidate = (evt) => this.onIceCandidate(evt);
|
|
152
|
+
pc.onaddstream = (evt) => this.onAddStream(evt);
|
|
153
|
+
pc.oniceconnectionstatechange = (evt) => {
|
|
157
154
|
console.log("oniceconnectionstatechange state: " + pc.iceConnectionState);
|
|
158
|
-
if (
|
|
155
|
+
if (this.videoElement) {
|
|
159
156
|
if (pc.iceConnectionState === "connected") {
|
|
160
|
-
|
|
157
|
+
this.videoElement.style.opacity = "1.0";
|
|
161
158
|
}
|
|
162
159
|
else if (pc.iceConnectionState === "disconnected") {
|
|
163
|
-
|
|
160
|
+
this.videoElement.style.opacity = "0.25";
|
|
164
161
|
}
|
|
165
162
|
else if ( (pc.iceConnectionState === "failed") || (pc.iceConnectionState === "closed") ) {
|
|
166
|
-
|
|
163
|
+
this.videoElement.style.opacity = "0.5";
|
|
167
164
|
} else if (pc.iceConnectionState === "new") {
|
|
168
|
-
|
|
165
|
+
this.getIceCandidate();
|
|
169
166
|
}
|
|
170
167
|
}
|
|
171
168
|
}
|
|
@@ -244,10 +241,9 @@ WebRtcStreamer.prototype.onAddStream = function(event) {
|
|
|
244
241
|
this.videoElement.srcObject = event.stream;
|
|
245
242
|
var promise = this.videoElement.play();
|
|
246
243
|
if (promise !== undefined) {
|
|
247
|
-
|
|
248
|
-
promise.catch(function(error) {
|
|
244
|
+
promise.catch((error) => {
|
|
249
245
|
console.warn("error:"+error);
|
|
250
|
-
|
|
246
|
+
this.videoElement.setAttribute("controls", true);
|
|
251
247
|
});
|
|
252
248
|
}
|
|
253
249
|
}
|
|
@@ -256,20 +252,19 @@ WebRtcStreamer.prototype.onAddStream = function(event) {
|
|
|
256
252
|
* AJAX /call callback
|
|
257
253
|
*/
|
|
258
254
|
WebRtcStreamer.prototype.onReceiveCall = function(dataJson) {
|
|
259
|
-
|
|
255
|
+
|
|
260
256
|
console.log("offer: " + JSON.stringify(dataJson));
|
|
261
257
|
var descr = new RTCSessionDescription(dataJson);
|
|
262
|
-
this.pc.setRemoteDescription(descr
|
|
263
|
-
, function() {
|
|
258
|
+
this.pc.setRemoteDescription(descr).then(() => {
|
|
264
259
|
console.log ("setRemoteDescription ok");
|
|
265
|
-
while (
|
|
266
|
-
var candidate =
|
|
267
|
-
|
|
260
|
+
while (this.earlyCandidates.length) {
|
|
261
|
+
var candidate = this.earlyCandidates.shift();
|
|
262
|
+
this.addIceCandidate(this.pc.peerid, candidate);
|
|
268
263
|
}
|
|
269
264
|
|
|
270
|
-
|
|
265
|
+
this.getIceCandidate()
|
|
271
266
|
}
|
|
272
|
-
,
|
|
267
|
+
, (error) => {
|
|
273
268
|
console.log ("setRemoteDescription error:" + JSON.stringify(error));
|
|
274
269
|
});
|
|
275
270
|
}
|
|
@@ -284,9 +279,8 @@ WebRtcStreamer.prototype.onReceiveCandidate = function(dataJson) {
|
|
|
284
279
|
var candidate = new RTCIceCandidate(dataJson[i]);
|
|
285
280
|
|
|
286
281
|
console.log("Adding ICE candidate :" + JSON.stringify(candidate) );
|
|
287
|
-
this.pc.addIceCandidate(candidate
|
|
288
|
-
,
|
|
289
|
-
, function(error) { console.log ("addIceCandidate error:" + JSON.stringify(error)); } );
|
|
282
|
+
this.pc.addIceCandidate(candidate).then( () => { console.log ("addIceCandidate OK"); }
|
|
283
|
+
, (error) => { console.log ("addIceCandidate error:" + JSON.stringify(error)); } );
|
|
290
284
|
}
|
|
291
285
|
this.pc.addIceCandidate();
|
|
292
286
|
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<link rel="icon" type="image/png" href="webrtc.png" />
|
|
5
|
+
<script type="module" src="webrtc-streamer-footer-element.js"></script>
|
|
6
|
+
<script type="module" src="webrtc-streamer-menu-element.js"></script>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
WHIP Url:<input id="whipServer" type="text" size="50" value="http://localhost:7080/whip"/>
|
|
10
|
+
|
|
11
|
+
<webrtc-streamer-menu id="selector" ></webrtc-streamer-menu>
|
|
12
|
+
<webrtc-streamer-footer></webrtc-streamer-footer>
|
|
13
|
+
|
|
14
|
+
<script>
|
|
15
|
+
const srvurl = location.protocol+"//"+window.location.hostname+":"+window.location.port;
|
|
16
|
+
function onWhipPublish(response, peerid) {
|
|
17
|
+
console.log("onWhipPublish:"+JSON.stringify(response));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function onCreateOffer(response, peerid) {
|
|
21
|
+
console.log("onCreateOffer:"+JSON.stringify(response));
|
|
22
|
+
|
|
23
|
+
var whipUrl = "http://127.0.0.1:7080/whip/endpoint/aa";
|
|
24
|
+
|
|
25
|
+
fetch(whipUrl, {method: "POST", body: response.sdp, headers:{"Content-Type": "application/sdp"}})
|
|
26
|
+
.then( (response) => (response.text()) )
|
|
27
|
+
.then( (response) => onWhipPublish(response, peerid) )
|
|
28
|
+
.catch( (error) => console.log("whipUrl " + error ))
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
customElements.whenDefined('webrtc-streamer-menu').then(() => {
|
|
32
|
+
let selectorElement = document.getElementById("selector");
|
|
33
|
+
|
|
34
|
+
let url;
|
|
35
|
+
if (typeof URLSearchParams != 'undefined') {
|
|
36
|
+
var params = new URLSearchParams(location.search);
|
|
37
|
+
if (params.has("video") || params.has("audio")) {
|
|
38
|
+
url = { video:params.get("video"), audio:params.get("audio") };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
selectorElement.addEventListener('init', (event) => {
|
|
43
|
+
if (url) {
|
|
44
|
+
let media = JSON.stringify(url)
|
|
45
|
+
selectorElement.setAttribute('selected', media);
|
|
46
|
+
} else {
|
|
47
|
+
let mediaList = event.detail;
|
|
48
|
+
if (mediaList.length > 0) {
|
|
49
|
+
var random = mediaList.sort(() => .5 - Math.random());
|
|
50
|
+
let media = JSON.stringify(random[0])
|
|
51
|
+
selectorElement.setAttribute('selected', media);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
selectorElement.addEventListener('change', ({detail}) => {
|
|
58
|
+
console.error(detail);
|
|
59
|
+
|
|
60
|
+
const peerid = Math.random().toString();
|
|
61
|
+
const json = JSON.parse(detail.url);
|
|
62
|
+
var videourl = json.video;
|
|
63
|
+
var createOfferUrl = srvurl + "/api/createOffer?peerid="+ peerid+"&url="+encodeURIComponent(videourl);
|
|
64
|
+
|
|
65
|
+
fetch(createOfferUrl)
|
|
66
|
+
.then( (response) => (response.json()) )
|
|
67
|
+
.then( (response) => onCreateOffer(response, peerid) )
|
|
68
|
+
.catch( (error) => console.log("createOffer " + error ))
|
|
69
|
+
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
});
|
|
73
|
+
</script>
|
|
74
|
+
</body>
|
|
75
|
+
</html>
|
|
76
|
+
|
|
File without changes
|
package/html/xmppvideoroom.html
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
<script src="libs/jquery-3.5.1.min.js"></script>
|
|
8
8
|
<script src="libs/EventEmitter.min.js" ></script>
|
|
9
9
|
<script src="xmppvideoroom.js" ></script>
|
|
10
|
-
<script src="
|
|
11
|
-
<script src="
|
|
10
|
+
<script src="xmppconfig.js" ></script>
|
|
11
|
+
<script src="webrtcconfig.js" ></script>
|
|
12
12
|
<link rel="icon" type="image/ico" href="jitsi.ico" />
|
|
13
13
|
<link rel="stylesheet" type="text/css" href="styles.css">
|
|
14
14
|
</head>
|
package/libv4l2cpp/README.md
CHANGED
|
@@ -12,13 +12,13 @@ V4L2 Capture
|
|
|
12
12
|
-------------
|
|
13
13
|
- create a V4L2 Capture interface using MMAP interface:
|
|
14
14
|
|
|
15
|
-
V4L2DeviceParameters param("/dev/video0", V4L2_PIX_FMT_*, width, height, fps, verbose);
|
|
16
|
-
V4l2Capture* videoCapture = V4l2Capture::create(param
|
|
15
|
+
V4L2DeviceParameters param("/dev/video0", V4L2_PIX_FMT_*, width, height, fps, IOTYPE_MMAP, verbose);
|
|
16
|
+
V4l2Capture* videoCapture = V4l2Capture::create(param);
|
|
17
17
|
|
|
18
18
|
- data are available :
|
|
19
19
|
|
|
20
20
|
timeval timeout;
|
|
21
|
-
bool isReadable =
|
|
21
|
+
bool isReadable = videoCapture->isReadable(&timeout);
|
|
22
22
|
|
|
23
23
|
- read data :
|
|
24
24
|
|
|
@@ -30,13 +30,13 @@ V4L2 Output
|
|
|
30
30
|
|
|
31
31
|
- To create a V4L2 Output interface using MMAP interface:
|
|
32
32
|
|
|
33
|
-
V4L2DeviceParameters param("/dev/video0", V4L2_PIX_FMT_*, width, height, fps, verbose);
|
|
34
|
-
V4l2Output* videoOutput = V4l2Output::create(param
|
|
33
|
+
V4L2DeviceParameters param("/dev/video0", V4L2_PIX_FMT_*, width, height, fps, IOTYPE_MMAP, verbose);
|
|
34
|
+
V4l2Output* videoOutput = V4l2Output::create(param);
|
|
35
35
|
|
|
36
36
|
- data could be written :
|
|
37
37
|
|
|
38
38
|
timeval timeout;
|
|
39
|
-
bool isWritable =
|
|
39
|
+
bool isWritable = videoOutput->isWritable(&timeout);
|
|
40
40
|
|
|
41
41
|
- write data :
|
|
42
42
|
|
|
@@ -17,24 +17,23 @@
|
|
|
17
17
|
|
|
18
18
|
class V4l2Access
|
|
19
19
|
{
|
|
20
|
-
public:
|
|
21
|
-
enum IoType
|
|
22
|
-
{
|
|
23
|
-
IOTYPE_READWRITE,
|
|
24
|
-
IOTYPE_MMAP
|
|
25
|
-
};
|
|
26
|
-
|
|
20
|
+
public:
|
|
27
21
|
V4l2Access(V4l2Device* device);
|
|
28
22
|
virtual ~V4l2Access();
|
|
29
23
|
|
|
30
|
-
int getFd()
|
|
24
|
+
int getFd() { return m_device->getFd(); }
|
|
31
25
|
unsigned int getBufferSize() { return m_device->getBufferSize(); }
|
|
32
26
|
unsigned int getFormat() { return m_device->getFormat(); }
|
|
33
27
|
unsigned int getWidth() { return m_device->getWidth(); }
|
|
34
28
|
unsigned int getHeight() { return m_device->getHeight(); }
|
|
35
29
|
|
|
36
30
|
void queryFormat() { m_device->queryFormat(); }
|
|
37
|
-
int setFormat(unsigned int format, unsigned int width, unsigned int height) {
|
|
31
|
+
int setFormat(unsigned int format, unsigned int width, unsigned int height) {
|
|
32
|
+
return m_device->setFormat(format, width, height);
|
|
33
|
+
}
|
|
34
|
+
int setFps(int fps) {
|
|
35
|
+
return m_device->setFps(fps);
|
|
36
|
+
}
|
|
38
37
|
|
|
39
38
|
int isReady() { return m_device->isReady(); }
|
|
40
39
|
int start() { return m_device->start(); }
|
|
@@ -24,11 +24,11 @@ class V4l2Capture : public V4l2Access
|
|
|
24
24
|
V4l2Capture(V4l2Device* device);
|
|
25
25
|
|
|
26
26
|
public:
|
|
27
|
-
static V4l2Capture* create(const V4L2DeviceParameters & param
|
|
27
|
+
static V4l2Capture* create(const V4L2DeviceParameters & param);
|
|
28
28
|
virtual ~V4l2Capture();
|
|
29
29
|
|
|
30
30
|
size_t read(char* buffer, size_t bufferSize);
|
|
31
|
-
|
|
31
|
+
bool isReadable(timeval* tv);
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
|