diff --git a/lib/src/extensions.dart b/lib/src/extensions.dart index 4949cfa..0afc7c8 100644 --- a/lib/src/extensions.dart +++ b/lib/src/extensions.dart @@ -40,6 +40,7 @@ extension ProtocolVersionExt on ProtocolVersion { String toStringValue() => { ProtocolVersion.protocol2: '2', ProtocolVersion.protocol3: '3', + ProtocolVersion.protocol4: '4', }[this]!; } diff --git a/lib/src/participant/remote_participant.dart b/lib/src/participant/remote_participant.dart index 418572d..8ba718e 100644 --- a/lib/src/participant/remote_participant.dart +++ b/lib/src/participant/remote_participant.dart @@ -1,4 +1,6 @@ import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc; +import 'package:livekit_client/src/track/remote_audio_track.dart'; +import 'package:livekit_client/src/track/remote_video_track.dart'; import 'package:meta/meta.dart'; import '../constants.dart'; @@ -8,10 +10,8 @@ import '../logger.dart'; import '../managers/event.dart'; import '../proto/livekit_models.pb.dart' as lk_models; import '../signal_client.dart'; -import '../track/audio_track.dart'; import '../track/remote_track_publication.dart'; import '../track/track.dart'; -import '../track/video_track.dart'; import '../types.dart'; import 'participant.dart'; @@ -91,14 +91,14 @@ class RemoteParticipant extends Participant { final Track track; if (pub.kind == lk_models.TrackType.AUDIO) { // audio track - final audioTrack = AudioTrack(pub.name, mediaTrack, stream); - await audioTrack.start(); - track = audioTrack; + track = RemoteAudioTrack(pub.name, mediaTrack, stream); } else { // video track - track = VideoTrack(pub.name, mediaTrack, stream); + track = RemoteVideoTrack(pub.name, mediaTrack, stream); } + await track.start(); + pub.track = track; addTrackPublication(pub); diff --git a/lib/src/rtc_engine.dart b/lib/src/rtc_engine.dart index 29b073c..6cdee1e 100644 --- a/lib/src/rtc_engine.dart +++ b/lib/src/rtc_engine.dart @@ -495,6 +495,7 @@ class RTCEngine extends Disposable with EventsEmittable { logger.fine('[$objectId] Received server offer(type: ${event.sd.type}, ' '${subscriber!.pc.signalingState})'); + logger.finer('sdp: ${event.sd.sdp}'); await subscriber!.setRemoteDescription(event.sd); diff --git a/lib/src/signal_client.dart b/lib/src/signal_client.dart index 538d915..44382c8 100644 --- a/lib/src/signal_client.dart +++ b/lib/src/signal_client.dart @@ -24,7 +24,7 @@ class SignalClient extends Disposable with EventsEmittable { LiveKitWebSocket? _ws; SignalClient({ - this.protocol = ProtocolVersion.protocol3, + this.protocol = ProtocolVersion.protocol4, }) { events.listen((event) { logger.fine('[SignalEvent] $event'); diff --git a/lib/src/track/audio_track.dart b/lib/src/track/audio_track.dart index 26808ec..2a7ac9d 100644 --- a/lib/src/track/audio_track.dart +++ b/lib/src/track/audio_track.dart @@ -8,7 +8,7 @@ import 'package:synchronized/synchronized.dart' as sync; import '../logger.dart'; import '../proto/livekit_models.pb.dart' as lk_models; import '../support/native_audio.dart'; -import '_audio_api.dart' if (dart.library.html) '_audio_html.dart' as audio; + import 'local_audio_track.dart'; import 'track.dart'; @@ -22,7 +22,7 @@ enum AudioTrackState { typedef ConfigureNativeAudioFunc = Future Function( AudioTrackState state); -class AudioTrack extends Track { +abstract class AudioTrack extends Track { // it's possible to set custom function here to customize audio session configuration static ConfigureNativeAudioFunc nativeAudioConfigurationForAudioTrackState = defaultNativeAudioConfigurationFunc; @@ -50,10 +50,6 @@ class AudioTrack extends Track { Future start() async { final didStart = await super.start(); if (didStart) { - if (this is! LocalAudioTrack) { - audio.startAudio(getCid(), mediaStreamTrack); - } - // update counter await _trackCounterLock.synchronized(() async { if (this is LocalAudioTrack) { @@ -64,7 +60,6 @@ class AudioTrack extends Track { await _onAudioTrackCountDidChange(); }); } - return didStart; } @@ -72,10 +67,6 @@ class AudioTrack extends Track { Future stop() async { final didStop = await super.stop(); if (didStop) { - await mediaStream?.dispose(); - mediaStream = null; - audio.stopAudio(getCid()); - // update counter await _trackCounterLock.synchronized(() async { if (this is LocalAudioTrack) { @@ -86,7 +77,6 @@ class AudioTrack extends Track { await _onAudioTrackCountDidChange(); }); } - return didStop; } diff --git a/lib/src/track/local_audio_track.dart b/lib/src/track/local_audio_track.dart index ff8201f..9b0709f 100644 --- a/lib/src/track/local_audio_track.dart +++ b/lib/src/track/local_audio_track.dart @@ -7,7 +7,8 @@ import 'audio_track.dart'; import 'options.dart'; class LocalAudioTrack extends AudioTrack { - LocalAudioTrack( + // private constructor + LocalAudioTrack._( String name, rtc.MediaStreamTrack track, rtc.MediaStream stream, @@ -29,6 +30,15 @@ class LocalAudioTrack extends AudioTrack { if (stream.getAudioTracks().isEmpty) throw TrackCreateException(); - return LocalAudioTrack('', stream.getAudioTracks().first, stream); + return LocalAudioTrack._('', stream.getAudioTracks().first, stream); + } + + @override + Future stop() async { + final didStop = await super.stop(); + if (didStop) { + await mediaStreamTrack.stop(); + } + return didStop; } } diff --git a/lib/src/track/local_video_track.dart b/lib/src/track/local_video_track.dart index c7197f6..4ce5280 100644 --- a/lib/src/track/local_video_track.dart +++ b/lib/src/track/local_video_track.dart @@ -92,6 +92,15 @@ class LocalVideoTrack extends VideoTrack { if (stream.getVideoTracks().isEmpty) throw TrackCreateException(); return stream; } + + @override + Future stop() async { + final didStop = await super.stop(); + if (didStop) { + await mediaStreamTrack.stop(); + } + return didStop; + } } // diff --git a/lib/src/track/remote_audio_track.dart b/lib/src/track/remote_audio_track.dart new file mode 100644 index 0000000..cf15310 --- /dev/null +++ b/lib/src/track/remote_audio_track.dart @@ -0,0 +1,34 @@ +import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc; +import '_audio_api.dart' if (dart.library.html) '_audio_html.dart' as audio; +import 'audio_track.dart'; + +class RemoteAudioTrack extends AudioTrack { + // + RemoteAudioTrack( + String name, + rtc.MediaStreamTrack track, + rtc.MediaStream stream, + ) : super(name, track, stream); + + @override + Future start() async { + final didStart = await super.start(); + if (didStart) { + // web support + audio.startAudio(getCid(), mediaStreamTrack); + await enable(); + } + return didStart; + } + + @override + Future stop() async { + final didStop = await super.stop(); + if (didStop) { + // web support + audio.stopAudio(getCid()); + await disable(); + } + return didStop; + } +} diff --git a/lib/src/track/remote_video_track.dart b/lib/src/track/remote_video_track.dart new file mode 100644 index 0000000..e976ef2 --- /dev/null +++ b/lib/src/track/remote_video_track.dart @@ -0,0 +1,29 @@ +import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc; +import 'package:livekit_client/src/track/video_track.dart'; + +class RemoteVideoTrack extends VideoTrack { + // + RemoteVideoTrack( + String name, + rtc.MediaStreamTrack mediaTrack, + rtc.MediaStream stream, + ) : super(name, mediaTrack, stream); + + @override + Future start() async { + final didStart = await super.start(); + if (didStart) { + await enable(); + } + return didStart; + } + + @override + Future stop() async { + final didStop = await super.stop(); + if (didStop) { + await disable(); + } + return didStop; + } +} diff --git a/lib/src/track/track.dart b/lib/src/track/track.dart index 689e16f..f258e89 100644 --- a/lib/src/track/track.dart +++ b/lib/src/track/track.dart @@ -76,6 +76,8 @@ abstract class Track extends DisposableChangeNotifier return false; } + logger.fine('Track.start()'); + _active = true; return true; } @@ -88,13 +90,29 @@ abstract class Track extends DisposableChangeNotifier return false; } - try { - await mediaStreamTrack.stop(); - } catch (_) { - logger.warning('[$objectId] rtc.mediaStreamTrack.stop() did throw ${_}'); - } + logger.fine('Track.stop()'); _active = false; return true; } + + Future enable() async { + logger.fine('Track.enable()'); + try { + mediaStreamTrack.enabled = true; + } catch (_) { + logger.warning( + '[$objectId] set rtc.mediaStreamTrack.enabled did throw ${_}'); + } + } + + Future disable() async { + logger.fine('Track.disable()'); + try { + mediaStreamTrack.enabled = false; + } catch (_) { + logger.warning( + '[$objectId] set rtc.mediaStreamTrack.enabled did throw ${_}'); + } + } } diff --git a/lib/src/track/video_track.dart b/lib/src/track/video_track.dart index 0677b9d..171ed17 100644 --- a/lib/src/track/video_track.dart +++ b/lib/src/track/video_track.dart @@ -5,7 +5,7 @@ import '../proto/livekit_models.pb.dart' as lk_models; import 'track.dart'; /// A video track will notify when its mediaTrack has changed. -class VideoTrack extends Track { +abstract class VideoTrack extends Track { rtc.MediaStream _mediaStream; VideoTrack( diff --git a/lib/src/types.dart b/lib/src/types.dart index 0917e0b..98888aa 100644 --- a/lib/src/types.dart +++ b/lib/src/types.dart @@ -7,6 +7,7 @@ typedef CancelListenFunc = Function(); enum ProtocolVersion { protocol2, protocol3, + protocol4, } enum ConnectionState {