|
|
@@ -3,6 +3,7 @@
|
|
3
|
3
|
var logger = require("jitsi-meet-logger").getLogger(__filename);
|
|
4
|
4
|
var JingleSession = require("./JingleSession");
|
|
5
|
5
|
var TraceablePeerConnection = require("./TraceablePeerConnection");
|
|
|
6
|
+var MediaType = require("../../service/RTC/MediaType");
|
|
6
|
7
|
var SDPDiffer = require("./SDPDiffer");
|
|
7
|
8
|
var SDPUtil = require("./SDPUtil");
|
|
8
|
9
|
var SDP = require("./SDP");
|
|
|
@@ -113,29 +114,10 @@ JingleSessionPC.prototype.doInitialize = function () {
|
|
113
|
114
|
self.sendIceCandidate(candidate);
|
|
114
|
115
|
};
|
|
115
|
116
|
this.peerconnection.onaddstream = function (event) {
|
|
116
|
|
- if (event.stream.id !== 'default') {
|
|
117
|
|
- logger.log("REMOTE STREAM ADDED: ", event.stream , event.stream.id);
|
|
118
|
|
- self.remoteStreamAdded(event);
|
|
119
|
|
- } else {
|
|
120
|
|
- // This is a recvonly stream. Clients that implement Unified Plan,
|
|
121
|
|
- // such as Firefox use recvonly "streams/channels/tracks" for
|
|
122
|
|
- // receiving remote stream/tracks, as opposed to Plan B where there
|
|
123
|
|
- // are only 3 channels: audio, video and data.
|
|
124
|
|
- logger.log("RECVONLY REMOTE STREAM IGNORED: " + event.stream + " - " + event.stream.id);
|
|
125
|
|
- }
|
|
|
117
|
+ self.remoteStreamAdded(event.stream);
|
|
126
|
118
|
};
|
|
127
|
119
|
this.peerconnection.onremovestream = function (event) {
|
|
128
|
|
- // Remove the stream from remoteStreams
|
|
129
|
|
- if (event.stream.id !== 'default') {
|
|
130
|
|
- logger.log("REMOTE STREAM REMOVED: ", event.stream , event.stream.id);
|
|
131
|
|
- self.remoteStreamRemoved(event);
|
|
132
|
|
- } else {
|
|
133
|
|
- // This is a recvonly stream. Clients that implement Unified Plan,
|
|
134
|
|
- // such as Firefox use recvonly "streams/channels/tracks" for
|
|
135
|
|
- // receiving remote stream/tracks, as opposed to Plan B where there
|
|
136
|
|
- // are only 3 channels: audio, video and data.
|
|
137
|
|
- logger.log("RECVONLY REMOTE STREAM IGNORED: " + event.stream + " - " + event.stream.id);
|
|
138
|
|
- }
|
|
|
120
|
+ self.remoteStreamRemoved(event.stream);
|
|
139
|
121
|
};
|
|
140
|
122
|
this.peerconnection.onsignalingstatechange = function (event) {
|
|
141
|
123
|
if (!(self && self.peerconnection)) return;
|
|
|
@@ -1184,58 +1166,138 @@ JingleSessionPC.onJingleFatalError = function (session, error)
|
|
1184
|
1166
|
this.room.eventEmitter.emit(XMPPEvents.JINGLE_FATAL_ERROR, session, error);
|
|
1185
|
1167
|
};
|
|
1186
|
1168
|
|
|
1187
|
|
-JingleSessionPC.prototype.remoteStreamAdded = function (data, times) {
|
|
|
1169
|
+/**
|
|
|
1170
|
+ * Called when new remote MediaStream is added to the PeerConnection.
|
|
|
1171
|
+ * @param stream the WebRTC MediaStream for remote participant
|
|
|
1172
|
+ */
|
|
|
1173
|
+JingleSessionPC.prototype.remoteStreamAdded = function (stream) {
|
|
1188
|
1174
|
var self = this;
|
|
1189
|
|
- var thessrc;
|
|
1190
|
|
- var streamId = RTC.getStreamID(data.stream);
|
|
|
1175
|
+ if (!RTC.isUserStream(stream)) {
|
|
|
1176
|
+ logger.info(
|
|
|
1177
|
+ "Ignored remote 'stream added' event for non-user stream", stream);
|
|
|
1178
|
+ return;
|
|
|
1179
|
+ }
|
|
|
1180
|
+ // Bind 'addtrack'/'removetrack' event handlers
|
|
|
1181
|
+ if (RTCBrowserType.isChrome()) {
|
|
|
1182
|
+ stream.onaddtrack = function (event) {
|
|
|
1183
|
+ self.remoteTrackAdded(event.target, event.track);
|
|
|
1184
|
+ };
|
|
|
1185
|
+ stream.onremovetrack = function (event) {
|
|
|
1186
|
+ self.remoteTrackRemoved(event.target, event.track);
|
|
|
1187
|
+ };
|
|
|
1188
|
+ }
|
|
|
1189
|
+ // Call remoteTrackAdded for each track in the stream
|
|
|
1190
|
+ stream.getAudioTracks().forEach(function (track) {
|
|
|
1191
|
+ self.remoteTrackAdded(stream, track);
|
|
|
1192
|
+ });
|
|
|
1193
|
+ stream.getVideoTracks().forEach(function (track) {
|
|
|
1194
|
+ self.remoteTrackAdded(stream, track);
|
|
|
1195
|
+ });
|
|
|
1196
|
+};
|
|
|
1197
|
+
|
|
|
1198
|
+/**
|
|
|
1199
|
+ * Called on "track added" and "stream added" PeerConnection events(cause we
|
|
|
1200
|
+ * handle streams on per track basis). Does find the owner and the SSRC for
|
|
|
1201
|
+ * the track and passes that to ChatRoom for further processing.
|
|
|
1202
|
+ * @param stream WebRTC MediaStream instance which is the parent of the track
|
|
|
1203
|
+ * @param track the WebRTC MediaStreamTrack added for remote participant
|
|
|
1204
|
+ */
|
|
|
1205
|
+JingleSessionPC.prototype.remoteTrackAdded = function (stream, track) {
|
|
|
1206
|
+ logger.info("Remote track added", stream, track);
|
|
|
1207
|
+ var streamId = RTC.getStreamID(stream);
|
|
|
1208
|
+ var mediaType = track.kind;
|
|
|
1209
|
+
|
|
|
1210
|
+ // This is our event structure which will be passed by the ChatRoom as
|
|
|
1211
|
+ // XMPPEvents.REMOTE_TRACK_ADDED data
|
|
|
1212
|
+ var jitsiTrackAddedEvent = {
|
|
|
1213
|
+ stream: stream,
|
|
|
1214
|
+ track: track,
|
|
|
1215
|
+ mediaType: track.kind, /* 'audio' or 'video' */
|
|
|
1216
|
+ owner: undefined, /* to be determined below */
|
|
|
1217
|
+ muted: null /* will be set in the ChatRoom */
|
|
|
1218
|
+ };
|
|
1191
|
1219
|
|
|
1192
|
1220
|
// look up an associated JID for a stream id
|
|
1193
|
|
- if (!streamId) {
|
|
1194
|
|
- logger.error("No stream ID for", data.stream);
|
|
1195
|
|
- } else if (streamId && streamId.indexOf('mixedmslabel') === -1) {
|
|
1196
|
|
- // look only at a=ssrc: and _not_ at a=ssrc-group: lines
|
|
1197
|
|
-
|
|
1198
|
|
- var ssrclines = this.peerconnection.remoteDescription?
|
|
1199
|
|
- SDPUtil.find_lines(this.peerconnection.remoteDescription.sdp, 'a=ssrc:') : [];
|
|
1200
|
|
- ssrclines = ssrclines.filter(function (line) {
|
|
1201
|
|
- // NOTE(gp) previously we filtered on the mslabel, but that property
|
|
1202
|
|
- // is not always present.
|
|
1203
|
|
- // return line.indexOf('mslabel:' + data.stream.label) !== -1;
|
|
1204
|
|
-
|
|
1205
|
|
- if (RTCBrowserType.isTemasysPluginUsed()) {
|
|
1206
|
|
- return ((line.indexOf('mslabel:' + streamId) !== -1));
|
|
1207
|
|
- } else {
|
|
1208
|
|
- return ((line.indexOf('msid:' + streamId) !== -1));
|
|
1209
|
|
- }
|
|
1210
|
|
- });
|
|
1211
|
|
- if (ssrclines.length) {
|
|
1212
|
|
- thessrc = ssrclines[0].substring(7).split(' ')[0];
|
|
|
1221
|
+ if (!mediaType) {
|
|
|
1222
|
+ logger.error("MediaType undefined", track);
|
|
|
1223
|
+ return;
|
|
|
1224
|
+ }
|
|
1213
|
1225
|
|
|
1214
|
|
- if (!self.ssrcOwners[thessrc]) {
|
|
1215
|
|
- logger.error("No SSRC owner known for: " + thessrc);
|
|
1216
|
|
- return;
|
|
1217
|
|
- }
|
|
1218
|
|
- data.peerjid = self.ssrcOwners[thessrc];
|
|
1219
|
|
- logger.log('associated jid', self.ssrcOwners[thessrc]);
|
|
|
1226
|
+ var remoteSDP = new SDP(this.peerconnection.remoteDescription.sdp);
|
|
|
1227
|
+ var medialines = remoteSDP.media.filter(function (mediaLines){
|
|
|
1228
|
+ return mediaLines.startsWith("m=" + mediaType);
|
|
|
1229
|
+ });
|
|
|
1230
|
+
|
|
|
1231
|
+ if (!medialines.length) {
|
|
|
1232
|
+ logger.error("No media for type " + mediaType + " found in remote SDP");
|
|
|
1233
|
+ return;
|
|
|
1234
|
+ }
|
|
|
1235
|
+
|
|
|
1236
|
+ var ssrclines = SDPUtil.find_lines(medialines[0], 'a=ssrc:');
|
|
|
1237
|
+ ssrclines = ssrclines.filter(function (line) {
|
|
|
1238
|
+ if (RTCBrowserType.isTemasysPluginUsed()) {
|
|
|
1239
|
+ return ((line.indexOf('mslabel:' + streamId) !== -1));
|
|
1220
|
1240
|
} else {
|
|
1221
|
|
- logger.error("No SSRC lines for ", streamId);
|
|
|
1241
|
+ return ((line.indexOf('msid:' + streamId) !== -1));
|
|
1222
|
1242
|
}
|
|
|
1243
|
+ });
|
|
|
1244
|
+
|
|
|
1245
|
+ var thessrc;
|
|
|
1246
|
+ if (ssrclines.length) {
|
|
|
1247
|
+ thessrc = ssrclines[0].substring(7).split(' ')[0];
|
|
|
1248
|
+ if (!this.ssrcOwners[thessrc]) {
|
|
|
1249
|
+ logger.error("No SSRC owner known for: " + thessrc);
|
|
|
1250
|
+ return;
|
|
|
1251
|
+ }
|
|
|
1252
|
+ jitsiTrackAddedEvent.owner = this.ssrcOwners[thessrc];
|
|
|
1253
|
+ logger.log('associated jid', this.ssrcOwners[thessrc], thessrc);
|
|
|
1254
|
+ } else {
|
|
|
1255
|
+ logger.error("No SSRC lines for ", streamId);
|
|
|
1256
|
+ return;
|
|
1223
|
1257
|
}
|
|
|
1258
|
+ jitsiTrackAddedEvent.ssrc = thessrc;
|
|
1224
|
1259
|
|
|
1225
|
|
- this.room.remoteStreamAdded(data, this.sid, thessrc);
|
|
|
1260
|
+ this.room.remoteTrackAdded(jitsiTrackAddedEvent);
|
|
1226
|
1261
|
};
|
|
1227
|
1262
|
|
|
1228
|
1263
|
/**
|
|
1229
|
1264
|
* Handles remote stream removal.
|
|
1230
|
|
- * @param event The event object associated with the removal.
|
|
|
1265
|
+ * @param stream the WebRTC MediaStream object which is being removed from the
|
|
|
1266
|
+ * PeerConnection
|
|
1231
|
1267
|
*/
|
|
1232
|
|
-JingleSessionPC.prototype.remoteStreamRemoved = function (event) {
|
|
1233
|
|
- var thessrc;
|
|
1234
|
|
- var streamId = RTC.getStreamID(event.stream);
|
|
|
1268
|
+JingleSessionPC.prototype.remoteStreamRemoved = function (stream) {
|
|
|
1269
|
+ var self = this;
|
|
|
1270
|
+ if (!RTC.isUserStream(stream)) {
|
|
|
1271
|
+ logger.info(
|
|
|
1272
|
+ "Ignored remote 'stream removed' event for non-user stream", stream);
|
|
|
1273
|
+ return;
|
|
|
1274
|
+ }
|
|
|
1275
|
+ // Call remoteTrackRemoved for each track in the stream
|
|
|
1276
|
+ stream.getVideoTracks().forEach(function(track){
|
|
|
1277
|
+ self.remoteTrackRemoved(stream, track);
|
|
|
1278
|
+ });
|
|
|
1279
|
+ stream.getAudioTracks().forEach(function(track) {
|
|
|
1280
|
+ self.remoteTrackRemoved(stream, track);
|
|
|
1281
|
+ });
|
|
|
1282
|
+};
|
|
|
1283
|
+
|
|
|
1284
|
+/**
|
|
|
1285
|
+ * Handles remote media track removal.
|
|
|
1286
|
+ * @param stream WebRTC MediaStream instance which is the parent of the track
|
|
|
1287
|
+ * @param track the WebRTC MediaStreamTrack which has been removed from
|
|
|
1288
|
+ * the PeerConnection.
|
|
|
1289
|
+ */
|
|
|
1290
|
+JingleSessionPC.prototype.remoteTrackRemoved = function (stream, track) {
|
|
|
1291
|
+ logger.info("Remote track removed", stream, track);
|
|
|
1292
|
+ var streamId = RTC.getStreamID(stream);
|
|
|
1293
|
+ var trackId = track && track.id;
|
|
1235
|
1294
|
if (!streamId) {
|
|
1236
|
|
- logger.error("No stream ID for", event.stream);
|
|
1237
|
|
- } else if (streamId && streamId.indexOf('mixedmslabel') === -1) {
|
|
1238
|
|
- this.room.eventEmitter.emit(XMPPEvents.REMOTE_STREAM_REMOVED, streamId);
|
|
|
1295
|
+ logger.error("No stream ID for", stream);
|
|
|
1296
|
+ } else if (!trackId) {
|
|
|
1297
|
+ logger.error("No track ID for", track);
|
|
|
1298
|
+ } else {
|
|
|
1299
|
+ this.room.eventEmitter.emit(
|
|
|
1300
|
+ XMPPEvents.REMOTE_TRACK_REMOVED, streamId, trackId);
|
|
1239
|
1301
|
}
|
|
1240
|
1302
|
};
|
|
1241
|
1303
|
|