@flashphoner/websdk 2.0.206 → 2.0.207
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/stream-auto-restore/stream-auto-restore.css +23 -0
- package/examples/demo/streaming/stream-auto-restore/stream-auto-restore.html +76 -0
- package/examples/demo/streaming/stream-auto-restore/stream-auto-restore.js +356 -0
- package/flashphoner-no-flash.js +16 -16
- package/flashphoner-no-flash.min.js +2 -2
- package/flashphoner-no-webrtc.js +15 -15
- package/flashphoner-no-webrtc.min.js +1 -1
- package/flashphoner-no-wsplayer.js +17 -17
- package/flashphoner-no-wsplayer.min.js +2 -2
- package/flashphoner-room-api.js +3 -3
- package/flashphoner-room-api.min.js +2 -2
- package/flashphoner-temasys-flash-websocket-without-adapterjs.js +17 -17
- package/flashphoner-temasys-flash-websocket.js +17 -17
- package/flashphoner-temasys-flash-websocket.min.js +1 -1
- package/flashphoner-webrtc-only.js +14 -14
- package/flashphoner-webrtc-only.min.js +1 -1
- package/flashphoner.js +17 -17
- package/flashphoner.min.js +2 -2
- package/package.json +1 -1
- package/src/flashphoner-core.js +1 -1
- package/src/webrtc-media-provider.js +2 -2
package/docTemplate/README.md
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
.fp-Video {
|
|
2
|
+
border: 1px double black;
|
|
3
|
+
width: 322px;
|
|
4
|
+
height: 242px;
|
|
5
|
+
text-align: center;
|
|
6
|
+
background: #c0c0c0;
|
|
7
|
+
margin: 0 auto 0 auto;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.display {
|
|
11
|
+
width: 100%;
|
|
12
|
+
height: 100%;
|
|
13
|
+
display: inline-block;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.display > video, object {
|
|
17
|
+
width: 100%;
|
|
18
|
+
height: 100%;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
video:-webkit-full-screen {
|
|
22
|
+
border-radius: 1px;
|
|
23
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<link rel="stylesheet" href="../../dependencies/bootstrap/css/bootstrap.css">
|
|
7
|
+
<link rel="stylesheet" href="../../dependencies/bootstrap/font-awesome/css/font-awesome.min.css">
|
|
8
|
+
<link rel="stylesheet" href="stream-auto-restore.css">
|
|
9
|
+
<title>Two-way Streaming</title>
|
|
10
|
+
<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/js/utils.js"></script>
|
|
13
|
+
|
|
14
|
+
<script type="text/javascript" src="stream-auto-restore.js"></script>
|
|
15
|
+
</head>
|
|
16
|
+
<body onload="init_page()">
|
|
17
|
+
<div class="container">
|
|
18
|
+
<div class="row">
|
|
19
|
+
|
|
20
|
+
<h2 id="notifyFlash" class="text-danger"></h2>
|
|
21
|
+
|
|
22
|
+
<div class="col-sm-9 text-center">
|
|
23
|
+
|
|
24
|
+
<h2 class="text-center">Streaming Auto Restore</h2>
|
|
25
|
+
|
|
26
|
+
<div class="col-sm-6">
|
|
27
|
+
<div class="text-center text-muted">Local</div>
|
|
28
|
+
<div class="fp-Video">
|
|
29
|
+
<div id="localVideo" class="display"></div>
|
|
30
|
+
</div>
|
|
31
|
+
<div id="streamerForm" class="input-group col-sm-10" style="margin: 10px auto 0 auto;">
|
|
32
|
+
<input class="form-control" type="text" id="publishStream" placeholder="Stream Name">
|
|
33
|
+
<div class="input-group-btn">
|
|
34
|
+
<button id="publishBtn" type="button" class="btn btn-default">Publish</button>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
<div class="text-center" style="margin-top: 20px">
|
|
38
|
+
<div id="publishStatus"></div>
|
|
39
|
+
<div id="publishInfo"></div>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<div class="col-sm-6">
|
|
44
|
+
<div class="text-center text-muted">Player</div>
|
|
45
|
+
<div class="fp-Video">
|
|
46
|
+
<div id="remoteVideo" class="display"></div>
|
|
47
|
+
</div>
|
|
48
|
+
<div id="playerForm" class="input-group col-sm-10" style="margin: 10px auto 0 auto;">
|
|
49
|
+
<input class="form-control" type="text" id="playStream" placeholder="Stream Name">
|
|
50
|
+
<div class="input-group-btn">
|
|
51
|
+
<button id="playBtn" type="button" class="btn btn-default">Play</button>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
<div class="text-center" style="margin-top: 20px">
|
|
55
|
+
<div id="playStatus"></div>
|
|
56
|
+
<div id="playInfo"></div>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
<div class="row row-space">
|
|
62
|
+
<div class="col-sm-5 col-sm-offset-2">
|
|
63
|
+
<div id="connectionForm" class="input-group">
|
|
64
|
+
<input class="form-control" id="urlServer" type="text">
|
|
65
|
+
<div class="input-group-btn">
|
|
66
|
+
<button id="connectBtn" type="button" class="btn btn-default">Connect</button>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
<div class="text-center">
|
|
70
|
+
<div id="connectStatus"></div>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</body>
|
|
76
|
+
</html>
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
var SESSION_STATUS = Flashphoner.constants.SESSION_STATUS;
|
|
2
|
+
var STREAM_STATUS = Flashphoner.constants.STREAM_STATUS;
|
|
3
|
+
var STREAM_EVENT = Flashphoner.constants.STREAM_EVENT;
|
|
4
|
+
var STREAM_EVENT_TYPE = Flashphoner.constants.STREAM_EVENT_TYPE;
|
|
5
|
+
var STREAM_STATUS_INFO = Flashphoner.constants.STREAM_STATUS_INFO;
|
|
6
|
+
var ERROR_INFO = Flashphoner.constants.ERROR_INFO;
|
|
7
|
+
var PRELOADER_URL = "../../dependencies/media/preloader.mp4";
|
|
8
|
+
var PUBLISH_FAILURE_DETECTOR_MAX_TRIES = 3;
|
|
9
|
+
var PUBLISH_FAILURE_DETECTOR_INTERVAL = 500;
|
|
10
|
+
var Browser = Flashphoner.Browser;
|
|
11
|
+
var localVideo;
|
|
12
|
+
var remoteVideo;
|
|
13
|
+
var publishFailureIntervalID;
|
|
14
|
+
// H264 publishing failure detection parameters using outgoing video stats in Chrome #WCS-3382
|
|
15
|
+
var statPublishFailureDetector = {
|
|
16
|
+
failed: false,
|
|
17
|
+
codec: "",
|
|
18
|
+
lastBytesSent: 0,
|
|
19
|
+
counter: {
|
|
20
|
+
value: 0,
|
|
21
|
+
threshold: PUBLISH_FAILURE_DETECTOR_MAX_TRIES
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
//////////////////////////////////
|
|
26
|
+
/////////////// Init /////////////
|
|
27
|
+
|
|
28
|
+
function init_page() {
|
|
29
|
+
//init api
|
|
30
|
+
try {
|
|
31
|
+
Flashphoner.init();
|
|
32
|
+
} catch (e) {
|
|
33
|
+
$("#notifyFlash").text("Your browser doesn't support WebRTC technology needed for this example");
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
//local and remote displays
|
|
38
|
+
localVideo = document.getElementById("localVideo");
|
|
39
|
+
remoteVideo = document.getElementById("remoteVideo");
|
|
40
|
+
|
|
41
|
+
$("#urlServer").val(setURL());
|
|
42
|
+
var streamName = createUUID(4);
|
|
43
|
+
$("#publishStream").val(streamName);
|
|
44
|
+
$("#playStream").val(streamName);
|
|
45
|
+
onDisconnected();
|
|
46
|
+
onUnpublished();
|
|
47
|
+
onStopped();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function connect() {
|
|
51
|
+
var url = $('#urlServer').val();
|
|
52
|
+
|
|
53
|
+
//create session
|
|
54
|
+
console.log("Create new session with url " + url);
|
|
55
|
+
Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function (session) {
|
|
56
|
+
setStatus("#connectStatus", session.status());
|
|
57
|
+
onConnected(session);
|
|
58
|
+
}).on(SESSION_STATUS.DISCONNECTED, function () {
|
|
59
|
+
setStatus("#connectStatus", SESSION_STATUS.DISCONNECTED);
|
|
60
|
+
onDisconnected();
|
|
61
|
+
}).on(SESSION_STATUS.FAILED, function () {
|
|
62
|
+
setStatus("#connectStatus", SESSION_STATUS.FAILED);
|
|
63
|
+
onDisconnected();
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function onConnected(session) {
|
|
68
|
+
$("#connectBtn").text("Disconnect").off('click').click(function () {
|
|
69
|
+
$(this).prop('disabled', true);
|
|
70
|
+
session.disconnect();
|
|
71
|
+
}).prop('disabled', false);
|
|
72
|
+
onUnpublished();
|
|
73
|
+
onStopped();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function onDisconnected() {
|
|
77
|
+
$("#connectBtn").text("Connect").off('click').click(function () {
|
|
78
|
+
if (validateForm("connectionForm")) {
|
|
79
|
+
$('#urlServer').prop('disabled', true);
|
|
80
|
+
$(this).prop('disabled', true);
|
|
81
|
+
connect();
|
|
82
|
+
}
|
|
83
|
+
}).prop('disabled', false);
|
|
84
|
+
$('#urlServer').prop('disabled', false);
|
|
85
|
+
onUnpublished();
|
|
86
|
+
onStopped();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function onPublishing(stream) {
|
|
90
|
+
$("#publishBtn").text("Stop").off('click').click(function () {
|
|
91
|
+
$(this).prop('disabled', true);
|
|
92
|
+
stream.stop();
|
|
93
|
+
}).prop('disabled', false);
|
|
94
|
+
$("#publishInfo").text("");
|
|
95
|
+
// Start publish failure detector in Chrome browser #WCS-3382
|
|
96
|
+
if(Browser.isChrome()) {
|
|
97
|
+
detectPublishFailure(stream, PUBLISH_FAILURE_DETECTOR_INTERVAL, PUBLISH_FAILURE_DETECTOR_MAX_TRIES);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function onUnpublished() {
|
|
102
|
+
$("#publishBtn").text("Publish").off('click').click(publishBtnClick);
|
|
103
|
+
if (Flashphoner.getSessions()[0] && Flashphoner.getSessions()[0].status() == SESSION_STATUS.ESTABLISHED) {
|
|
104
|
+
$("#publishBtn").prop('disabled', false);
|
|
105
|
+
$('#publishStream').prop('disabled', false);
|
|
106
|
+
} else {
|
|
107
|
+
$("#publishBtn").prop('disabled', true);
|
|
108
|
+
$('#publishStream').prop('disabled', true);
|
|
109
|
+
}
|
|
110
|
+
if (publishFailureIntervalID) {
|
|
111
|
+
clearInterval(publishFailureIntervalID);
|
|
112
|
+
publishFailureIntervalID = null;
|
|
113
|
+
}
|
|
114
|
+
checkPublishFailureConditions();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function publishBtnClick(stripCodecs) {
|
|
118
|
+
if (validateForm("streamerForm")) {
|
|
119
|
+
$('#publishStream').prop('disabled', true);
|
|
120
|
+
$(this).prop('disabled', true);
|
|
121
|
+
if (Browser.isSafariWebRTC()) {
|
|
122
|
+
Flashphoner.playFirstVideo(localVideo, true, PRELOADER_URL).then(function() {
|
|
123
|
+
publishStream(stripCodecs);
|
|
124
|
+
});
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
publishStream(stripCodecs);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function onPlaying(stream) {
|
|
132
|
+
$("#playBtn").text("Stop").off('click').click(function () {
|
|
133
|
+
$(this).prop('disabled', true);
|
|
134
|
+
stream.stop();
|
|
135
|
+
}).prop('disabled', false);
|
|
136
|
+
$("#playInfo").text("");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function onStopped() {
|
|
140
|
+
$("#playBtn").text("Play").off('click').click(playBtnClick);
|
|
141
|
+
if (Flashphoner.getSessions()[0] && Flashphoner.getSessions()[0].status() == SESSION_STATUS.ESTABLISHED) {
|
|
142
|
+
$("#playBtn").prop('disabled', false);
|
|
143
|
+
$('#playStream').prop('disabled', false);
|
|
144
|
+
} else {
|
|
145
|
+
$("#playBtn").prop('disabled', true);
|
|
146
|
+
$('#playStream').prop('disabled', true);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function playBtnClick() {
|
|
151
|
+
if (validateForm("playerForm")) {
|
|
152
|
+
$('#playStream').prop('disabled', true);
|
|
153
|
+
$(this).prop('disabled', true);
|
|
154
|
+
if (Flashphoner.getMediaProviders()[0] === "WSPlayer") {
|
|
155
|
+
Flashphoner.playFirstSound();
|
|
156
|
+
} else if (Browser.isSafariWebRTC() || Flashphoner.getMediaProviders()[0] === "MSE") {
|
|
157
|
+
Flashphoner.playFirstVideo(remoteVideo, false, PRELOADER_URL).then(function () {
|
|
158
|
+
playStream();
|
|
159
|
+
});
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
playStream();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function publishStream(stripCodecs) {
|
|
167
|
+
var session = Flashphoner.getSessions()[0];
|
|
168
|
+
var streamName = $('#publishStream').val();
|
|
169
|
+
|
|
170
|
+
session.createStream({
|
|
171
|
+
name: streamName,
|
|
172
|
+
display: localVideo,
|
|
173
|
+
cacheLocalResources: true,
|
|
174
|
+
receiveVideo: false,
|
|
175
|
+
receiveAudio: false,
|
|
176
|
+
stripCodecs: stripCodecs
|
|
177
|
+
}).on(STREAM_STATUS.PUBLISHING, function (stream) {
|
|
178
|
+
setStatus("#publishStatus", STREAM_STATUS.PUBLISHING);
|
|
179
|
+
onPublishing(stream);
|
|
180
|
+
}).on(STREAM_STATUS.UNPUBLISHED, function () {
|
|
181
|
+
setStatus("#publishStatus", STREAM_STATUS.UNPUBLISHED);
|
|
182
|
+
onUnpublished();
|
|
183
|
+
}).on(STREAM_STATUS.FAILED, function (stream) {
|
|
184
|
+
setStatus("#publishStatus", STREAM_STATUS.FAILED, stream);
|
|
185
|
+
onUnpublished();
|
|
186
|
+
}).publish();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function playStream() {
|
|
190
|
+
var session = Flashphoner.getSessions()[0];
|
|
191
|
+
var streamName = $('#playStream').val();
|
|
192
|
+
|
|
193
|
+
session.createStream({
|
|
194
|
+
name: streamName,
|
|
195
|
+
display: remoteVideo
|
|
196
|
+
}).on(STREAM_STATUS.PENDING, function (stream) {
|
|
197
|
+
var video = document.getElementById(stream.id());
|
|
198
|
+
if (!video.hasListeners) {
|
|
199
|
+
video.hasListeners = true;
|
|
200
|
+
video.addEventListener('resize', function (event) {
|
|
201
|
+
resizeVideo(event.target);
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}).on(STREAM_STATUS.PLAYING, function (stream) {
|
|
205
|
+
setStatus("#playStatus", stream.status());
|
|
206
|
+
onPlaying(stream);
|
|
207
|
+
}).on(STREAM_STATUS.STOPPED, function () {
|
|
208
|
+
setStatus("#playStatus", STREAM_STATUS.STOPPED);
|
|
209
|
+
onStopped();
|
|
210
|
+
}).on(STREAM_STATUS.FAILED, function (stream) {
|
|
211
|
+
setStatus("#playStatus", STREAM_STATUS.FAILED, stream);
|
|
212
|
+
onStopped();
|
|
213
|
+
}).on(STREAM_EVENT, function(streamEvent) {
|
|
214
|
+
switch (streamEvent.type) {
|
|
215
|
+
case STREAM_EVENT_TYPE.DATA:
|
|
216
|
+
addPayload(streamEvent.payload);
|
|
217
|
+
break;
|
|
218
|
+
}
|
|
219
|
+
console.log("Received streamEvent ", streamEvent.type);
|
|
220
|
+
}).play();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
//show connection, or local, or remote stream status
|
|
225
|
+
function setStatus(selector, status, stream) {
|
|
226
|
+
var statusField = $(selector);
|
|
227
|
+
statusField.text(status).removeClass();
|
|
228
|
+
if (status == "PLAYING" || status == "ESTABLISHED" || status == "PUBLISHING") {
|
|
229
|
+
statusField.attr("class", "text-success");
|
|
230
|
+
} else if (status == "DISCONNECTED" || status == "UNPUBLISHED" || status == "STOPPED") {
|
|
231
|
+
statusField.attr("class", "text-muted");
|
|
232
|
+
} else if (status == "FAILED") {
|
|
233
|
+
if (stream) {
|
|
234
|
+
if (stream.published()) {
|
|
235
|
+
switch(stream.getInfo()){
|
|
236
|
+
case STREAM_STATUS_INFO.STREAM_NAME_ALREADY_IN_USE:
|
|
237
|
+
$("#publishInfo").text("Server already has a publish stream with the same name, try using different one").attr("class", "text-muted");
|
|
238
|
+
break;
|
|
239
|
+
case ERROR_INFO.LOCAL_ERROR:
|
|
240
|
+
$("#publishInfo").text("Browser error detected: " + stream.getErrorInfo()).attr("class", "text-muted");
|
|
241
|
+
break;
|
|
242
|
+
default:
|
|
243
|
+
$("#publishInfo").text("Other: "+stream.getInfo()).attr("class", "text-muted");
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
} else {
|
|
247
|
+
switch(stream.getInfo()){
|
|
248
|
+
case STREAM_STATUS_INFO.SESSION_DOES_NOT_EXIST:
|
|
249
|
+
$("#playInfo").text("Actual session does not exist").attr("class", "text-muted");
|
|
250
|
+
break;
|
|
251
|
+
case STREAM_STATUS_INFO.STOPPED_BY_PUBLISHER_STOP:
|
|
252
|
+
$("#playInfo").text("Related publisher stopped its stream or lost connection").attr("class", "text-muted");
|
|
253
|
+
break;
|
|
254
|
+
case STREAM_STATUS_INFO.SESSION_NOT_READY:
|
|
255
|
+
$("#playInfo").text("Session is not initialized or terminated on play ordinary stream").attr("class", "text-muted");
|
|
256
|
+
break;
|
|
257
|
+
case STREAM_STATUS_INFO.RTSP_STREAM_NOT_FOUND:
|
|
258
|
+
$("#playInfo").text("Rtsp stream not found where agent received '404-Not Found'").attr("class", "text-muted");
|
|
259
|
+
break;
|
|
260
|
+
case STREAM_STATUS_INFO.FAILED_TO_CONNECT_TO_RTSP_STREAM:
|
|
261
|
+
$("#playInfo").text("Failed to connect to rtsp stream").attr("class", "text-muted");
|
|
262
|
+
break;
|
|
263
|
+
case STREAM_STATUS_INFO.FILE_NOT_FOUND:
|
|
264
|
+
$("#playInfo").text("File does not exist, check filename").attr("class", "text-muted");
|
|
265
|
+
break;
|
|
266
|
+
case STREAM_STATUS_INFO.FILE_HAS_WRONG_FORMAT:
|
|
267
|
+
$("#playInfo").text("File has wrong format on play vod, this format is not supported").attr("class", "text-muted");
|
|
268
|
+
break;
|
|
269
|
+
case STREAM_STATUS_INFO.TRANSCODING_REQUIRED_BUT_DISABLED:
|
|
270
|
+
$("#playInfo").text("Transcoding required, but disabled in settings").attr("class", "text-muted");
|
|
271
|
+
break;
|
|
272
|
+
case STREAM_STATUS_INFO.NO_AVAILABLE_TRANSCODERS:
|
|
273
|
+
$("#playInfo").text("No available transcoders for stream").attr("class", "text-muted");
|
|
274
|
+
break;
|
|
275
|
+
default:
|
|
276
|
+
$("#playInfo").text("Other: "+stream.getInfo()).attr("class", "text-muted");
|
|
277
|
+
break;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
statusField.attr("class", "text-danger");
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Detect publishing failure in Chrome using outgoing streaming stats #WCS-3382
|
|
286
|
+
function detectPublishFailure(stream, failureCheckInterval, maxBitrateDropsCount) {
|
|
287
|
+
statPublishFailureDetector = {
|
|
288
|
+
failed: false,
|
|
289
|
+
codec: "",
|
|
290
|
+
lastBytesSent: 0,
|
|
291
|
+
counter: {
|
|
292
|
+
value: 0,
|
|
293
|
+
threshold: maxBitrateDropsCount
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
publishFailureIntervalID = setInterval(function() {
|
|
297
|
+
stream.getStats(function(stat) {
|
|
298
|
+
let videoStats = stat.outboundStream.video;
|
|
299
|
+
if(!videoStats) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
let codec = videoStats.codec;
|
|
303
|
+
let bytesSent = videoStats.bytesSent;
|
|
304
|
+
let bitrate = (bytesSent - statPublishFailureDetector.lastBytesSent) * 8;
|
|
305
|
+
if (bitrate == 0) {
|
|
306
|
+
statPublishFailureDetector.counter.value++;
|
|
307
|
+
console.log("Bitrate is 0 (" + statPublishFailureDetector.counter.value + ")");
|
|
308
|
+
if (statPublishFailureDetector.counter.value >= statPublishFailureDetector.counter.threshold) {
|
|
309
|
+
statPublishFailureDetector.failed = true;
|
|
310
|
+
console.log("Publishing seems to be failed, stop the stream");
|
|
311
|
+
stream.stop();
|
|
312
|
+
}
|
|
313
|
+
} else {
|
|
314
|
+
statPublishFailureDetector.counter.value = 0;
|
|
315
|
+
}
|
|
316
|
+
statPublishFailureDetector.lastBytesSent = bytesSent;
|
|
317
|
+
statPublishFailureDetector.codec = codec;
|
|
318
|
+
$("#publishInfo").text(statPublishFailureDetector.codec);
|
|
319
|
+
});
|
|
320
|
+
}, failureCheckInterval);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Check if H264 publishing is failed in Chrome and restart as VP8 #WCS-3382
|
|
324
|
+
function checkPublishFailureConditions() {
|
|
325
|
+
if (statPublishFailureDetector.failed) {
|
|
326
|
+
$("#publishInfo").text("Failed to publish " + statPublishFailureDetector.codec);
|
|
327
|
+
if (statPublishFailureDetector.codec == "H264") {
|
|
328
|
+
console.log("H264 publishing seems to be failed, trying VP8 by stripping H264");
|
|
329
|
+
let stripCodecs = "H264";
|
|
330
|
+
publishBtnClick(stripCodecs);
|
|
331
|
+
} else if (statPublishFailureDetector.codec == "VP8") {
|
|
332
|
+
console.log("VP8 publishing seems to be failed, giving up");
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function validateForm(formId) {
|
|
338
|
+
var valid = true;
|
|
339
|
+
$('#' + formId + ' :text').each(function () {
|
|
340
|
+
if (!$(this).val()) {
|
|
341
|
+
highlightInput($(this));
|
|
342
|
+
valid = false;
|
|
343
|
+
} else {
|
|
344
|
+
removeHighlight($(this));
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
return valid;
|
|
348
|
+
|
|
349
|
+
function highlightInput(input) {
|
|
350
|
+
input.closest('.input-group').addClass("has-error");
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function removeHighlight(input) {
|
|
354
|
+
input.closest('.input-group').removeClass("has-error");
|
|
355
|
+
}
|
|
356
|
+
}
|