init method
Implementation
Future<void> init() async {
_peerConnection = await createPeerConnection(_configuration.toMap());
if (_createDataChannel) {
RTCDataChannelInit dataChannelDict = RTCDataChannelInit()
..ordered = true
..maxRetransmits = 3
..protocol = "json";
_dataChannel = await _peerConnection.createDataChannel(SignalingClient.randomString(), dataChannelDict);
_peerConnection.onDataChannel = (event) {
event.onMessage = _dataChannelMessageReceived;
};
}
_addIceCandidate = (candidate) async {
if (candidate.clientId != _remoteClientId) {
// All ICE candidates received over signaling will be received via this callback.
// Ignore ICE candidates not directed for this PeerConnection (when multiple
// viewer participants are connecting to the same signaling channel).
return;
}
log('Received ICE candidate from ${candidate.clientId ?? 'remote'}');
log('ICE candidate: ${candidate.iceCandidate.toMap()}');
if (_inboundIceCandidateFilterFn(candidate.iceCandidate)) {
// Add the ICE candidate received from the client to the peer connection
await _peerConnection.addCandidate(candidate.iceCandidate);
} else {
log('Candidate rejected through filter. Not adding candidate from ${candidate.clientId ?? 'remote'}.');
}
};
_signalingClient.onIceCandidate.listen(_addIceCandidate);
_peerConnection.onIceCandidate = (event) async {
RTCIceCandidate? candidate = event;
if (candidate != null && candidate.candidate != null) {
log('Generated ICE candidate for ${_remoteClientId ?? 'remote'}');
log('ICE candidate: $candidate');
// When trickle ICE is enabled, send the ICE candidates as they are generated.
if (_trickleICE) {
if (_outboundIceCandidateFilterFn(candidate)) {
log('Sending ICE candidate to ${_remoteClientId ?? 'remote'}');
_signalingClient.sendIceCandidate(candidate, recipientClientId: _remoteClientId);
} else {
log('Not sending ICE candidate to ${_remoteClientId ?? 'remote'}');
}
}
} else if (candidate == null) {
// Firefox special case: candidate with null candidate field
} else {
log('All ICE candidates have been generated for ${_remoteClientId ?? 'remote'}');
// When trickle ICE is disabled, send the answer now that all the ICE candidates have been generated.
if (!_trickleICE) {
log('Sending SDP answer to ${_remoteClientId ?? 'remote'}');
final correlationId = SignalingClient.randomString();
final local = await _peerConnection.getLocalDescription() as RTCSessionDescription;
log('SDP answer: ${local.toMap()} correlationId: $correlationId');
_signalingClient.sendSdpAnswer(local, recipientClientId: _remoteClientId, correlationId: correlationId);
}
}
};
// We receive this event when the remote peer adds a new track to the PeerConnection
_peerConnection.onTrack = (event) {
log(
'Received ${event.track.kind ?? 'unknown'} track from ${_remoteClientId ?? 'remote'} '
'in mediaStream: ${event.streams.first.id ?? '[Error retrieving stream ID]'} with track id: ${event.track.id}',
);
_onMediaStreamsUpdated(event.streams);
};
// If there's no video/audio, this._mediaStream will be null. So, we should skip adding the tracks from it.
if (_mediaStream != null) {
_mediaStream.getTracks().forEach((track) {
_peerConnection.addTrack(track, _mediaStream);
});
}
await _peerConnection.setRemoteDescription(_offer);
for (final transceiver in await _peerConnection.getTransceivers()) {
if (transceiver.receiver.track?.kind == 'video' && videoCodecs.length > 0) {
transceiver.setCodecPreferences(videoCodecs);
} else if (transceiver.receiver.track?.kind == 'audio' && audioCodecs.length > 0) {
transceiver.setCodecPreferences(audioCodecs);
}
}
// Create an SDP answer to send back to the client
log('Creating SDP answer for ${_remoteClientId ?? 'remote'}');
final answer = await _peerConnection.createAnswer({'offerToReceiveAudio': true, 'offerToReceiveVideo': true});
await _peerConnection.setLocalDescription(answer);
// When trickle ICE is enabled, send the answer now and then send ICE candidates as they are generated. Otherwise wait on the ICE candidates.
if (_trickleICE) {
log('Sending SDP answer to ${_remoteClientId ?? 'remote'}');
final correlationId = SignalingClient.randomString();
log('SDP answer: ${_peerConnection.getLocalDescription()} correlationId: $correlationId');
_signalingClient.sendSdpAnswer(
await _peerConnection.getLocalDescription() as RTCSessionDescription,
recipientClientId: _remoteClientId,
correlationId: correlationId,
);
}
log('Generating ICE candidates for ${_remoteClientId ?? 'remote'}');
}