@flashphoner/websdk 2.0.246 → 2.0.248
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/docTemplate/README.md +1 -1
- package/examples/demo/streaming/media_devices_manager/manager.js +87 -53
- package/examples/demo/streaming/media_devices_manager/media_device_manager.html +14 -14
- package/examples/demo/streaming/screen-camera-mixer/screen-camera-mixer.html +4 -0
- package/examples/demo/streaming/screen-camera-mixer/screen-camera-mixer.js +70 -2
- package/flashphoner-no-flash.js +47 -19
- package/flashphoner-no-flash.min.js +2 -2
- package/flashphoner-no-webrtc.js +7 -7
- package/flashphoner-no-webrtc.min.js +2 -2
- package/flashphoner-no-wsplayer.js +47 -19
- package/flashphoner-no-wsplayer.min.js +2 -2
- package/flashphoner-room-api.js +45 -16
- package/flashphoner-room-api.min.js +3 -3
- package/flashphoner-temasys-flash-websocket-without-adapterjs.js +7 -7
- package/flashphoner-temasys-flash-websocket.js +7 -7
- package/flashphoner-temasys-flash-websocket.min.js +1 -1
- package/flashphoner-webrtc-only.js +45 -17
- package/flashphoner-webrtc-only.min.js +1 -1
- package/flashphoner.js +47 -19
- package/flashphoner.min.js +2 -2
- package/package.json +1 -1
- package/src/media-source-media-provider.js +3 -3
- package/src/webrtc-media-provider.js +42 -13
package/docTemplate/README.md
CHANGED
|
@@ -140,6 +140,12 @@ function init_page() {
|
|
|
140
140
|
$("#notifyFlash").text("Failed to get media devices");
|
|
141
141
|
});
|
|
142
142
|
|
|
143
|
+
if (Browser.isiOS() && Browser.isSafariWebRTC()) {
|
|
144
|
+
document.addEventListener('visibilitychange', () => {
|
|
145
|
+
onVisibilityChanged();
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
143
149
|
$("#urlServer").val(setURL());
|
|
144
150
|
var streamName = createUUID(4);
|
|
145
151
|
$("#publishStream").val(streamName);
|
|
@@ -217,6 +223,7 @@ function onPublishing(stream) {
|
|
|
217
223
|
}).prop('disabled', false);
|
|
218
224
|
$("#switchBtn").text("Switch").off('click').click(function () {
|
|
219
225
|
stream.switchCam().then(function(id) {
|
|
226
|
+
console.log("Switched by button to camera " + id);
|
|
220
227
|
$('#videoInput option:selected').prop('selected', false);
|
|
221
228
|
$("#videoInput option[value='"+ id +"']").prop('selected', true);
|
|
222
229
|
}).catch(function(e) {
|
|
@@ -272,6 +279,21 @@ function onDisconnected() {
|
|
|
272
279
|
onStopped();
|
|
273
280
|
}
|
|
274
281
|
|
|
282
|
+
function onVisibilityChanged() {
|
|
283
|
+
if (Browser.isiOS() && Browser.isSafariWebRTC() && document.hidden !== undefined) {
|
|
284
|
+
// iOS Safari may change camera when rising from the background, use chosen one explicitly
|
|
285
|
+
if (publishStream && !document.hidden) {
|
|
286
|
+
publishStream.switchCam($('#videoInput').val()).then(function(id) {
|
|
287
|
+
console.log("Switched explicitly to camera " + id);
|
|
288
|
+
$('#videoInput option:selected').prop('selected', false);
|
|
289
|
+
$("#videoInput option[value='"+ id +"']").prop('selected', true);
|
|
290
|
+
}).catch(function(e) {
|
|
291
|
+
console.log("Error " + e);
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
275
297
|
function connect() {
|
|
276
298
|
var url = $('#urlServer').val();
|
|
277
299
|
var tm = parseInt($('#timeout').val());
|
|
@@ -433,6 +455,7 @@ function publish() {
|
|
|
433
455
|
stripCodecs: strippedCodecs,
|
|
434
456
|
videoContentHint: contentHint
|
|
435
457
|
}).on(STREAM_STATUS.PUBLISHING, function (stream) {
|
|
458
|
+
publishConnectionQualityStat.connectionQualityUpdateTimestamp = new Date().valueOf();
|
|
436
459
|
$("#testBtn").prop('disabled', true);
|
|
437
460
|
var video = document.getElementById(stream.id());
|
|
438
461
|
//resize local if resolution is available
|
|
@@ -891,33 +914,39 @@ function readyControls() {
|
|
|
891
914
|
function loadPublishStats() {
|
|
892
915
|
if (publishStream) {
|
|
893
916
|
publishStream.getStats(function (stats) {
|
|
894
|
-
if (stats
|
|
895
|
-
if (stats.outboundStream
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
917
|
+
if (stats) {
|
|
918
|
+
if (stats.outboundStream) {
|
|
919
|
+
if (stats.outboundStream.video) {
|
|
920
|
+
showStat(stats.outboundStream.video, "outVideoStat");
|
|
921
|
+
let vBitrate = (stats.outboundStream.video.bytesSent - videoBytesSent) * 8;
|
|
922
|
+
if ($('#outVideoStatBitrate').length == 0) {
|
|
923
|
+
let html = "<div>Bitrate: " + "<span id='outVideoStatBitrate' style='font-weight: normal'>" + vBitrate + "</span>" + "</div>";
|
|
924
|
+
$("#outVideoStat").append(html);
|
|
925
|
+
} else {
|
|
926
|
+
$('#outVideoStatBitrate').text(vBitrate);
|
|
927
|
+
}
|
|
928
|
+
videoBytesSent = stats.outboundStream.video.bytesSent;
|
|
905
929
|
|
|
906
|
-
|
|
907
|
-
|
|
930
|
+
if(new Date().valueOf() - CONNECTION_QUALITY_UPDATE_TIMEOUT_MS > publishConnectionQualityStat.connectionQualityUpdateTimestamp) {
|
|
931
|
+
publishConnectionQualityStat.quality = CONNECTION_QUALITY.UNKNOWN;
|
|
932
|
+
}
|
|
908
933
|
}
|
|
909
|
-
}
|
|
910
934
|
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
935
|
+
if (stats.outboundStream.audio) {
|
|
936
|
+
showStat(stats.outboundStream.audio, "outAudioStat");
|
|
937
|
+
let aBitrate = (stats.outboundStream.audio.bytesSent - audioBytesSent) * 8;
|
|
938
|
+
if ($('#outAudioStatBitrate').length == 0) {
|
|
939
|
+
let html = "<div>Bitrate: " + "<span id='outAudioStatBitrate' style='font-weight: normal'>" + aBitrate + "</span>" + "</div>";
|
|
940
|
+
$("#outAudioStat").append(html);
|
|
941
|
+
} else {
|
|
942
|
+
$('#outAudioStatBitrate').text(aBitrate);
|
|
943
|
+
}
|
|
944
|
+
audioBytesSent = stats.outboundStream.audio.bytesSent;
|
|
919
945
|
}
|
|
920
|
-
|
|
946
|
+
|
|
947
|
+
}
|
|
948
|
+
if (stats.otherStats) {
|
|
949
|
+
showStat(stats.otherStats, "outConnectionStat");
|
|
921
950
|
}
|
|
922
951
|
}
|
|
923
952
|
if (publishConnectionQualityStat.quality !== undefined) {
|
|
@@ -931,47 +960,52 @@ function loadPublishStats() {
|
|
|
931
960
|
function loadPlayStats() {
|
|
932
961
|
if (previewStream) {
|
|
933
962
|
previewStream.getStats(function (stats) {
|
|
934
|
-
if (stats
|
|
935
|
-
if (stats.inboundStream
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
963
|
+
if (stats) {
|
|
964
|
+
if (stats.inboundStream) {
|
|
965
|
+
if (stats.inboundStream.video) {
|
|
966
|
+
showStat(stats.inboundStream.video, "inVideoStat");
|
|
967
|
+
let vBitrate = (stats.inboundStream.video.bytesReceived - videoBytesReceived) * 8;
|
|
968
|
+
if ($('#inVideoStatBitrate').length == 0) {
|
|
969
|
+
let html = "<div>Bitrate: " + "<span id='inVideoStatBitrate' style='font-weight: normal'>" + vBitrate + "</span>" + "</div>";
|
|
970
|
+
$("#inVideoStat").append(html);
|
|
971
|
+
} else {
|
|
972
|
+
$('#inVideoStatBitrate').text(vBitrate);
|
|
973
|
+
}
|
|
974
|
+
videoBytesReceived = stats.inboundStream.video.bytesReceived;
|
|
945
975
|
|
|
946
|
-
|
|
947
|
-
|
|
976
|
+
if (new Date().valueOf() - CONNECTION_QUALITY_UPDATE_TIMEOUT_MS > playConnectionQualityStat.connectionQualityUpdateTimestamp) {
|
|
977
|
+
playConnectionQualityStat.quality = CONNECTION_QUALITY.UNKNOWN;
|
|
978
|
+
}
|
|
948
979
|
}
|
|
949
|
-
}
|
|
950
980
|
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
981
|
+
if (stats.inboundStream.audio) {
|
|
982
|
+
if (stats.inboundStream.audio.audioLevel) {
|
|
983
|
+
// Round audio level to 6 decimal places
|
|
984
|
+
stats.inboundStream.audio.audioLevel = stats.inboundStream.audio.audioLevel.toFixed(6);
|
|
985
|
+
}
|
|
986
|
+
showStat(stats.inboundStream.audio, "inAudioStat");
|
|
987
|
+
let aBitrate = (stats.inboundStream.audio.bytesReceived - audioBytesReceived) * 8;
|
|
988
|
+
if ($('#inAudioStatBitrate').length == 0) {
|
|
989
|
+
let html = "<div style='font-weight: bold'>Bitrate: " + "<span id='inAudioStatBitrate' style='font-weight: normal'>" + aBitrate + "</span>" + "</div>";
|
|
990
|
+
$("#inAudioStat").append(html);
|
|
991
|
+
} else {
|
|
992
|
+
$('#inAudioStatBitrate').text(aBitrate);
|
|
993
|
+
}
|
|
994
|
+
audioBytesReceived = stats.inboundStream.audio.bytesReceived;
|
|
963
995
|
}
|
|
964
|
-
audioBytesReceived = stats.inboundStream.audio.bytesReceived;
|
|
965
996
|
}
|
|
966
|
-
if (
|
|
967
|
-
showStat(
|
|
997
|
+
if (stats.otherStats) {
|
|
998
|
+
showStat(stats.otherStats, "inConnectionStat");
|
|
968
999
|
}
|
|
969
1000
|
}
|
|
1001
|
+
if (playConnectionQualityStat.quality !== undefined) {
|
|
1002
|
+
showStat({"quality": playConnectionQualityStat.quality}, "inConnectionStat");
|
|
1003
|
+
}
|
|
970
1004
|
});
|
|
971
1005
|
}
|
|
972
1006
|
}
|
|
973
1007
|
|
|
974
|
-
// Helper
|
|
1008
|
+
// Helper function to display stats
|
|
975
1009
|
function showStat(stat, type) {
|
|
976
1010
|
Object.keys(stat).forEach(function(key) {
|
|
977
1011
|
if (typeof stat[key] !== 'object') {
|
|
@@ -29,12 +29,12 @@
|
|
|
29
29
|
</div>
|
|
30
30
|
<div class="row">
|
|
31
31
|
<h2 id="notifyFlash" class="text-danger"></h2>
|
|
32
|
-
<div class="col-sm-2"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
<div class="col-sm-2">
|
|
33
|
+
<label id="outVideoStat">Video stats</label>
|
|
34
|
+
<div></div>
|
|
35
|
+
<label id="outAudioStat">Audio stats</label>
|
|
36
|
+
<div></div>
|
|
37
|
+
<label id="outConnectionStat">Connection</label>
|
|
38
38
|
</div>
|
|
39
39
|
<div class="col-sm-4">
|
|
40
40
|
<div class="text-center text-muted">Local</div>
|
|
@@ -68,16 +68,16 @@
|
|
|
68
68
|
<div id="playStatus"></div>
|
|
69
69
|
</div>
|
|
70
70
|
</div>
|
|
71
|
-
<div class="col-sm-2"
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
71
|
+
<div class="col-sm-2">
|
|
72
|
+
<label id="inVideoStat">Video stats</label>
|
|
73
|
+
<div></div>
|
|
74
|
+
<label id="inAudioStat">Audio stats</label>
|
|
75
|
+
<div></div>
|
|
76
|
+
<label id="inConnectionStat">Connection</label>
|
|
77
77
|
</div>
|
|
78
78
|
</div>
|
|
79
79
|
<div class="row row-space">
|
|
80
|
-
<div class="col-sm-4 col-sm-offset-
|
|
80
|
+
<div class="col-sm-4 col-sm-offset-4">
|
|
81
81
|
<div id="connectionForm" class="input-group form-group">
|
|
82
82
|
<input class="form-control" id="urlServer" type="text">
|
|
83
83
|
<div class="input-group-btn">
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
</div>
|
|
99
99
|
<div class="row">
|
|
100
100
|
<form id="form" class="form-horizontal" role="form" style="margin-top: 10px; margin-left: 10px">
|
|
101
|
-
<div class="col-sm-4 col-sm-offset-
|
|
101
|
+
<div class="col-sm-4 col-sm-offset-2">
|
|
102
102
|
<div class="form-group" id="sendAudioGroup">
|
|
103
103
|
<div class="form-group">
|
|
104
104
|
<label class="col-sm-2 control-label"></label>
|
|
@@ -82,6 +82,8 @@
|
|
|
82
82
|
<div id="screenName"></div>
|
|
83
83
|
<div id="screenStatus"></div>
|
|
84
84
|
<div id="screenInfo"></div>
|
|
85
|
+
<div id="screenBitrate"></div>
|
|
86
|
+
<div id="screenAvailableBitrate"></div>
|
|
85
87
|
</div>
|
|
86
88
|
</div>
|
|
87
89
|
<div class="col-sm-6 text-center">
|
|
@@ -93,6 +95,8 @@
|
|
|
93
95
|
<div id="cameraName"></div>
|
|
94
96
|
<div id="cameraStatus"></div>
|
|
95
97
|
<div id="cameraInfo"></div>
|
|
98
|
+
<div id="cameraBitrate"></div>
|
|
99
|
+
<div id="cameraAvailableBitrate"></div>
|
|
96
100
|
</div>
|
|
97
101
|
</div>
|
|
98
102
|
<div class="row row-space text-center" style="margin-top: 20px">
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
const SESSION_STATUS = Flashphoner.constants.SESSION_STATUS;
|
|
2
2
|
const STREAM_STATUS = Flashphoner.constants.STREAM_STATUS;
|
|
3
3
|
const Browser = Flashphoner.Browser;
|
|
4
|
+
const STAT_INTERVAL = 1000;
|
|
4
5
|
let localVideoScreen;
|
|
5
6
|
let localVideoCamera;
|
|
7
|
+
let screenStats;
|
|
8
|
+
let cameraStats;
|
|
6
9
|
|
|
7
10
|
const init_page = function() {
|
|
8
11
|
//init api
|
|
@@ -61,6 +64,12 @@ const onStarted = function(cameraStream) {
|
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
const onStopped = function(session) {
|
|
67
|
+
if (cameraStats) {
|
|
68
|
+
cameraStats.stop();
|
|
69
|
+
}
|
|
70
|
+
if (screenStats) {
|
|
71
|
+
screenStats.stop();
|
|
72
|
+
}
|
|
64
73
|
setPublishButton("Start", session, null);
|
|
65
74
|
$("#connectBtn").prop('disabled', false);
|
|
66
75
|
}
|
|
@@ -152,6 +161,7 @@ const startStreamingScreen = function(session) {
|
|
|
152
161
|
resizeVideo(event.target);
|
|
153
162
|
});
|
|
154
163
|
setStatus("screen", STREAM_STATUS.PUBLISHING, screenStream);
|
|
164
|
+
screenStats = StreamStats("screen", screenStream, STAT_INTERVAL);
|
|
155
165
|
startStreamingCamera(session, screenStream);
|
|
156
166
|
}).on(STREAM_STATUS.UNPUBLISHED, function() {
|
|
157
167
|
setStatus("screen", STREAM_STATUS.UNPUBLISHED);
|
|
@@ -175,6 +185,7 @@ const startStreamingCamera = function(session, screenStream) {
|
|
|
175
185
|
resizeVideo(event.target);
|
|
176
186
|
});
|
|
177
187
|
setStatus("camera", STREAM_STATUS.PUBLISHING, cameraStream);
|
|
188
|
+
cameraStats = StreamStats("camera", cameraStream, STAT_INTERVAL);
|
|
178
189
|
onStarted(cameraStream);
|
|
179
190
|
}).on(STREAM_STATUS.UNPUBLISHED, function() {
|
|
180
191
|
setStatus("camera", STREAM_STATUS.UNPUBLISHED);
|
|
@@ -188,7 +199,6 @@ const startStreamingCamera = function(session, screenStream) {
|
|
|
188
199
|
}).publish();
|
|
189
200
|
}
|
|
190
201
|
|
|
191
|
-
//show connection or local stream status
|
|
192
202
|
const setStatus = function(type, status, stream) {
|
|
193
203
|
let nameField = $("#"+type+"Name");
|
|
194
204
|
let statusField = $("#"+type+"Status");
|
|
@@ -211,6 +221,24 @@ const setStatus = function(type, status, stream) {
|
|
|
211
221
|
}
|
|
212
222
|
}
|
|
213
223
|
|
|
224
|
+
const setBitrate = function(type, bitrate) {
|
|
225
|
+
let bitrateField = $("#" + type + "Bitrate");
|
|
226
|
+
let text = bitrate;
|
|
227
|
+
if (bitrate !== "") {
|
|
228
|
+
text = "Bitrate: " + bitrate;
|
|
229
|
+
}
|
|
230
|
+
bitrateField.text(text);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const setAvailableBitrate = function(type, bitrate) {
|
|
234
|
+
let bitrateField = $("#" + type + "AvailableBitrate");
|
|
235
|
+
let text = bitrate;
|
|
236
|
+
if (bitrate !== "") {
|
|
237
|
+
text = "Available bitrate: " + bitrate;
|
|
238
|
+
}
|
|
239
|
+
bitrateField.text(text);
|
|
240
|
+
}
|
|
241
|
+
|
|
214
242
|
const muteInputs = function() {
|
|
215
243
|
$(":input").each(function() {
|
|
216
244
|
$(this).prop('disabled',true);
|
|
@@ -250,7 +278,7 @@ const removeHighlight = function(input) {
|
|
|
250
278
|
input.closest('.form-group').removeClass("has-error");
|
|
251
279
|
}
|
|
252
280
|
|
|
253
|
-
|
|
281
|
+
const getStreamName = function(type, url) {
|
|
254
282
|
let streamName = url.endsWith('/') === false ? url.split('/')[3] : "";
|
|
255
283
|
if (streamName) {
|
|
256
284
|
streamName += "-" + type;
|
|
@@ -262,4 +290,44 @@ function getStreamName(type, url) {
|
|
|
262
290
|
}
|
|
263
291
|
}
|
|
264
292
|
return streamName;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const StreamStats = function(type, stream, interval) {
|
|
296
|
+
const streamStats = {
|
|
297
|
+
type: type,
|
|
298
|
+
timer: null,
|
|
299
|
+
stream: stream,
|
|
300
|
+
bytesSent: 0,
|
|
301
|
+
start: function(interval) {
|
|
302
|
+
if (!streamStats.timer) {
|
|
303
|
+
streamStats.timer = setInterval(streamStats.displayStats, interval);
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
stop: function() {
|
|
307
|
+
if (streamStats.timer) {
|
|
308
|
+
clearInterval(streamStats.timer);
|
|
309
|
+
streamStats.timer = null;
|
|
310
|
+
}
|
|
311
|
+
setBitrate(streamStats.type, "");
|
|
312
|
+
setAvailableBitrate(streamStats.type, "");
|
|
313
|
+
},
|
|
314
|
+
displayStats: function() {
|
|
315
|
+
if (streamStats.stream) {
|
|
316
|
+
streamStats.stream.getStats((stats) => {
|
|
317
|
+
if (stats) {
|
|
318
|
+
if (stats.outboundStream && stats.outboundStream.video) {
|
|
319
|
+
let vBitrate = (stats.outboundStream.video.bytesSent - streamStats.bytesSent) * 8;
|
|
320
|
+
setBitrate(streamStats.type, vBitrate);
|
|
321
|
+
streamStats.bytesSent = stats.outboundStream.video.bytesSent;
|
|
322
|
+
}
|
|
323
|
+
if (stats.otherStats && stats.otherStats.availableOutgoingBitrate !== undefined) {
|
|
324
|
+
setAvailableBitrate(streamStats.type, stats.otherStats.availableOutgoingBitrate);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
streamStats.start(interval);
|
|
332
|
+
return streamStats;
|
|
265
333
|
}
|