@flashphoner/websdk 2.0.210 → 2.0.215

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,4 +1,4 @@
1
- Web SDK - 2.0.210
1
+ Web SDK - 2.0.215
2
2
 
3
3
  [Download builds](https://docs.flashphoner.com/display/WEBSDK2EN/Web+SDK+release+notes)
4
4
 
@@ -66,6 +66,11 @@
66
66
  <div class="text-center" style="margin-top: 20px">
67
67
  <div id="participant1Status"></div>
68
68
  </div>
69
+ <div class="input-group text-center" style="margin: 5px auto 0 auto;">
70
+ <button id="participant1Btn" type="button" class="btn btn-default">Play</button>
71
+ <button id="participant1AudioBtn" type="button" class="btn btn-default">Audio</button>
72
+ <div id="participant1AudioState"></div>
73
+ </div>
69
74
  </div>
70
75
 
71
76
  <div class="col-sm-6">
@@ -76,6 +81,11 @@
76
81
  <div class="text-center" style="margin-top: 20px">
77
82
  <div id="participant2Status"></div>
78
83
  </div>
84
+ <div class="input-group text-center" style="margin: 5px auto 0 auto;">
85
+ <button id="participant2Btn" type="button" class="btn btn-default">Play</button>
86
+ <button id="participant2AudioBtn" type="button" class="btn btn-default">Audio</button>
87
+ <div id="participant2AudioState"></div>
88
+ </div>
79
89
  </div>
80
90
 
81
91
  </div>
@@ -5,6 +5,7 @@ var ROOM_EVENT = RoomApi.events;
5
5
  var PRELOADER_URL = "../../dependencies/media/preloader.mp4";
6
6
  var Browser = Flashphoner.Browser;
7
7
  var connection;
8
+ var participantStateList;
8
9
 
9
10
  //initialize interface
10
11
  function init_page() {
@@ -21,6 +22,7 @@ function init_page() {
21
22
  $("#notifyFlash").text("Your browser doesn't support WebRTC technology needed for this example");
22
23
  return;
23
24
  }
25
+ participantStateList = new ParticipantLocalStateList();
24
26
  $("#url").val(setURL());
25
27
  onLeft();
26
28
  }
@@ -47,6 +49,10 @@ function onLeft() {
47
49
  $("[id$=Name]").not(":contains('NONE')").each(function(index,value) {
48
50
  $(value).text('NONE');
49
51
  });
52
+ participantStateList.clean();
53
+ for (var i = 0; i < _participants; i++) {
54
+ resetParticipantButtons("participant" + i);
55
+ };
50
56
  $("#joinBtn").text("Join").off('click').click(function(){
51
57
  if (validateForm()) {
52
58
  $(this).prop('disabled', true);
@@ -75,14 +81,6 @@ function start() {
75
81
  return;
76
82
  }
77
83
  }
78
- if (Browser.isSafariWebRTC()) {
79
- for (var i = 1; i < _participants; i++){
80
- Flashphoner.playFirstVideo(document.getElementById("participant" + i + "Display"), false, PRELOADER_URL).then(function() {
81
- createConnection(url, username);
82
- });
83
- return;
84
- }
85
- }
86
84
  createConnection(url, username);
87
85
  }
88
86
 
@@ -123,14 +121,7 @@ function joinRoom() {
123
121
  } else {
124
122
  addMessage("chat", " room is empty");
125
123
  }
126
- if (Browser.isSafariWebRTC()) {
127
- Flashphoner.playFirstVideo(document.getElementById("localDisplay"), true, PRELOADER_URL).then(function() {
128
- publishLocalMedia(room);
129
- onJoined(room);
130
- });
131
- return;
132
- }
133
- publishLocalMedia(room);
124
+ publishLocalStream(room);
134
125
  onJoined(room);
135
126
  }).on(ROOM_EVENT.JOINED, function(participant){
136
127
  installParticipant(participant);
@@ -162,38 +153,131 @@ function installParticipant(participant) {
162
153
  if (($("[id$=Name]").not(":contains('NONE')").length + 1) == _participants) {
163
154
  console.warn("More than " + _participants + " participants, ignore participant " + participant.name());
164
155
  } else {
165
- var p = $("[id$=Name]:contains('NONE')")[0].id.replace('Name','');
166
- var pName = '#' + p + 'Name';
167
- var pDisplay = p + 'Display';
156
+ var pBase = $("[id$=Name]:contains('NONE')")[0].id.replace('Name','');
157
+ var pName = '#' + pBase + 'Name';
168
158
  $(pName).text(participant.name());
159
+ participantStateList.add(participant, pBase);
169
160
  playParticipantsStream(participant);
170
161
  }
171
162
  }
172
163
 
173
164
  function removeParticipant(participant) {
174
- $("[id$=Name]").each(function(index,value) {
175
- if ($(value).text() == participant.name()) {
176
- $(value).text('NONE');
177
- }
178
- });
165
+ var participantState = participantStateList.getState(participant);
166
+ if (participantState) {
167
+ participantStateList.remove(participant);
168
+ $(participantState.getName()).text('NONE');
169
+ resetParticipantButtons(participantState.getBaseId());
170
+ } else {
171
+ console.log("Cannot remove " + participant.name() + " from participants list: not found");
172
+ }
179
173
  }
180
174
 
181
175
  function playParticipantsStream(participant) {
182
- if (participant.getStreams().length > 0) {
183
- $("[id$=Name]").each(function (index, value) {
184
- if ($(value).text() == participant.name()) {
185
- var p = value.id.replace('Name', '');
186
- var pDisplay = p + 'Display';
187
- participant.getStreams()[0].play(document.getElementById(pDisplay)).on(STREAM_STATUS.PLAYING, function (playingStream) {
188
- document.getElementById(playingStream.id()).addEventListener('resize', function (event) {
189
- resizeVideo(event.target);
190
- });
191
- });
176
+ var participantState = participantStateList.getState(participant);
177
+ if (participantState && participant.getStreams().length > 0) {
178
+ var pDisplay = participantState.getDisplay();
179
+ if (Browser.isSafariWebRTC()) {
180
+ Flashphoner.playFirstVideo(pDisplay, false, PRELOADER_URL).then(function() {
181
+ playStream(participant, pDisplay);
182
+ }).catch(function (error) {
183
+ // Low Power Mode detected, user action is needed to start playback in this mode #WCS-2639
184
+ console.log("Can't atomatically play participant" + participant.name() + " stream, use Play button");
185
+ for (var i = 0; i < pDisplay.children.length; i++) {
186
+ if (pDisplay.children[i]) {
187
+ console.log("remove cached instance id " + pDisplay.children[i].id);
188
+ pDisplay.removeChild(pDisplay.children[i]);
189
+ }
190
+ }
191
+ onParticipantStopped(participant);
192
+ });
193
+ } else {
194
+ playStream(participant, pDisplay);
195
+ }
196
+ } else {
197
+ console.log("Cannot play participant " + participant.name() + " stream: participant not found");
198
+ }
199
+ }
200
+
201
+ function playStream(participant, display) {
202
+ var participantState = participantStateList.getState(participant);
203
+ if (participantState) {
204
+ var playBtn = participantState.getPlayButton();
205
+ var audioBtn = participantState.getAudioButton();
206
+ var options = {
207
+ unmutePlayOnStart: true,
208
+ constraints: {
209
+ audio: {
210
+ deviceId: 'default'
211
+ }
212
+ }
213
+ };
214
+ // Leave participant stream muted in Android Edge browser #WCS-3445
215
+ if (Browser.isChromiumEdge() && Browser.isAndroid()) {
216
+ options.unmutePlayOnStart = false;
217
+ }
218
+ participant.getStreams()[0].play(display, options).on(STREAM_STATUS.PLAYING, function (playingStream) {
219
+ var video = document.getElementById(playingStream.id())
220
+ video.addEventListener('resize', function (event) {
221
+ resizeVideo(event.target);
222
+ });
223
+ // Set up participant Stop/Play button
224
+ if (playBtn) {
225
+ $(playBtn).text("Stop").off('click').click(function() {
226
+ $(this).prop('disabled', true);
227
+ playingStream.stop();
228
+ }).prop('disabled', false);
192
229
  }
230
+ // Set up participant audio toggle button #WCS-3445
231
+ if (audioBtn) {
232
+ $(audioBtn).text("Audio").off('click').click(function() {
233
+ if (playingStream.isRemoteAudioMuted()) {
234
+ playingStream.unmuteRemoteAudio();
235
+ } else {
236
+ playingStream.muteRemoteAudio();
237
+ }
238
+ }).prop('disabled', false);
239
+ }
240
+ // Start participant audio state checking timer #WCS-3445
241
+ participantState.startMutedCheck(playingStream);
242
+ }).on(STREAM_STATUS.STOPPED, function () {
243
+ onParticipantStopped(participant);
244
+ }).on(STREAM_STATUS.FAILED, function () {
245
+ onParticipantStopped(participant);
193
246
  });
247
+ } else {
248
+ console.log("Cannot play stream: participant " + participant.name() + " not found");
249
+ }
250
+ }
251
+
252
+ function onParticipantStopped(participant) {
253
+ var participantState = participantStateList.getState(participant);
254
+ if (participantState) {
255
+ var playBtn = participantState.getPlayButton();
256
+ var audioBtn = participantState.getAudioButton();
257
+ var audioState = participantState.getAudioState();
258
+ if (playBtn) {
259
+ $(playBtn).text("Play").off('click').click(function() {
260
+ playParticipantsStream(participant);
261
+ }).prop('disabled', false);
262
+ }
263
+ if (audioBtn) {
264
+ $(audioBtn).text("Audio").off('click').prop('disabled', true);
265
+ }
266
+ if (audioState) {
267
+ participantState.stopMutedCheck();
268
+ $(audioState).text("");
269
+ }
270
+ } else {
271
+ console.log("Cannot perfom onStopped actions: " + participant.name() + " not found");
194
272
  }
195
273
  }
196
274
 
275
+ function resetParticipantButtons(id) {
276
+ $("#" + id + 'Btn').text("Play").off('click').prop('disabled', true);
277
+ $("#" + id + 'AudioBtn').text("Audio").off('click').prop('disabled', true);
278
+ $("#" + id + 'AudioState').text("");
279
+ }
280
+
197
281
  function getRoomName() {
198
282
  var name = getUrlParam("roomName");
199
283
  if (name && name !== '') {
@@ -239,7 +323,7 @@ function onMediaPublished(stream) {
239
323
  function onMediaStopped(room) {
240
324
  $("#localStopBtn").text("Publish").off('click').click(function(){
241
325
  $(this).prop('disabled', true);
242
- publishLocalMedia(room);
326
+ publishLocalStream(room);
243
327
  }).prop('disabled', (connection.getRooms().length == 0));
244
328
  $("#localAudioToggle").prop("disabled", true);
245
329
  $("#localVideoToggle").prop("disabled", true);
@@ -274,6 +358,26 @@ function publishLocalMedia(room) {
274
358
  });
275
359
  }
276
360
 
361
+ function publishLocalStream(room) {
362
+ if (Browser.isSafariWebRTC()) {
363
+ var display = document.getElementById("localDisplay");
364
+ Flashphoner.playFirstVideo(display, true, PRELOADER_URL).then(function() {
365
+ publishLocalMedia(room);
366
+ }).catch(function (error) {
367
+ console.log("Can't atomatically publish local stream, use Publish button");
368
+ for (var i = 0; i < display.children.length; i++) {
369
+ if (display.children[i]) {
370
+ console.log("remove cached instance id " + display.children[i].id);
371
+ display.removeChild(display.children[i]);
372
+ }
373
+ }
374
+ onMediaStopped(room);
375
+ });
376
+ } else {
377
+ publishLocalMedia(room);
378
+ }
379
+ }
380
+
277
381
  function muteConnectInputs() {
278
382
  $(':text').each(function(){
279
383
  $(this).prop('disabled', true);
@@ -317,3 +421,100 @@ function setStatus(selector, status) {
317
421
  statusField.attr("class","text-danger");
318
422
  }
319
423
  }
424
+
425
+ // Object to store local state to display participant #WCS-3445
426
+ function ParticipantLocalState(participant, id) {
427
+ var state = {
428
+ participant: participant,
429
+ baseId: id,
430
+ audioTimer: null,
431
+ getBaseId: function() {
432
+ return state.baseId;
433
+ },
434
+ getName: function() {
435
+ return document.getElementById(state.baseId + 'Name');
436
+ },
437
+ getDisplay: function() {
438
+ return document.getElementById(state.baseId + 'Display');
439
+ },
440
+ getPlayButton: function() {
441
+ return document.getElementById(state.baseId + 'Btn');
442
+ },
443
+ getAudioButton: function() {
444
+ return document.getElementById(state.baseId + 'AudioBtn');
445
+ },
446
+ getAudioState: function() {
447
+ return document.getElementById(state.baseId + 'AudioState');
448
+ },
449
+ startMutedCheck: function(stream) {
450
+ var audioState = state.getAudioState();
451
+ state.stopMutedCheck();
452
+ state.audioTimer = setInterval(function () {
453
+ if (stream.isRemoteAudioMuted()) {
454
+ $(audioState).text("Muted");
455
+ } else {
456
+ $(audioState).text("Unmuted");
457
+ }
458
+ }, 500);
459
+ },
460
+ stopMutedCheck: function() {
461
+ if (state.audioTimer) {
462
+ clearInterval(state.audioTimer);
463
+ state.audioTimer = null;
464
+ }
465
+ }
466
+ }
467
+
468
+ return state;
469
+ }
470
+
471
+ // Array object to store local participant states #WCS-3445
472
+ function ParticipantLocalStateList() {
473
+ var stateList = {
474
+ list: [],
475
+ add: function(participant, id) {
476
+ var state = new ParticipantLocalState(participant, id);
477
+ stateList.list.push(state);
478
+ },
479
+ remove: function(participant) {
480
+ for (var i = 0; i < stateList.list.length; i++) {
481
+ if (stateList.list[i].participant && (stateList.list[i].participant.name() === participant.name())) {
482
+ stateList.list[i].stopMutedCheck();
483
+ stateList.list.splice(i, 1);
484
+ }
485
+ }
486
+ },
487
+ clean: function() {
488
+ while (stateList.list.length) {
489
+ var state = stateList.list.pop();
490
+ state.stopMutedCheck();
491
+ }
492
+ },
493
+ getState: function(participant) {
494
+ for (var i = 0; i < stateList.list.length; i++) {
495
+ if (stateList.list[i].participant && (stateList.list[i].participant.name() === participant.name())) {
496
+ return stateList.list[i];
497
+ }
498
+ }
499
+ return null;
500
+ },
501
+ startMutedCheck: function(participant, stream) {
502
+ var item = stateList.getState(participant);
503
+ if (item) {
504
+ item.startMutedCheck(stream);
505
+ } else {
506
+ console.error("Cannot start muted check timer for participant " + participant);
507
+ }
508
+ },
509
+ stopMutedCheck: function(participant) {
510
+ var item = stateList.getState(participant);
511
+ if (item) {
512
+ item.stopMutedCheck();
513
+ } else {
514
+ console.error("Cannot stop muted check timer for participant " + participant);
515
+ }
516
+ }
517
+ }
518
+
519
+ return stateList;
520
+ }
@@ -61,6 +61,11 @@
61
61
  <div class="text-center" style="margin-top: 20px">
62
62
  <div id="participant1Status"></div>
63
63
  </div>
64
+ <div class="input-group text-center" style="margin: 5px auto 0 auto;">
65
+ <button id="participant1Btn" type="button" class="btn btn-default">Play</button>
66
+ <button id="participant1AudioBtn" type="button" class="btn btn-default">Audio</button>
67
+ <div id="participant1AudioState"></div>
68
+ </div>
64
69
  </div>
65
70
 
66
71
  <div class="col-sm-7">