webrtc-streamer 0.8.9 → 0.8.10

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.
@@ -9,7 +9,7 @@
9
9
  "type": "cppdbg",
10
10
  "request": "launch",
11
11
  "program": "${workspaceFolder}/webrtc-streamer",
12
- "args": ["-C", "config.json", "-a"],
12
+ "args": ["-C", "config.json", "-o"],
13
13
  "stopAtEntry": false,
14
14
  "cwd": "${workspaceFolder}",
15
15
  "environment": [],
package/README.md CHANGED
@@ -17,6 +17,7 @@
17
17
  [![Demo](https://img.shields.io/badge/azure-livedemo-green)](https://webrtcstreamer.agreeabletree-365b9a90.canadacentral.azurecontainerapps.io/)
18
18
  [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/mpromonet/webrtc-streamer)
19
19
 
20
+
20
21
  Experimentation to stream WebRTC media sources like capture devices, screen capture, mkv files and RMTP/RTSP sources using simple signaling mechanism (see [api](docs/api.md)). It is also compatible with [WHEP](https://datatracker.ietf.org/doc/html/draft-ietf-wish-whep-01) interface.
21
22
 
22
23
  ## Artefacts
@@ -136,7 +137,7 @@ The container entry point is the webrtc-streamer application, then you can:
136
137
  - run the container giving config.json file:
137
138
 
138
139
  ```sh
139
- docker run -p 8000:8000 -v $PWD/config.json:/app/config.json mpromonet/webrtc-streamer
140
+ docker run -p 8000:8000 -v $PWD/config.json:/usr/local/share/webrtc-streamer/config.json mpromonet/webrtc-streamer
140
141
  ```
141
142
 
142
143
  ## Using embedded STUN/TURN server behind a NAT
@@ -395,3 +396,8 @@ following architectures:
395
396
  - arm64 crosscompiled
396
397
  - Windows x64 build with clang
397
398
  - MacOS
399
+
400
+
401
+ ## Star History
402
+
403
+ [![Star History Chart](https://api.star-history.com/svg?repos=mpromonet/webrtc-streamer&type=Date)](https://star-history.com/#mpromonet/webrtc-streamer&Date)
package/h265.mkv ADDED
Binary file
package/html/index.html CHANGED
@@ -10,21 +10,23 @@
10
10
  // ------------------------------------------
11
11
  // WebRTC connections
12
12
  // ------------------------------------------
13
- var webRtcServerList = {};
13
+ let webRtcServerList = {};
14
14
 
15
15
  // ------------------------------------------
16
16
  // decode URL arguments
17
17
  // ------------------------------------------
18
- var argurl = { video:location.search.slice(1) };
19
- var argoptions = null;
20
- var layout = null;
18
+ let argurl = { video:location.search.slice(1) };
19
+ let argoptions = null;
20
+ let prefmime = null;
21
+ let layout = null;
21
22
  if (typeof URLSearchParams != 'undefined') {
22
- var params = new URLSearchParams(location.search);
23
+ let params = new URLSearchParams(location.search);
23
24
  argurl = { video:params.get("video"), audio:params.get("audio") };
24
25
  argoptions = params.get("options");
25
26
  if (!argoptions) {
26
27
  argoptions = webrtcConfig.options;
27
28
  }
29
+ prefmime = params.get("codec");
28
30
  layout = params.get("layout");
29
31
  } else {
30
32
  console.log("URLSearchParams not supported then no argument could be used");
@@ -195,7 +197,7 @@
195
197
  options += webrtcConfig.layoutextraoptions;
196
198
  }
197
199
 
198
- webRtcServer.connect(url.video, url.audio, options);
200
+ webRtcServer.connect(url.video, url.audio, options, null, prefmime);
199
201
 
200
202
  // highlight the navigation
201
203
  var navElt = document.getElementById ("nav_" + videoTag);
@@ -80,6 +80,65 @@ WebRtcStreamer.prototype.disconnect = function() {
80
80
  }
81
81
  }
82
82
 
83
+ WebRtcStreamer.prototype.filterPreferredCodec = function(sdp, prefmime) {
84
+ const lines = sdp.split('\n');
85
+ const [prefkind, prefcodec] = prefmime.toLowerCase().split('/');
86
+ let currentMediaType = null;
87
+ let sdpSections = [];
88
+ let currentSection = [];
89
+
90
+ // Group lines into sections
91
+ lines.forEach(line => {
92
+ if (line.startsWith('m=')) {
93
+ if (currentSection.length) {
94
+ sdpSections.push(currentSection);
95
+ }
96
+ currentSection = [line];
97
+ } else {
98
+ currentSection.push(line);
99
+ }
100
+ });
101
+ sdpSections.push(currentSection);
102
+
103
+ // Process each section
104
+ const processedSections = sdpSections.map(section => {
105
+ const firstLine = section[0];
106
+ if (!firstLine.startsWith('m=' + prefkind)) {
107
+ return section.join('\n');
108
+ }
109
+
110
+ // Get payload types for preferred codec
111
+ const rtpLines = section.filter(line => line.startsWith('a=rtpmap:'));
112
+ const preferredPayloads = rtpLines
113
+ .filter(line => line.toLowerCase().includes(prefcodec))
114
+ .map(line => line.split(':')[1].split(' ')[0]);
115
+
116
+ if (preferredPayloads.length === 0) {
117
+ return section.join('\n');
118
+ }
119
+
120
+ // Modify m= line to only include preferred payloads
121
+ const mLine = firstLine.split(' ');
122
+ const newMLine = [...mLine.slice(0,3), ...preferredPayloads].join(' ');
123
+
124
+ // Filter related attributes
125
+ const filteredLines = section.filter(line => {
126
+ if (line === firstLine) return false;
127
+ if (line.startsWith('a=rtpmap:')) {
128
+ return preferredPayloads.some(payload => line.startsWith(`a=rtpmap:${payload}`));
129
+ }
130
+ if (line.startsWith('a=fmtp:') || line.startsWith('a=rtcp-fb:')) {
131
+ return preferredPayloads.some(payload => line.startsWith(`a=${line.split(':')[0].split('a=')[1]}:${payload}`));
132
+ }
133
+ return true;
134
+ });
135
+
136
+ return [newMLine, ...filteredLines].join('\n');
137
+ });
138
+
139
+ return processedSections.join('\n');
140
+ }
141
+
83
142
  /*
84
143
  * GetIceServers callback
85
144
  */
@@ -89,7 +148,7 @@ WebRtcStreamer.prototype.onReceiveGetIceServers = function(iceServers, videourl,
89
148
  try {
90
149
  this.createPeerConnection();
91
150
 
92
- var callurl = this.srvurl + "/api/call?peerid=" + this.pc.peerid + "&url=" + encodeURIComponent(videourl);
151
+ let callurl = this.srvurl + "/api/call?peerid=" + this.pc.peerid + "&url=" + encodeURIComponent(videourl);
93
152
  if (audiourl) {
94
153
  callurl += "&audiourl="+encodeURIComponent(audiourl);
95
154
  }
@@ -102,29 +161,27 @@ WebRtcStreamer.prototype.onReceiveGetIceServers = function(iceServers, videourl,
102
161
  }
103
162
 
104
163
  // clear early candidates
105
- this.earlyCandidates.length = 0;
106
-
164
+ this.earlyCandidates.length = 0;
165
+
107
166
  // create Offer
108
167
  this.pc.createOffer(this.mediaConstraints).then((sessionDescription) => {
109
168
  console.log("Create offer:" + JSON.stringify(sessionDescription));
110
169
 
111
170
  console.log(`video codecs:${Array.from(new Set(RTCRtpReceiver.getCapabilities("video")?.codecs?.map(codec => codec.mimeType)))}`)
112
171
  console.log(`audio codecs:${Array.from(new Set(RTCRtpReceiver.getCapabilities("audio")?.codecs?.map(codec => codec.mimeType)))}`)
113
-
172
+
114
173
  if (prefmime != undefined) {
115
174
  //set prefered codec
116
- const [prefkind] = prefmime.split('/');
117
- const codecs = RTCRtpReceiver.getCapabilities(prefkind).codecs;
118
- const preferedCodecs = codecs.filter(codec => codec.mimeType === prefmime);
119
-
120
- console.log(`preferedCodecs:${JSON.stringify(preferedCodecs)}`);
121
- this.pc.getTransceivers().filter(transceiver => transceiver.receiver.track.kind === prefkind).forEach(tcvr => {
122
- if(tcvr.setCodecPreferences != undefined) {
123
- tcvr.setCodecPreferences(preferedCodecs);
124
- }
125
- });
175
+ let [prefkind] = prefmime.split('/');
176
+ if (prefkind != "video" && prefkind != "audio") {
177
+ prefkind = "video";
178
+ prefmime = prefkind + "/" + prefmime;
179
+ }
180
+ console.log("sdp:" + sessionDescription.sdp);
181
+ sessionDescription.sdp = this.filterPreferredCodec(sessionDescription.sdp, prefmime);
182
+ console.log("sdp:" + sessionDescription.sdp);
126
183
  }
127
-
184
+
128
185
 
129
186
  this.pc.setLocalDescription(sessionDescription)
130
187
  .then(() => {
@@ -164,7 +221,7 @@ WebRtcStreamer.prototype.getIceCandidate = function() {
164
221
  WebRtcStreamer.prototype.createPeerConnection = function() {
165
222
  console.log("createPeerConnection config: " + JSON.stringify(this.pcConfig));
166
223
  this.pc = new RTCPeerConnection(this.pcConfig);
167
- var pc = this.pc;
224
+ let pc = this.pc;
168
225
  pc.peerid = Math.random();
169
226
 
170
227
  pc.onicecandidate = (evt) => this.onIceCandidate(evt);
@@ -198,7 +255,7 @@ WebRtcStreamer.prototype.createPeerConnection = function() {
198
255
  }
199
256
 
200
257
  try {
201
- var dataChannel = pc.createDataChannel("ClientDataChannel");
258
+ let dataChannel = pc.createDataChannel("ClientDataChannel");
202
259
  dataChannel.onopen = function() {
203
260
  console.log("local datachannel open");
204
261
  this.send("local channel openned");
@@ -247,7 +304,7 @@ WebRtcStreamer.prototype.onAddStream = function(event) {
247
304
  console.log("Remote track added:" + JSON.stringify(event));
248
305
 
249
306
  this.videoElement.srcObject = event.stream;
250
- var promise = this.videoElement.play();
307
+ let promise = this.videoElement.play();
251
308
  if (promise !== undefined) {
252
309
  promise.catch((error) => {
253
310
  console.warn("error:"+error);
@@ -262,11 +319,11 @@ WebRtcStreamer.prototype.onAddStream = function(event) {
262
319
  WebRtcStreamer.prototype.onReceiveCall = function(dataJson) {
263
320
 
264
321
  console.log("offer: " + JSON.stringify(dataJson));
265
- var descr = new RTCSessionDescription(dataJson);
322
+ let descr = new RTCSessionDescription(dataJson);
266
323
  this.pc.setRemoteDescription(descr).then(() => {
267
324
  console.log ("setRemoteDescription ok");
268
325
  while (this.earlyCandidates.length) {
269
- var candidate = this.earlyCandidates.shift();
326
+ let candidate = this.earlyCandidates.shift();
270
327
  this.addIceCandidate(this.pc.peerid, candidate);
271
328
  }
272
329
 
@@ -283,8 +340,8 @@ WebRtcStreamer.prototype.onReceiveCall = function(dataJson) {
283
340
  WebRtcStreamer.prototype.onReceiveCandidate = function(dataJson) {
284
341
  console.log("candidate: " + JSON.stringify(dataJson));
285
342
  if (dataJson) {
286
- for (var i=0; i<dataJson.length; i++) {
287
- var candidate = new RTCIceCandidate(dataJson[i]);
343
+ for (let i=0; i<dataJson.length; i++) {
344
+ let candidate = new RTCIceCandidate(dataJson[i]);
288
345
 
289
346
  console.log("Adding ICE candidate :" + JSON.stringify(candidate) );
290
347
  this.pc.addIceCandidate(candidate).then( () => { console.log ("addIceCandidate OK"); }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webrtc-streamer",
3
- "version": "0.8.9",
3
+ "version": "0.8.10",
4
4
  "description": "",
5
5
  "main": "joinjanusvideoroom.js",
6
6
  "dependencies": {