signal & webrtc connections established

This commit is contained in:
David Zhao
2021-07-23 23:56:06 -07:00
parent 26981c1c8c
commit 0bd2679e94
8 changed files with 68 additions and 38 deletions
+1 -1
View File
@@ -1,8 +1,8 @@
library livekit_client;
export 'src/livekit.dart';
export 'src/errors.dart';
export 'src/room.dart';
export 'src/rtc_engine.dart';
export 'src/participant/participant.dart';
export 'src/participant/local_participant.dart';
export 'src/participant/remote_participant.dart';
+5 -5
View File
@@ -9,9 +9,11 @@ class RTCConfiguration {
iceServersMap.add(element.toMap());
});
return {
// only supports unified plan
'sdpSemantics': 'unified-plan',
if (iceCandidatePoolSize != null)
"iceCandidatePoolSize": iceCandidatePoolSize,
if (iceServersMap.isNotEmpty) "iceServers": iceServersMap,
"iceServers": iceServersMap,
if (iceTransportPolicy != null) "iceTransportPolicy": iceTransportPolicy,
};
}
@@ -27,10 +29,8 @@ class RTCIceServer {
Map<String, dynamic> toMap() {
return {
"urls": urls,
if (username != null)
"username": username,
if (credential != null)
"credential": credential,
if (username != null) "username": username,
if (credential != null) "credential": credential,
};
}
}
+9
View File
@@ -0,0 +1,9 @@
import 'room.dart';
class LiveKitClient {
// TODO: take in connect options
static Future<Room> connect(String url, String token) {
var room = Room();
return room.connect(url, token);
}
}
@@ -34,6 +34,7 @@ class LocalParticipant extends Participant {
return stream;
}
/// publish an audio track to the room
Future<TrackPublication> publishAudioTrack(LocalAudioTrack track) async {
if (audioTracks.values.any(
(element) => element.track?.mediaTrack.id == track.mediaTrack.id)) {
@@ -59,6 +60,7 @@ class LocalParticipant extends Participant {
return pub;
}
/// publish a video track to the room
Future<TrackPublication> publishVideoTrack(LocalVideoTrack track) async {
if (audioTracks.values.any(
(element) => element.track?.mediaTrack.id == track.mediaTrack.id)) {
+7 -7
View File
@@ -73,8 +73,8 @@ class Room with ParticipantDelegate {
Completer<Room>? _connectCompleter;
Room(SignalClient client, RTCConfiguration? rtcConfig)
: _engine = new RTCEngine(client, rtcConfig) {
Room([RTCConfiguration? rtcConfig])
: _engine = new RTCEngine(SignalClient(), rtcConfig) {
_engine.onTrack = _onTrackAdded;
_engine.onICEConnected = _handleICEConnected;
_engine.onDisconnected = _handleDisconnect;
@@ -85,7 +85,7 @@ class Room with ParticipantDelegate {
// TODO: handle reconnecting & reconnected events
}
Future<Room> connect(String url, String token, JoinOptions? opts) async {
Future<Room> connect(String url, String token, [JoinOptions? opts]) async {
var completer = new Completer<Room>();
_connectCompleter = completer;
@@ -109,10 +109,10 @@ class Room with ParticipantDelegate {
// room is not ready until ICE is connected. so we would return a completer for now
// if it times out, we'll fail the completer
Timer(Duration(seconds: 5), () {
_connectCompleter?.completeError(ConnectError());
_connectCompleter = null;
});
// Timer(Duration(seconds: 5), () {
// _connectCompleter?.completeError(ConnectError());
// _connectCompleter = null;
// });
return completer.future;
}
+24 -11
View File
@@ -64,6 +64,8 @@ class RTCEngine with SignalClientDelegate {
var completer = new Completer<JoinResponse>();
joinCompleter = completer;
client.join(url, token, opts);
// if it's not complete after 5 seconds, fail
new Timer(connectionTimeout, () {
joinCompleter?.completeError(new ConnectError());
@@ -116,7 +118,12 @@ class RTCEngine with SignalClientDelegate {
return;
}
var remoteDesc = await pub.pc.getRemoteDescription();
RTCSessionDescription? remoteDesc;
if (pub.pc.iceConnectionState != null) {
// when not initially connected, this crashes on iOS
remoteDesc = await pub.pc.getRemoteDescription();
}
// handle cases that we couldn't create a new offer due to a pending answer
// that's lost in transit
if (remoteDesc != null &&
@@ -151,8 +158,9 @@ class RTCEngine with SignalClientDelegate {
};
pubPC.onRenegotiationNeeded = () {
if (pubPC.iceConnectionState ==
RTCIceConnectionState.RTCIceConnectionStateNew) {
if (pubPC.iceConnectionState == null ||
pubPC.iceConnectionState ==
RTCIceConnectionState.RTCIceConnectionStateNew) {
return;
}
negotiate();
@@ -185,13 +193,16 @@ class RTCEngine with SignalClientDelegate {
};
// create data channels
var lossyInit = new RTCDataChannelInit();
lossyInit.ordered = true;
lossyInit.maxRetransmits = 1;
var lossyInit = new RTCDataChannelInit()
..maxRetransmits = 1
..ordered = true
..binaryType = 'binary';
lossyDC = await pubPC.createDataChannel(lossyDataChannel, lossyInit);
var reliableInit = new RTCDataChannelInit();
reliableInit.ordered = true;
var reliableInit = new RTCDataChannelInit()
..ordered = true
..maxRetransmits = 50
..binaryType = 'binary';
reliableDC =
await pubPC.createDataChannel(reliableDataChannel, reliableInit);
@@ -224,7 +235,7 @@ class RTCEngine with SignalClientDelegate {
//------------------ SignalClient Delegate methods -------------------------//
void onConnected(JoinResponse response) {
void onConnected(JoinResponse response) async {
// create peer connections
this.isClosed = false;
@@ -243,7 +254,7 @@ class RTCEngine with SignalClientDelegate {
rtcConfig.iceServers = iceServers;
}
_configurePeerConnections();
await _configurePeerConnections();
negotiate();
@@ -251,7 +262,9 @@ class RTCEngine with SignalClientDelegate {
joinCompleter = null;
}
void onClose(String? reason) {}
void onClose([String? reason]) {
// TODO: handle reconnect when signal interrupted
}
void onOffer(RTCSessionDescription sd) async {
var sub = subscriber;
+19 -13
View File
@@ -19,7 +19,7 @@ mixin SignalClientDelegate {
// initial connection established
void onConnected(JoinResponse response);
// websocket has closed
void onClose(String? reason);
void onClose([String? reason]);
// when a server offer is received
void onOffer(RTCSessionDescription sd);
// when an answer from server is received
@@ -37,19 +37,19 @@ mixin SignalClientDelegate {
}
class SignalClient {
SignalClientDelegate delegate;
SignalClientDelegate? delegate;
bool _connected = false;
WebSocketChannel? _ws;
SignalClient(this.delegate);
SignalClient();
bool get connected => this._connected;
join(String url, String token, JoinOptions options) {
join(String url, String token, JoinOptions? options) {
url += '/rtc';
var params = _paramsForToken(token);
if (options.autoSubscribe != null) {
if (options != null && options.autoSubscribe != null) {
params += '&auto_subscribe=${options.autoSubscribe! ? '1' : '0'}';
}
var uri = Uri.parse(url + params);
@@ -61,6 +61,7 @@ class SignalClient {
_ws = ws;
} catch (e) {
// failed before error handler is installed, fail immediately
_handleError(e);
}
}
@@ -164,30 +165,30 @@ class SignalClient {
case SignalResponse_Message.join:
if (!_connected) {
_connected = true;
delegate.onConnected(msg.join);
delegate?.onConnected(msg.join);
}
break;
case SignalResponse_Message.answer:
delegate.onAnswer(toRTCSessionDescription(msg.answer));
delegate?.onAnswer(toRTCSessionDescription(msg.answer));
break;
case SignalResponse_Message.offer:
delegate.onOffer(toRTCSessionDescription(msg.offer));
delegate?.onOffer(toRTCSessionDescription(msg.offer));
break;
case SignalResponse_Message.trickle:
delegate.onTrickle(
delegate?.onTrickle(
toRTCIceCandidate(msg.trickle.candidateInit), msg.trickle.target);
break;
case SignalResponse_Message.update:
delegate.onParticipantUpdate(msg.update.participants);
delegate?.onParticipantUpdate(msg.update.participants);
break;
case SignalResponse_Message.trackPublished:
delegate.onLocalTrackPublished(msg.trackPublished);
delegate?.onLocalTrackPublished(msg.trackPublished);
break;
case SignalResponse_Message.speaker:
delegate.onActiveSpeakersChanged(msg.speaker.speakers);
delegate?.onActiveSpeakersChanged(msg.speaker.speakers);
break;
case SignalResponse_Message.leave:
delegate.onLeave(msg.leave);
delegate?.onLeave(msg.leave);
break;
default:
log('unsupported message: ' + jsonEncode(msg));
@@ -199,7 +200,12 @@ class SignalClient {
}
_handleDone() {
if (!_connected) {
return;
}
_ws = null;
_connected = false;
delegate?.onClose();
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
name: livekit_client_flutter
name: livekit_client
description: Flutter client for LiveKit
version: 0.0.1
homepage: https://livekit.io