|
@@ -17,7 +17,7 @@ export const SHARED_VIDEO_CONTAINER_TYPE = "sharedvideo";
|
17
|
17
|
* @type {string}
|
18
|
18
|
*/
|
19
|
19
|
const defaultSharedVideoLink = "https://www.youtube.com/watch?v=xNXN7CZk8X0";
|
20
|
|
-
|
|
20
|
+const updateInterval = 5000; // milliseconds
|
21
|
21
|
/**
|
22
|
22
|
* Manager of shared video.
|
23
|
23
|
*/
|
|
@@ -26,7 +26,6 @@ export default class SharedVideoManager {
|
26
|
26
|
this.emitter = emitter;
|
27
|
27
|
this.isSharedVideoShown = false;
|
28
|
28
|
this.isPlayerAPILoaded = false;
|
29
|
|
- this.updateInterval = 5000; // milliseconds
|
30
|
29
|
}
|
31
|
30
|
|
32
|
31
|
/**
|
|
@@ -71,6 +70,13 @@ export default class SharedVideoManager {
|
71
|
70
|
var firstScriptTag = document.getElementsByTagName('script')[0];
|
72
|
71
|
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
|
73
|
72
|
|
|
73
|
+ // sometimes we receive errors like player not defined
|
|
74
|
+ // or player.pauseVideo is not a function
|
|
75
|
+ // we need to operate with player after start playing
|
|
76
|
+ // self.player will be defined once it start playing
|
|
77
|
+ // and will process any initial attributes if any
|
|
78
|
+ this.initialAttributes = null;
|
|
79
|
+
|
74
|
80
|
var self = this;
|
75
|
81
|
if(self.isPlayerAPILoaded)
|
76
|
82
|
window.onYouTubeIframeAPIReady();
|
|
@@ -78,14 +84,14 @@ export default class SharedVideoManager {
|
78
|
84
|
window.onYouTubeIframeAPIReady = function() {
|
79
|
85
|
self.isPlayerAPILoaded = true;
|
80
|
86
|
let showControls = APP.conference.isLocalId(self.from) ? 1 : 0;
|
81
|
|
- self.player = new YT.Player('sharedVideoIFrame', {
|
|
87
|
+ new YT.Player('sharedVideoIFrame', {
|
82
|
88
|
height: '100%',
|
83
|
89
|
width: '100%',
|
84
|
90
|
videoId: self.url,
|
85
|
91
|
playerVars: {
|
86
|
92
|
'origin': location.origin,
|
87
|
93
|
'fs': '0',
|
88
|
|
- 'autoplay': 1,
|
|
94
|
+ 'autoplay': 0,
|
89
|
95
|
'controls': showControls,
|
90
|
96
|
'rel' : 0
|
91
|
97
|
},
|
|
@@ -97,19 +103,19 @@ export default class SharedVideoManager {
|
97
|
103
|
});
|
98
|
104
|
};
|
99
|
105
|
|
100
|
|
- // whether we should pause the player as initial status
|
101
|
|
- // sometimes if we try to pause the player before it starts playing
|
102
|
|
- // we can end up with player in buffering mode
|
103
|
|
- this.initialPause = false;
|
104
|
106
|
window.onPlayerStateChange = function(event) {
|
105
|
107
|
if (event.data == YT.PlayerState.PLAYING) {
|
106
|
108
|
self.playerPaused = false;
|
107
|
109
|
|
108
|
|
- // check for initial pause
|
109
|
|
- if(self.initialPause) {
|
110
|
|
- self.initialPause = false;
|
111
|
|
- self.player.pauseVideo();
|
|
110
|
+ self.player = event.target;
|
|
111
|
+
|
|
112
|
+ if(self.initialAttributes)
|
|
113
|
+ {
|
|
114
|
+ self.processAttributes(
|
|
115
|
+ self.player, self.initialAttributes, self.playerPaused);
|
|
116
|
+ self.initialAttributes = null;
|
112
|
117
|
}
|
|
118
|
+
|
113
|
119
|
self.updateCheck();
|
114
|
120
|
} else if (event.data == YT.PlayerState.PAUSED) {
|
115
|
121
|
self.playerPaused = true;
|
|
@@ -119,6 +125,8 @@ export default class SharedVideoManager {
|
119
|
125
|
|
120
|
126
|
window.onPlayerReady = function(event) {
|
121
|
127
|
let player = event.target;
|
|
128
|
+ // do not relay on autoplay as it is not sending all of the events
|
|
129
|
+ // in onPlayerStateChange
|
122
|
130
|
player.playVideo();
|
123
|
131
|
|
124
|
132
|
let thumb = new SharedVideoThumb(self.url);
|
|
@@ -140,15 +148,14 @@ export default class SharedVideoManager {
|
140
|
148
|
if(APP.conference.isLocalId(self.from)) {
|
141
|
149
|
self.intervalId = setInterval(
|
142
|
150
|
self.updateCheck.bind(self),
|
143
|
|
- self.updateInterval);
|
|
151
|
+ updateInterval);
|
144
|
152
|
}
|
145
|
153
|
|
146
|
|
- // set initial state of the player if there is enough information
|
147
|
|
- if(attributes.state === 'pause')
|
148
|
|
- self.initialPause = true;
|
149
|
|
- else if(attributes.time > 0) {
|
150
|
|
- console.log("Player seekTo:", attributes.time);
|
151
|
|
- player.seekTo(attributes.time);
|
|
154
|
+ if(self.player)
|
|
155
|
+ self.processAttributes(
|
|
156
|
+ self.player, attributes, self.playerPaused);
|
|
157
|
+ else {
|
|
158
|
+ self.initialAttributes = attributes;
|
152
|
159
|
}
|
153
|
160
|
};
|
154
|
161
|
|
|
@@ -157,13 +164,55 @@ export default class SharedVideoManager {
|
157
|
164
|
};
|
158
|
165
|
}
|
159
|
166
|
|
|
167
|
+ /**
|
|
168
|
+ * Process attributes, whether player needs to be paused or seek.
|
|
169
|
+ * @param player the player to operate over
|
|
170
|
+ * @param attributes the attributes with the player state we want
|
|
171
|
+ * @param playerPaused current saved state for the player
|
|
172
|
+ */
|
|
173
|
+ processAttributes (player, attributes, playerPaused)
|
|
174
|
+ {
|
|
175
|
+ if(!attributes)
|
|
176
|
+ return;
|
|
177
|
+
|
|
178
|
+ if (attributes.state == 'playing') {
|
|
179
|
+
|
|
180
|
+ // check received time and current time
|
|
181
|
+ let currentPosition = player.getCurrentTime();
|
|
182
|
+ let diff = Math.abs(attributes.time - currentPosition);
|
|
183
|
+
|
|
184
|
+ // if we drift more than the interval for checking
|
|
185
|
+ // sync, the interval is in milliseconds
|
|
186
|
+ if(diff > updateInterval/1000) {
|
|
187
|
+ console.info("DDD Player seekTo:", attributes.time,
|
|
188
|
+ " current time is:", currentPosition, " diff:", diff);
|
|
189
|
+ player.seekTo(attributes.time);
|
|
190
|
+ }
|
|
191
|
+
|
|
192
|
+ // lets check the volume
|
|
193
|
+ if (attributes.volume !== undefined &&
|
|
194
|
+ player.getVolume() != attributes.volume) {
|
|
195
|
+ player.setVolume(attributes.volume);
|
|
196
|
+ console.info("Player change of volume:" + attributes.volume);
|
|
197
|
+ }
|
|
198
|
+
|
|
199
|
+ if(playerPaused)
|
|
200
|
+ player.playVideo();
|
|
201
|
+
|
|
202
|
+ } else if (attributes.state == 'pause') {
|
|
203
|
+ // if its not paused, pause it
|
|
204
|
+ player.pauseVideo();
|
|
205
|
+ }
|
|
206
|
+ }
|
|
207
|
+
|
160
|
208
|
/**
|
161
|
209
|
* Checks current state of the player and fire an event with the values.
|
162
|
210
|
*/
|
163
|
211
|
updateCheck(sendPauseEvent)
|
164
|
212
|
{
|
165
|
213
|
// ignore update checks if we are not the owner of the video
|
166
|
|
- if(!APP.conference.isLocalId(this.from))
|
|
214
|
+ // or there is still no player defined
|
|
215
|
+ if(!APP.conference.isLocalId(this.from) || !this.player)
|
167
|
216
|
return;
|
168
|
217
|
|
169
|
218
|
let state = this.player.getPlayerState();
|
|
@@ -195,54 +244,15 @@ export default class SharedVideoManager {
|
195
|
244
|
return;
|
196
|
245
|
}
|
197
|
246
|
|
198
|
|
- if (attributes.state == 'playing') {
|
199
|
|
-
|
200
|
|
- if(!this.isSharedVideoShown) {
|
201
|
|
- this.showSharedVideo(id, url, attributes);
|
202
|
|
- return;
|
203
|
|
- }
|
204
|
|
-
|
205
|
|
- // ocasionally we get this.player.getCurrentTime is not a function
|
206
|
|
- // it seems its that player hasn't really loaded
|
207
|
|
- if(!this.player || !this.player.getCurrentTime
|
208
|
|
- || !this.player.pauseVideo
|
209
|
|
- || !this.player.playVideo
|
210
|
|
- || !this.player.getVolume
|
211
|
|
- || !this.player.seekTo
|
212
|
|
- || !this.player.getVolume)
|
213
|
|
- return;
|
214
|
|
-
|
215
|
|
- // check received time and current time
|
216
|
|
- let currentPosition = this.player.getCurrentTime();
|
217
|
|
- let diff = Math.abs(attributes.time - currentPosition);
|
218
|
|
-
|
219
|
|
- // if we drift more than two times of the interval for checking
|
220
|
|
- // sync, the interval is in milliseconds
|
221
|
|
- if(diff > this.updateInterval*2/1000) {
|
222
|
|
- console.log("Player seekTo:", attributes.time,
|
223
|
|
- " current time is:", currentPosition, " diff:", diff);
|
224
|
|
- this.player.seekTo(attributes.time);
|
225
|
|
- }
|
226
|
|
-
|
227
|
|
- // lets check the volume
|
228
|
|
- if (attributes.volume !== undefined &&
|
229
|
|
- this.player.getVolume() != attributes.volume) {
|
230
|
|
- this.player.setVolume(attributes.volume);
|
231
|
|
- console.log("Player change of volume:" + attributes.volume);
|
232
|
|
- }
|
|
247
|
+ if(!this.isSharedVideoShown) {
|
|
248
|
+ this.showSharedVideo(id, url, attributes);
|
|
249
|
+ return;
|
|
250
|
+ }
|
233
|
251
|
|
234
|
|
- if(this.playerPaused)
|
235
|
|
- this.player.playVideo();
|
236
|
|
- } else if (attributes.state == 'pause') {
|
237
|
|
- // if its not paused, pause it
|
238
|
|
- if(this.isSharedVideoShown) {
|
239
|
|
- this.player.pauseVideo();
|
240
|
|
- }
|
241
|
|
- else {
|
242
|
|
- // if not shown show it, passing attributes so it can
|
243
|
|
- // be shown paused
|
244
|
|
- this.showSharedVideo(id, url, attributes);
|
245
|
|
- }
|
|
252
|
+ if(!this.player)
|
|
253
|
+ this.initialAttributes = attributes;
|
|
254
|
+ else {
|
|
255
|
+ this.processAttributes(this.player, attributes, this.playerPaused);
|
246
|
256
|
}
|
247
|
257
|
}
|
248
|
258
|
|
|
@@ -251,9 +261,8 @@ export default class SharedVideoManager {
|
251
|
261
|
* shared video is the one in the id (called when user
|
252
|
262
|
* left and we want to remove video if the user sharing it left).
|
253
|
263
|
* @param id the id of the sender of the command
|
254
|
|
- * @param attributes
|
255
|
264
|
*/
|
256
|
|
- stopSharedVideo (id, attributes) {
|
|
265
|
+ stopSharedVideo (id) {
|
257
|
266
|
if (!this.isSharedVideoShown)
|
258
|
267
|
return;
|
259
|
268
|
|