generated from AgoraIO-Community/group-video-chat
-
Notifications
You must be signed in to change notification settings - Fork 0
/
agora-interface.js
311 lines (281 loc) · 11.9 KB
/
agora-interface.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
/*
* JS Interface for Agora.io SDK
*/
// video profile settings
var cameraVideoProfile = '480p_4'; // 640 × 480 @ 30fps & 750kbs
var screenVideoProfile = '480p_2'; // 640 × 480 @ 30fps
// create client instances for camera (client) and screen share (screenClient)
var client = AgoraRTC.createClient({mode: 'rtc', codec: 'vp8'});
var screenClient;
// stream references (keep track of active streams)
var remoteStreams = {}; // remote streams obj struct [id : stream]
var localStreams = {
camera: {
id: "",
stream: {}
},
screen: {
id: "",
stream: {}
}
};
AgoraRTC.Logger.enableLogUpload(); // auto upload logs
var mainStreamId; // reference to main stream
var screenShareActive = false; // flag for screen share
function initClientAndJoinChannel(agoraAppId, token, channelName, uid) {
// init Agora SDK
client.init(agoraAppId, function () {
console.log("AgoraRTC client initialized");
joinChannel(channelName, uid, token); // join channel upon successfull init
}, function (err) {
console.log("[ERROR] : AgoraRTC client init failed", err);
});
}
client.on('stream-published', function (evt) {
console.log("Publish local stream successfully");
});
// connect remote streams
client.on('stream-added', function (evt) {
var stream = evt.stream;
var streamId = stream.getId();
console.log("new stream added: " + streamId);
// Check if the stream is local
if (streamId != localStreams.screen.id) {
console.log('subscribe to remote stream:' + streamId);
// Subscribe to the stream.
client.subscribe(stream, function (err) {
console.log("[ERROR] : subscribe stream failed", err);
});
}
});
client.on('stream-subscribed', function (evt) {
var remoteStream = evt.stream;
var remoteId = remoteStream.getId();
remoteStreams[remoteId] = remoteStream;
console.log("Subscribe remote stream successfully: " + remoteId);
if( $('#full-screen-video').is(':empty') ) {
mainStreamId = remoteId;
remoteStream.play('full-screen-video');
$('#main-stats-btn').show();
$('#main-stream-stats-btn').show();
} else if (remoteId == 49024) {
// move the current main stream to miniview
remoteStreams[mainStreamId].stop(); // stop the main video stream playback
client.setRemoteVideoStreamType(remoteStreams[mainStreamId], 1); // subscribe to the low stream
addRemoteStreamMiniView(remoteStreams[mainStreamId]); // send the main video stream to a container
// set the screen-share as the main
mainStreamId = remoteId;
remoteStream.play('full-screen-video');s
} else {
client.setRemoteVideoStreamType(remoteStream, 1); // subscribe to the low stream
addRemoteStreamMiniView(remoteStream);
}
});
// remove the remote-container when a user leaves the channel
client.on("peer-leave", function(evt) {
var streamId = evt.stream.getId(); // the the stream id
if(remoteStreams[streamId] != undefined) {
remoteStreams[streamId].stop(); // stop playing the feed
delete remoteStreams[streamId]; // remove stream from list
if (streamId == mainStreamId) {
var streamIds = Object.keys(remoteStreams);
var randomId = streamIds[Math.floor(Math.random()*streamIds.length)]; // select from the remaining streams
remoteStreams[randomId].stop(); // stop the stream's existing playback
var remoteContainerID = '#' + randomId + '_container';
$(remoteContainerID).empty().remove(); // remove the stream's miniView container
remoteStreams[randomId].play('full-screen-video'); // play the random stream as the main stream
mainStreamId = randomId; // set the new main remote stream
} else {
var remoteContainerID = '#' + streamId + '_container';
$(remoteContainerID).empty().remove(); //
}
}
});
// show mute icon whenever a remote has muted their mic
client.on("mute-audio", function (evt) {
toggleVisibility('#' + evt.uid + '_mute', true);
});
client.on("unmute-audio", function (evt) {
toggleVisibility('#' + evt.uid + '_mute', false);
});
// show user icon whenever a remote has disabled their video
client.on("mute-video", function (evt) {
var remoteId = evt.uid;
// if the main user stops their video select a random user from the list
if (remoteId != mainStreamId) {
// if not the main vidiel then show the user icon
toggleVisibility('#' + remoteId + '_no-video', true);
}
});
client.on("unmute-video", function (evt) {
toggleVisibility('#' + evt.uid + '_no-video', false);
});
// join a channel
function joinChannel(channelName, uid, token) {
client.join(token, channelName, uid, function(uid) {
console.log("User " + uid + " join channel successfully");
createCameraStream(uid);
localStreams.camera.id = uid; // keep track of the stream uid
}, function(err) {
console.log("[ERROR] : join channel failed", err);
});
}
// video streams for channel
function createCameraStream(uid) {
var localStream = AgoraRTC.createStream({
streamID: uid,
audio: true,
video: true,
screen: false
});
localStream.setVideoProfile(cameraVideoProfile);
localStream.init(function() {
console.log("getUserMedia successfully");
// TODO: add check for other streams. play local stream full size if alone in channel
localStream.play('local-video'); // play the given stream within the local-video div
// publish local stream
client.publish(localStream, function (err) {
console.log("[ERROR] : publish local stream error: " + err);
});
enableUiControls(localStream); // move after testing
localStreams.camera.stream = localStream; // keep track of the camera stream for later
}, function (err) {
console.log("[ERROR] : getUserMedia failed", err);
});
}
// SCREEN SHARING
function initScreenShare(agoraAppId, channelName) {
screenClient = AgoraRTC.createClient({mode: 'rtc', codec: 'vp8'});
console.log("AgoraRTC screenClient initialized");
var uid = 49024; // hardcoded uid to make it easier to identify on remote clients
screenClient = AgoraRTC.createClient({mode: 'rtc', codec: 'vp8'});
screenClient.init(agoraAppId, function () {
console.log("AgoraRTC screenClient initialized");
}, function (err) {
console.log("[ERROR] : AgoraRTC screenClient init failed", err);
});
// keep track of the uid of the screen stream.
localStreams.screen.id = uid;
// Create the stream for screen sharing.
var screenStream = AgoraRTC.createStream({
streamID: uid,
audio: false, // Set the audio attribute as false to avoid any echo during the call.
video: false,
screen: true, // screen stream
screenAudio: true,
mediaSource: 'screen', // Firefox: 'screen', 'application', 'window' (select one)
});
// initialize the stream
// -- NOTE: this must happen directly from user interaction, if called by a promise or callback it will fail.
screenStream.init(function(){
console.log("getScreen successful");
localStreams.screen.stream = screenStream; // keep track of the screen stream
screenShareActive = true;
$("#screen-share-btn").prop("disabled",false); // enable button
screenClient.join(token, channelName, uid, function(uid) {
screenClient.publish(screenStream, function (err) {
console.log("[ERROR] : publish screen stream error: " + err);
});
}, function(err) {
console.log("[ERROR] : join channel as screen-share failed", err);
});
}, function (err) {
console.log("[ERROR] : getScreen failed", err);
localStreams.screen.id = ""; // reset screen stream id
localStreams.screen.stream = {}; // reset the screen stream
screenShareActive = false; // resest screenShare
toggleScreenShareBtn(); // toggle the button icon back
$("#screen-share-btn").prop("disabled",false); // enable button
});
var token = generateToken();
screenClient.on('stream-published', function (evt) {
console.log("Publish screen stream successfully");
if( $('#full-screen-video').is(':empty') ) {
$('#main-stats-btn').show();
$('#main-stream-stats-btn').show();
} else {
// move the current main stream to miniview
remoteStreams[mainStreamId].stop(); // stop the main video stream playback
client.setRemoteVideoStreamType(remoteStreams[mainStreamId], 1); // subscribe to the low stream
addRemoteStreamMiniView(remoteStreams[mainStreamId]); // send the main video stream to a container
}
mainStreamId = localStreams.screen.id;
localStreams.screen.stream.play('full-screen-video');
});
screenClient.on('stopScreenSharing', function (evt) {
console.log("screen sharing stopped", err);
});
}
function stopScreenShare() {
localStreams.screen.stream.disableVideo(); // disable the local video stream (will send a mute signal)
localStreams.screen.stream.stop(); // stop playing the local stream
localStreams.camera.stream.enableVideo(); // enable the camera feed
localStreams.camera.stream.play('local-video'); // play the camera within the full-screen-video div
$("#video-btn").prop("disabled",false);
screenClient.leave(function() {
screenShareActive = false;
console.log("screen client leaves channel");
$("#screen-share-btn").prop("disabled",false); // enable button
screenClient.unpublish(localStreams.screen.stream); // unpublish the screen client
localStreams.screen.stream.close(); // close the screen client stream
localStreams.screen.id = ""; // reset the screen id
localStreams.screen.stream = {}; // reset the stream obj
}, function(err) {
console.log("client leave failed ", err); //error handling
});
}
// REMOTE STREAMS UI
function addRemoteStreamMiniView(remoteStream){
var streamId = remoteStream.getId();
// append the remote stream template to #remote-streams
$('#remote-streams').append(
$('<div/>', {'id': streamId + '_container', 'class': 'remote-stream-container col'}).append(
$('<div/>', {'id': streamId + '_mute', 'class': 'mute-overlay'}).append(
$('<i/>', {'class': 'fas fa-microphone-slash'})
),
$('<div/>', {'id': streamId + '_no-video', 'class': 'no-video-overlay text-center'}).append(
$('<i/>', {'class': 'fas fa-user'})
),
$('<div/>', {'id': 'agora_remote_' + streamId, 'class': 'remote-video'})
)
);
remoteStream.play('agora_remote_' + streamId);
var containerId = '#' + streamId + '_container';
$(containerId).dblclick(function() {
// play selected container as full screen - swap out current full screen stream
remoteStreams[mainStreamId].stop(); // stop the main video stream playback
addRemoteStreamMiniView(remoteStreams[mainStreamId]); // send the main video stream to a container
$(containerId).empty().remove(); // remove the stream's miniView container
remoteStreams[streamId].stop() // stop the container's video stream playback
remoteStreams[streamId].play('full-screen-video'); // play the remote stream as the full screen video
mainStreamId = streamId; // set the container stream id as the new main stream id
});
}
function leaveChannel() {
if(screenShareActive) {
stopScreenShare();
}
client.leave(function() {
console.log("client leaves channel");
localStreams.camera.stream.stop() // stop the camera stream playback
client.unpublish(localStreams.camera.stream); // unpublish the camera stream
localStreams.camera.stream.close(); // clean up and close the camera stream
$("#remote-streams").empty() // clean up the remote feeds
//disable the UI elements
$("#mic-btn").prop("disabled", true);
$("#video-btn").prop("disabled", true);
$("#screen-share-btn").prop("disabled", true);
$("#exit-btn").prop("disabled", true);
// hide the mute/no-video overlays
toggleVisibility("#mute-overlay", false);
toggleVisibility("#no-local-video", false);
// show the modal overlay to join
$("#modalForm").modal("show");
}, function(err) {
console.log("client leave failed ", err); //error handling
});
}
// use tokens for added security
function generateToken() {
return null; // TODO: add a token generation
}