@flashphoner/websdk 2.0.241 → 2.0.243

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.
@@ -1,48 +1,67 @@
1
- var Browser = Flashphoner.Browser;
2
- var remoteVideo = null;
1
+ const Browser = Flashphoner.Browser;
2
+ const STATS_INTERVAL = 1000;
3
+ let remoteVideo = null;
4
+ let playbackStats = null;
3
5
 
4
- function loadPlayerPage() {
5
- $("#playerPage").load("../hls-player/player-page.html", initPage );
6
+ const loadPlayerPage = function() {
7
+ loadPage("../hls-player/player-page.html", "playerPage", initPage );
6
8
  }
7
9
 
8
- function initPage() {
9
- $("#header").text("HLS Native Player Minimal");
10
- $("#urlServer").val(getHLSUrl());
11
- $("#applyBtn").prop('disabled', false).text("Play").off('click').click(playBtnClick);
10
+ const loadPage = function(page, containerId, onLoad) {
11
+ fetch(page).then(function (response) {
12
+ if (response.ok) {
13
+ return response.text();
14
+ }
15
+ throw response;
16
+ }).then(function (text) {
17
+ let container = document.getElementById(containerId);
18
+ container.innerHTML = text;
19
+ onLoad();
20
+ });
21
+ }
22
+
23
+ const initPage = function() {
24
+ setText("header", "HLS Native Player Minimal");
25
+ setValue("urlServer", getHLSUrl());
26
+ setText("applyBtn", "Play");
27
+ setHandler("applyBtn", "click", playBtnClick);
12
28
  remoteVideo = document.getElementById('remoteVideo');
13
29
  remoteVideo.style ="background-color: lightgrey;";
14
30
  if (Browser.isSafariWebRTC() && Browser.isiOS()) {
15
31
  // iOS hack when using standard controls to leave fullscreen mode
16
32
  setWebkitFullscreenHandlers(remoteVideo);
17
33
  }
34
+ if (remoteVideo.canPlayType('application/vnd.apple.mpegurl') && Browser.isSafariWebRTC()) {
35
+ enableItem("applyBtn");
36
+ playbackStats = PlaybackStats(STATS_INTERVAL);
37
+ } else {
38
+ setText("notifyFlash", "Your browser doesn't support native HLS playback");
39
+ disableItem("applyBtn");
40
+ toggleInputs(false);
41
+ }
18
42
  }
19
43
 
20
- function playBtnClick() {
44
+ const playBtnClick = function() {
21
45
  if (validateForm()) {
22
- var streamName = $('#playStream').val();
46
+ let streamName = getValue("playStream");
23
47
  streamName = encodeURIComponent(streamName);
24
- var videoSrc = $("#urlServer").val() + '/' + streamName + '/' + streamName + '.m3u8';
25
- var key = $('#key').val();
26
- var token = $("#token").val();
48
+ let videoSrc = getValue("urlServer") + '/' + streamName + '/' + streamName + '.m3u8';
49
+ let key = getValue('key');
50
+ let token = getValue("token");
27
51
  if (key.length > 0 && token.length > 0) {
28
52
  videoSrc += "?" + key + "=" + token;
29
53
  }
30
- if (remoteVideo.canPlayType('application/vnd.apple.mpegurl')) {
31
- remoteVideo.src = videoSrc;
32
- remoteVideo.addEventListener('loadedmetadata', function() {
33
- console.log("Play native HLS");
34
- remoteVideo.play();
35
- onStarted();
36
- });
37
- }
38
- else {
39
- $("#notifyFlash").text("Your browser doesn't support native HLS playback");
40
- }
54
+ remoteVideo.src = videoSrc;
55
+ remoteVideo.addEventListener('loadedmetadata', function() {
56
+ console.log("Play native HLS");
57
+ remoteVideo.play();
58
+ onStarted();
59
+ });
41
60
  }
42
61
  }
43
62
 
44
63
 
45
- function stopBtnClick() {
64
+ const stopBtnClick = function() {
46
65
  if (remoteVideo != null) {
47
66
  console.log("Stop HTML5 player");
48
67
  remoteVideo.pause();
@@ -54,51 +73,124 @@ function stopBtnClick() {
54
73
  }
55
74
 
56
75
 
57
- function onStarted() {
58
- $("#urlServer").prop('disabled', true);
59
- $("#playStream").prop('disabled', true);
60
- $("#key").prop('disabled', true);
61
- $("#token").prop('disabled', true);
62
- $("#player").prop('disabled', true);
63
- $("#applyBtn").prop('disabled', false).text("Stop").off('click').click(stopBtnClick);
76
+ const onStarted = function() {
77
+ toggleInputs(false);
78
+ enableItem("applyBtn");
79
+ setText("applyBtn", "Stop");
80
+ setHandler("applyBtn", "click", stopBtnClick, playBtnClick);
81
+ playbackStats.start();
64
82
  }
65
83
 
66
84
 
67
- function onStopped() {
68
- $("#urlServer").prop('disabled', false);
69
- $("#playStream").prop('disabled', false);
70
- $("#key").prop('disabled', false);
71
- $("#token").prop('disabled', false);
72
- $("#player").prop('disabled', false);
73
- $("#applyBtn").prop('disabled', false).text("Play").off('click').click(playBtnClick);
85
+ const onStopped = function() {
86
+ toggleInputs(true);
87
+ enableItem("applyBtn");
88
+ setText("applyBtn", "Play");
89
+ setHandler("applyBtn", "click", playBtnClick, stopBtnClick);
90
+ playbackStats.stop();
74
91
  }
75
92
 
76
93
 
77
- function validateForm() {
78
- var valid = true;
79
- if (!$("#urlServer").val().length) {
80
- highlightInput($("#urlServer"));
81
- valid = false;
82
- } else {
83
- removeHighlight($("#urlServer"));
94
+ const validateForm = function() {
95
+ let valid = validateInput("urlServer");
96
+ if (valid) {
97
+ valid = validateInput("playStream");
84
98
  }
85
- if (!$("#playStream").val().length) {
86
- highlightInput($("#playStream"));
99
+ return valid;
100
+ }
101
+
102
+ const validateInput = function(id) {
103
+ let value = getValue(id);
104
+ let valid = true;
105
+ if (!value || !value.length) {
106
+ highlightInput(id);
87
107
  valid = false;
88
108
  } else {
89
- removeHighlight($("#playStream"));
109
+ removeHighlight(id);
90
110
  }
91
-
92
111
  return valid;
93
-
94
112
  }
95
113
 
96
-
97
- function highlightInput(input) {
98
- input.closest('.form-group').addClass("has-error");
114
+ const highlightInput = function(input) {
115
+ let item = document.getElementById(input);
116
+ if (item) {
117
+ let parent = closest(input,'.form-group');
118
+ if (parent) {
119
+ parent.classList.add("has-error");
120
+ }
121
+ }
99
122
  }
100
123
 
101
124
 
102
- function removeHighlight(input) {
103
- input.closest('.form-group').removeClass("has-error");
125
+ const removeHighlight = function(input) {
126
+ let item = document.getElementById(input);
127
+ if (item) {
128
+ let parent = closest(input,'.form-group');
129
+ if (parent) {
130
+ parent.classList.remove("has-error");
131
+ }
132
+ }
133
+ }
134
+
135
+ const toggleInputs = function(enable) {
136
+ if (enable) {
137
+ enableItem("urlServer");
138
+ enableItem("playStream");
139
+ enableItem("key");
140
+ enableItem("token");
141
+ enableItem("player");
142
+ } else {
143
+ disableItem("urlServer");
144
+ disableItem("playStream");
145
+ disableItem("key");
146
+ disableItem("token");
147
+ disableItem("player");
148
+ }
104
149
  }
150
+
151
+ const PlaybackStats = function(interval) {
152
+ const playbackStats = {
153
+ interval: interval || STATS_INTERVAL,
154
+ timer: null,
155
+ stats: null,
156
+ start: function() {
157
+ let video = remoteVideo;
158
+
159
+ playbackStats.stop();
160
+ stats = HTML5Stats(video);
161
+ playbackStats.timer = setInterval(playbackStats.displayStats, playbackStats.interval);
162
+ setText("videoWidth", "N/A");
163
+ setText("videoHeight", "N/A");
164
+ setText("videoRate", "N/A");
165
+ setText("videoFps", "N/A");
166
+ showItem("stats");
167
+ },
168
+ stop: function() {
169
+ if (playbackStats.timer) {
170
+ clearInterval(playbackStats.timer);
171
+ playbackStats.timer = null;
172
+ }
173
+ playbackStats.stats = null;
174
+ hideItem("stats");
175
+ },
176
+ displayStats: function() {
177
+ if (stats.collect()) {
178
+ let width = stats.getWidth();
179
+ let height = stats.getHeight();
180
+ let bitrate = stats.getBitrate();
181
+ let fps = stats.getFps();
182
+
183
+ setText("videoWidth", width);
184
+ setText("videoHeight", height);
185
+
186
+ if (bitrate !== undefined) {
187
+ setText("videoRate", Math.round(bitrate));
188
+ }
189
+ if (fps !== undefined) {
190
+ setText("videoFps", fps.toFixed(1));
191
+ }
192
+ }
193
+ }
194
+ };
195
+ return playbackStats;
196
+ }
@@ -5,14 +5,11 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
6
  <link rel="stylesheet" href="../../dependencies/bootstrap/css/bootstrap.css">
7
7
  <link rel="stylesheet" href="hls-player.css">
8
- <!-- <link rel="stylesheet" href="video-js.css"> -->
9
8
  <title>HLS VideoJS Player Minimal</title>
10
9
  <script type="text/javascript" src="../../../../flashphoner.js"></script>
11
- <!-- <script type="text/javascript" src="../../dependencies/jquery/jquery-1.12.0.js"></script>
12
- <script type="text/javascript" src="../../dependencies/jquery/jquery-ui.js"></script> -->
13
10
  <script type="text/javascript" src="../../dependencies/js/utils.js"></script>
11
+ <script type="text/javascript" src="../../dependencies/js/stats.js"></script>
14
12
  <script type="text/javascript" src="hls-player.js"></script>
15
- <!-- <script type="text/javascript" src="video.js"></script> -->
16
13
  </head>
17
14
  <body onload="loadPlayerPage()">
18
15
  <div class="row form-group" id="videojsInputForm">
@@ -6,9 +6,11 @@ const VIDEOJS_VERSION_TYPE = {
6
6
  const LIVE_THRESHOLD = 5;
7
7
  const LIVE_TOLERANCE = 5;
8
8
  const LIVE_UI_INTERVAL = 1000;
9
+ const STATS_INTERVAL = 1000;
9
10
  let player = null;
10
11
  let liveUITimer = null;
11
12
  let videojsVersion = getUrlParam("version");
13
+ let playbackStats = null;
12
14
 
13
15
  const loadPlayerPage = function() {
14
16
  if (videojsVersion) {
@@ -127,6 +129,7 @@ const initPage = function() {
127
129
  let remoteVideo = document.getElementById('remoteVideo');
128
130
  remoteVideo.className = "video-js vjs-default-skin";
129
131
  player = initVideoJsPlayer(remoteVideo);
132
+ playbackStats = PlaybackStats(STATS_INTERVAL);
130
133
  }
131
134
 
132
135
  const playBtnClick = function() {
@@ -234,6 +237,7 @@ const onStarted = function() {
234
237
  toggleBackButtons(true);
235
238
  setText("applyBtn", "Stop");
236
239
  setHandler("applyBtn", "click", stopBtnClick, playBtnClick);
240
+ playbackStats.start();
237
241
  }
238
242
 
239
243
 
@@ -243,6 +247,7 @@ const onStopped = function() {
243
247
  hideItem("backward");
244
248
  setText("applyBtn", "Play");
245
249
  setHandler("applyBtn", "click", playBtnClick, stopBtnClick);
250
+ playbackStats.stop();
246
251
  if(!document.getElementById('remoteVideo')) {
247
252
  createRemoteVideo(document.getElementById('videoContainer'));
248
253
  }
@@ -250,10 +255,8 @@ const onStopped = function() {
250
255
 
251
256
 
252
257
  const createRemoteVideo = function(parent) {
253
- remoteVideo = document.createElement("video");
258
+ let remoteVideo = document.createElement("video");
254
259
  remoteVideo.id = "remoteVideo";
255
- remoteVideo.width=852;
256
- remoteVideo.height=480;
257
260
  remoteVideo.controls="controls";
258
261
  remoteVideo.autoplay="autoplay";
259
262
  remoteVideo.type="application/vnd.apple.mpegurl";
@@ -314,7 +317,8 @@ const initVideoJsPlayer = function(video) {
314
317
  liveTracker: {
315
318
  trackingThreshold: LIVE_THRESHOLD,
316
319
  liveTolerance: LIVE_TOLERANCE
317
- }
320
+ },
321
+ fill: true
318
322
  });
319
323
  console.log("Using VideoJs " + videojs.VERSION);
320
324
  if (Browser.isSafariWebRTC() && Browser.isiOS()) {
@@ -361,4 +365,51 @@ const toggleInputs = function(enable) {
361
365
  disableItem("token");
362
366
  disableItem("player");
363
367
  }
368
+ }
369
+
370
+ const PlaybackStats = function(interval) {
371
+ const playbackStats = {
372
+ interval: interval || STATS_INTERVAL,
373
+ timer: null,
374
+ stats: null,
375
+ start: function() {
376
+ let video = getActualVideoTag();
377
+
378
+ playbackStats.stop();
379
+ stats = HTML5Stats(video);
380
+ playbackStats.timer = setInterval(playbackStats.displayStats, playbackStats.interval);
381
+ setText("videoWidth", "N/A");
382
+ setText("videoHeight", "N/A");
383
+ setText("videoRate", "N/A");
384
+ setText("videoFps", "N/A");
385
+ showItem("stats");
386
+ },
387
+ stop: function() {
388
+ if (playbackStats.timer) {
389
+ clearInterval(playbackStats.timer);
390
+ playbackStats.timer = null;
391
+ }
392
+ playbackStats.stats = null;
393
+ hideItem("stats");
394
+ },
395
+ displayStats: function() {
396
+ if (stats.collect()) {
397
+ let width = stats.getWidth();
398
+ let height = stats.getHeight();
399
+ let bitrate = stats.getBitrate();
400
+ let fps = stats.getFps();
401
+
402
+ setText("videoWidth", width);
403
+ setText("videoHeight", height);
404
+
405
+ if (bitrate !== undefined) {
406
+ setText("videoRate", Math.round(bitrate));
407
+ }
408
+ if (fps !== undefined) {
409
+ setText("videoFps", fps.toFixed(1));
410
+ }
411
+ }
412
+ }
413
+ };
414
+ return playbackStats;
364
415
  }
@@ -1,5 +1,5 @@
1
1
  <div class="row">
2
- <div class="col-sm-12 text-center" style="max-width: 525px">
2
+ <div class="col-sm-12 text-center" style="max-width: 500px">
3
3
 
4
4
  <h2 id="header"></h2>
5
5
 
@@ -69,12 +69,42 @@
69
69
  </div>
70
70
  </div>
71
71
  <div class="row">
72
- <div id="videoContainer" class="col-sm-12 text-center" style="margin-top: 20px; max-width: 852px">
73
- <video id="remoteVideo" width="852" height="480"
72
+ <div id="videoContainer" class="col-sm-12 text-center" style="margin-top: 20px; max-width: 852px; width: available; max-height: 480px; height: 56.25vw">
73
+ <video id="remoteVideo"
74
+ width="100%"
75
+ height="100%"
74
76
  controls="controls"
75
77
  autoplay="autoplay"
76
78
  playsinline="playsinline"
77
79
  webkit-playsinline="webkit-playsinline"
78
80
  type="application/vnd.apple.mpegurl"></video>
79
81
  </div>
82
+ </div>
83
+ <div id="stats" class="row" style="display: none;">
84
+ <div class="col-sm-12">
85
+ <div class="row" style="margin-top: 20px">
86
+ <div class="col-sm-2">
87
+ <label class="form-check-label" for="videoWidth">Video width</label>
88
+ </div>
89
+ <div class="col-sm-2" id="videoWidth"></div>
90
+ </div>
91
+ <div class="row" style="margin-top: 10px">
92
+ <div class="col-sm-2">
93
+ <label class="form-check-label" for="videoHeight">Video height</label>
94
+ </div>
95
+ <div class="col-sm-2" id="videoHeight"></div>
96
+ </div>
97
+ <div class="row" style="margin-top: 10px">
98
+ <div class="col-sm-2">
99
+ <label class="form-check-label" for="videoRate">Bitrate, bps</label>
100
+ </div>
101
+ <div class="col-sm-2" id="videoRate"></div>
102
+ </div>
103
+ <div class="row" style="margin-top: 10px">
104
+ <div class="col-sm-2">
105
+ <label class="form-check-label" for="videoFps">Framerate</label>
106
+ </div>
107
+ <div class="col-sm-2" id="videoFps"></div>
108
+ </div>
109
+ </div>
80
110
  </div>
@@ -9167,7 +9167,7 @@ var createSession = function createSession(options) {
9167
9167
  * @param {string=} options.stripCodecs Comma separated strings of codecs which should be stripped from WebRTC SDP (ex. "SILK,G722")
9168
9168
  * @param {Array<string>=} options.sipSDP Array of custom SDP params (ex. bandwidth (b=))
9169
9169
  * @param {Array<string>=} options.sipHeaders Array of custom SIP headers
9170
- * @param {string=} options.videoContentHint Video content hint for browser ('detail' by default to maintain resolution), {@link Flashphoner.constants.CONTENT_HINT_TYPE}
9170
+ * @param {string=} options.videoContentHint Video content hint for browser ('motion' by default to maintain bitrate and fps), {@link Flashphoner.constants.CONTENT_HINT_TYPE}
9171
9171
  * @param {Boolean=} options.useControls Use a standard HTML5 video controls (play, pause, fullscreen). May be a workaround for fullscreen mode to work in Safari 16
9172
9172
  * @param {Object=} options.logger Call logger options
9173
9173
  * @param {sdpHook} sdpHook The callback that handles sdp from the server
@@ -9964,7 +9964,7 @@ var createSession = function createSession(options) {
9964
9964
  * @param {Boolean=} options.cvoExtension Enable rtp video orientation extension
9965
9965
  * @param {Integer=} options.playoutDelay Time delay between network reception of media and playout
9966
9966
  * @param {string=} options.useCanvasMediaStream EXPERIMENTAL: when publish bind browser's media stream to the canvas. It can be useful for image filtering
9967
- * @param {string=} options.videoContentHint Video content hint for browser ('detail' by default to maintain resolution), {@link Flashphoner.constants.CONTENT_HINT_TYPE}
9967
+ * @param {string=} options.videoContentHint Video content hint for browser ('motion' by default to maintain bitrate and fps), {@link Flashphoner.constants.CONTENT_HINT_TYPE}
9968
9968
  * @param {Boolean=} options.unmutePlayOnStart Unmute playback on start. May be used after user gesture only, so set 'unmutePlayOnStart: false' for autoplay
9969
9969
  * @param {Boolean=} options.useControls Use a standard HTML5 video controls (play, pause, fullscreen). May be a workaround for fullscreen mode to work in Safari 16
9970
9970
  * @param {Object=} options.logger Stream logger options
@@ -11784,7 +11784,8 @@ var createConnection = function createConnection(options) {
11784
11784
  var screenShare = false;
11785
11785
  var playoutDelay = options.playoutDelay;
11786
11786
  // Set video track contentHint to `detail` by default to workaround Chromium 91 bug #WCS-3257
11787
- var videoContentHint = options.videoContentHint ? options.videoContentHint : 'detail';
11787
+ // Set video track contentHint to `motion` by default to keep bitrate and fps for better camera stream quality #WCS-4109
11788
+ var videoContentHint = options.videoContentHint ? options.videoContentHint : 'motion';
11788
11789
  // Pass the option to unmute automatically (true by default) #WCS-2425
11789
11790
  var unmutePlayOnStart = options.unmutePlayOnStart !== undefined ? options.unmutePlayOnStart : true;
11790
11791
  // Use a standard HTML5 video controls if needed (to enable fullscreen in Safari 16 for example) #WCS-3606