streamsDone method
Implementation
streamsDone(int handleId, RTCSessionDescription jsep, Map media, callbacks,
MediaStream stream) async {
Plugin pluginHandle = this.pluginHandles[handleId.toString()];
if (pluginHandle == null) {
Janus.warn("Invalid handle");
callbacks.error("Invalid handle");
return;
}
Janus.debug("streamsDone:" + stream.toString());
if (stream != null) {
Janus.debug(" -- Audio tracks:" + stream.getAudioTracks().toString());
Janus.debug(" -- Video tracks:" + stream.getVideoTracks().toString());
}
// We're now capturing the new stream: check if we're updating or if it's a new thing
bool addTracks = false;
if (pluginHandle.myStream == null ||
!media['update'] ||
pluginHandle.streamExternal) {
pluginHandle.myStream = stream;
addTracks = true;
} else {
// We only need to update the existing stream
if (((!media['update'] && isAudioSendEnabled(media)) ||
(media['update'] &&
(media['addAudio'] || media['replaceAudio']))) &&
stream.getAudioTracks() != null &&
stream.getAudioTracks().length > 0) {
pluginHandle.myStream.addTrack(stream.getAudioTracks()[0]);
if (Janus.unifiedPlan) {
// Use Transceivers
Janus.log((media['replaceAudio'] ? "Replacing" : "Adding") +
" audio track:" +
stream.getAudioTracks()[0].toString());
Map<String, dynamic> audioTransceiver;
// FIX ME
// List transceivers = pc.getTransceivers();
List transceivers = [];
if (transceivers != null && transceivers.length > 0) {
for (var t in transceivers) {
// TODO sender is MediaStreamTrack
if ((t['sender'] &&
t['sender'].track &&
t['sender'].track.kind == "audio") ||
(t['receiver'] &&
t['receiver'].track &&
t['receiver'].track.kind == "audio")) {
audioTransceiver = t;
break;
}
}
}
if (audioTransceiver != null && audioTransceiver['sender'] != null) {
// Todo implement replaceTrack
audioTransceiver['sender'].replaceTrack(stream.getAudioTracks()[0]);
} else {
// FIX ME
// pc.addTrack(stream.getAudioTracks()[0], stream);
pluginHandle.pc.addStream(stream);
}
} else {
Janus.log((media['replaceAudio'] ? "Replacing" : "Adding") +
" audio track:" +
stream.getAudioTracks()[0].toString());
// FIX ME
// pc.addTrack(stream.getAudioTracks()[0], stream);
pluginHandle.pc.addStream(stream);
}
}
if (((!media['update'] && isVideoSendEnabled(media)) ||
(media['update'] &&
(media['addVideo'] || media['replaceVideo']))) &&
stream.getVideoTracks() != null &&
stream.getVideoTracks().length > 0) {
pluginHandle.myStream.addTrack(stream.getVideoTracks()[0]);
if (Janus.unifiedPlan) {
// Use Transceivers
Janus.log((media['replaceVideo'] ? "Replacing" : "Adding") +
" video track:" +
stream.getVideoTracks()[0].toString());
Map<String, dynamic> videoTransceiver;
// List transceivers = pc.getTransceivers();
List transceivers = [];
if (transceivers != null && transceivers.length > 0) {
for (var t in transceivers) {
// TODO sender is MediaStreamTrack
if ((t['sender'] &&
t['sender'].track &&
t['sender'].track.kind == "video") ||
(t['receiver'] &&
t['receiver'].track &&
t['receiver'].track.kind == "video")) {
videoTransceiver = t;
break;
}
}
}
if (videoTransceiver != null && videoTransceiver['sender'] != null) {
// Todo implement replaceTrack
videoTransceiver['sender'].replaceTrack(stream.getVideoTracks()[0]);
} else {
// FIX ME
// pc.addTrack(stream.getVideoTracks()[0], stream);
pluginHandle.pc.addStream(stream);
}
} else {
Janus.log((media['replaceVideo'] ? "Replacing" : "Adding") +
" video track:" +
stream.getVideoTracks()[0].toString());
// FIX ME
// pc.addTrack(stream.getVideoTracks()[0], stream);
pluginHandle.pc.addStream(stream);
}
}
}
// If we still need to create a PeerConnection, let's do that
if (pluginHandle.pc == null) {
Map<String, dynamic> pcConfig = {"iceServers": this.iceServers};
if (this.iceTransportPolicy != null)
pcConfig["iceTransportPolicy"] = this.iceTransportPolicy;
if (this.bundlePolicy != null)
pcConfig["bundlePolicy"] = this.bundlePolicy;
if (Janus.webRTCAdapter['browserDetails']['browser'] == "chrome") {
// For Chrome versions before 72, we force a plan-b semantic, and unified-plan otherwise
pcConfig["sdpSemantics"] =
(Janus.webRTCAdapter['browserDetails']['version'] < 72)
? "plan-b"
: "unified-plan";
}
Map<String, dynamic> pcConstraints = {
"mandatory": {},
"optional": [
{"DtlsSrtpKeyAgreement": true}
]
};
if (this.ipv6Support) {
pcConstraints['optional'].add({"googIPv6": true});
}
// Any custom constraint to add?
if (callbacks.rtcConstraints != null) {
Janus.debug("Adding custom PeerConnection constraints:" +
callbacks.rtcConstraints.toString()); // FIX ME
for (var i in callbacks.rtcConstraints) {
pcConstraints['optional'].add(callbacks.rtcConstraints[i]);
}
}
if (Janus.webRTCAdapter['browserDetails']['browser'] == "edge") {
// This is Edge, enable BUNDLE explicitly
pcConfig['bundlePolicy'] = "max-bundle";
}
Janus.log("Creating PeerConnection");
Janus.debug(pcConstraints.toString());
Janus.debug(pcConfig.toString());
// From webrtc
pluginHandle.pc = await createPeerConnection(pcConfig, pcConstraints);
Janus.debug("Peer Connection is ready");
Janus.debug(pluginHandle.pc.toString());
// FIXME
// pluginHandle.pc.getStats().then((List<StatsReport> stats) {
// if (stats != null) {
// Janus.log(
// "PC Stats: " + stats[1].type + stats[1].values.toString());
// pluginHandle.volume = {};
// pluginHandle.bitrate['value'] = "0 kbits/sec";
// }
// }).catchError((error, StackTrace stackTrace) {
// Janus.error(error.toString());
// });
Janus.log("Preparing local SDP and gathering candidates (trickle=" +
pluginHandle.trickle.toString() +
")");
pluginHandle.pc.onIceConnectionState = (RTCIceConnectionState state) {
if (pluginHandle.pc != null) pluginHandle.iceState(state);
};
pluginHandle.pc.onIceCandidate = (RTCIceCandidate candidate) {
if (candidate == null ||
(Janus.webRTCAdapter['browserDetails']['browser'] == 'edge' &&
candidate.candidate.indexOf('endOfCandidates') > 0)) {
Janus.log("End of candidates.");
pluginHandle.iceDone = true;
Janus.log(pluginHandle.trickle);
if (pluginHandle.trickle == true) {
// Notify end of candidates
sendTrickleCandidate(handleId, {"completed": true});
} else {
// No trickle, time to send the complete SDP (including all candidates)
sendSDP(handleId, callbacks);
}
} else {
// JSON.stringify doesn't work on some WebRTC objects anymore
// See https://code.google.com/p/chromium/issues/detail?id=467366
// RTCIceCandidate candidate = RTCIceCandidate(iceCandidate.candidate,
// iceCandidate.sdpMid, iceCandidate.sdpMlineIndex);
if (pluginHandle.trickle == true) {
// Send candidate
sendTrickleCandidate(handleId, candidate.toMap());
Janus.debug(candidate.toMap());
}
}
};
pluginHandle.pc.onAddStream = (MediaStream stream) {
Janus.log("Handling Remote Stream");
Janus.debug(stream);
if (stream == null) return;
pluginHandle.remoteStream = stream;
pluginHandle.onRemoteStream(stream);
};
pluginHandle.pc.onRemoveStream = (MediaStream stream) {
Janus.log('onRemoveStream event call');
Janus.log(stream.toString());
};
pluginHandle.pc.onAddTrack =
(MediaStream stream, MediaStreamTrack track) {
Janus.log("Handling Remote Track");
Janus.debug(stream);
if (stream == null) return;
pluginHandle.remoteStream = stream;
pluginHandle.onRemoteStream(stream);
// FIX ME no equivalent call exists in flutter_webrtc
// if (event.track.onended) return;
// Janus.log("Adding onended callback to track:" + event.track);
// event.track.onended = (ev) {
// Janus.log("Remote track muted/removed:" + ev);
// if (pluginHandle.remoteStream) {
// pluginHandle.remoteStream.removeTrack(ev.target);
// pluginHandle.onremotestream(pluginHandle.remoteStream);
// }
// };
// FIX ME no equivalent call exists in flutter_webrtc
// event.track.onmute = event.track.onended;
// event.track.onunmute = (ev) {
// Janus.log("Remote track flowing again:" + ev);
// try {
// pluginHandle.remoteStream.addTrack(ev.target);
// pluginHandle.onremotestream(pluginHandle.remoteStream);
// } catch (e) {
// Janus.error(e);
// }
// ;
// };
};
// TODO connect addTrack
if (addTracks && stream != null) {
// var simulcast2 = (callbacks.simulcast2 == true);
// FIX ME: janus.js find out all the track from the stream and then add to the PC
// There is no equivalnet call in flutter_webrtc. We will add the stream to PC
pluginHandle.pc.addStream(stream).then((void v) {
Janus.log("Stream added to PC");
}).catchError((error, StackTrace stackTrace) {
Janus.log(stackTrace);
Janus.error(error.toString());
});
// // Get a list of audio and video tracks
// List<MediaStreamTrack> tracks =
// stream.getAudioTracks() + stream.getVideoTracks();
// tracks.forEach((MediaStreamTrack track) {
// Janus.log('Adding local track:' + track.toString());
// if (!simulcast2) {
// Janus.log('here i am');
// pluginHandle.pc.addTrack(track, stream);
// } else {
// if (track.kind == "audio") {
// pluginHandle.pc.addTrack(track, stream);
// } else {
// Janus.log(
// 'Enabling rid-based simulcasting:' + track.toString());
// var maxBitrates =
// getMaxBitrates(callbacks.simulcastMaxBitrates);
// pc.addTransceiver(track, {
// 'direction': "sendrecv",
// 'streams': [stream],
// 'sendEncodings': [
// {
// 'rid': "h",
// 'active': true,
// 'maxBitrate': maxBitrates['high']
// },
// {
// 'rid': "m",
// 'active': true,
// 'maxBitrate': maxBitrates['medium'],
// 'scaleResolutionDownBy': 2
// },
// {
// 'rid': "l",
// 'active': true,
// 'maxBitrate': maxBitrates['low'],
// 'scaleResolutionDownBy': 4
// }
// ]
// });
// }
// }
// });
}
// Any data channel to create?
if (isDataEnabled(media) &&
pluginHandle.dataChannels[Janus.dataChanDefaultLabel] == null) {
Janus.log("Creating data channel");
createDataChannel(handleId, Janus.dataChanDefaultLabel, null, null);
Janus.log('failing here');
pluginHandle.pc.onDataChannel = (var channel) {
Janus.log(
"Data channel created by Janus:" + channel.toString()); // FIX ME
createDataChannel(handleId, "label", channel, null);
};
}
// If there's a new local stream, let's notify the application
if (pluginHandle.myStream != null) {
pluginHandle.onLocalStream(pluginHandle.myStream);
}
// Create offer/answer now
if (jsep == null) {
createOffer(handleId, media, callbacks);
} else {
pluginHandle.pc.setRemoteDescription(jsep).then((void v) {
Janus.log("Remote description accepted!");
pluginHandle.remoteSdp = jsep.sdp;
// Any trickle candidate we cached?
if (pluginHandle.candidates != null &&
pluginHandle.candidates.length > 0) {
for (var i = 0; i < pluginHandle.candidates.length; i++) {
RTCIceCandidate candidate = pluginHandle.candidates[i];
Janus.debug("Adding remote candidate:" + candidate.toString());
if (candidate == null) {
// end-of-candidates
pluginHandle.pc.addCandidate(Janus.endOfCandidates);
} else {
// New candidate
pluginHandle.pc.addCandidate(candidate);
}
}
pluginHandle.candidates = [];
}
// Create the answer now
createAnswer(handleId, media, callbacks, null);
}).catchError((error, StackTrace stackTrade) {
callbacks.error(error);
});
}
}
}