diff --git a/lib/src/core/engine.dart b/lib/src/core/engine.dart index e6dce4c7..211d724f 100644 --- a/lib/src/core/engine.dart +++ b/lib/src/core/engine.dart @@ -970,7 +970,11 @@ extension EngineInternalMethods on Engine { matched.add(c); } matched.addAll([...partialMatched, ...unmatched]); - await transceiver.setCodecPreferences(matched); + try { + await transceiver.setCodecPreferences(matched); + } catch (e) { + logger.warning('setCodecPreferences failed: $e'); + } } } diff --git a/lib/src/core/transport.dart b/lib/src/core/transport.dart index e2c990ae..ed03d014 100644 --- a/lib/src/core/transport.dart +++ b/lib/src/core/transport.dart @@ -123,7 +123,12 @@ class Transport extends Disposable { return; } - await pc.setRemoteDescription(sd); + try { + await pc.setRemoteDescription(sd); + } catch (e) { + logger + .warning('[$objectId] setRemoteDescription() failed with error: $e'); + } for (final candidate in _pendingCandidates) { await pc.addCandidate(candidate); diff --git a/lib/src/track/local/audio.dart b/lib/src/track/local/audio.dart index 9dcf5ae7..a3d4272e 100644 --- a/lib/src/track/local/audio.dart +++ b/lib/src/track/local/audio.dart @@ -19,6 +19,7 @@ import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc; import 'package:meta/meta.dart'; import '../../events.dart'; +import '../../logger.dart'; import '../../proto/livekit_models.pb.dart' as lk_models; import '../../types/other.dart'; import '../audio_management.dart'; @@ -52,15 +53,20 @@ class LocalAudioTrack extends LocalTrack _currentBitrate = 0; return false; } - final stats = await getSenderStats(); + try { + final stats = await getSenderStats(); - if (stats != null && prevStats != null && sender != null) { - _currentBitrate = computeBitrateForSenderStats(stats, prevStats); - events.emit( - AudioSenderStatsEvent(stats: stats, currentBitrate: currentBitrate)); - } + if (stats != null && prevStats != null && sender != null) { + _currentBitrate = computeBitrateForSenderStats(stats, prevStats); + events.emit(AudioSenderStatsEvent( + stats: stats, currentBitrate: currentBitrate)); + } - prevStats = stats; + prevStats = stats; + } catch (e) { + logger.warning('failed to get sender stats: $e'); + return false; + } return true; } @@ -69,7 +75,13 @@ class LocalAudioTrack extends LocalTrack return null; } - final stats = await sender!.getStats(); + late List stats; + try { + stats = await sender!.getStats(); + } catch (e) { + rethrow; + } + AudioSenderStats? senderStats; for (var v in stats) { if (v.type == 'outbound-rtp') { diff --git a/lib/src/track/remote/audio.dart b/lib/src/track/remote/audio.dart index b0a86e31..ad11248a 100644 --- a/lib/src/track/remote/audio.dart +++ b/lib/src/track/remote/audio.dart @@ -17,6 +17,7 @@ import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc; import '../../events.dart'; import '../../internal/events.dart'; +import '../../logger.dart'; import '../../proto/livekit_models.pb.dart' as lk_models; import '../../types/other.dart'; import '../audio_management.dart'; @@ -85,15 +86,20 @@ class RemoteAudioTrack extends RemoteTrack _currentBitrate = 0; return false; } - final stats = await getReceiverStats(); + try { + final stats = await getReceiverStats(); - if (stats != null && prevStats != null && receiver != null) { - _currentBitrate = computeBitrateForReceiverStats(stats, prevStats); - events.emit(AudioReceiverStatsEvent( - stats: stats, currentBitrate: currentBitrate)); - } + if (stats != null && prevStats != null && receiver != null) { + _currentBitrate = computeBitrateForReceiverStats(stats, prevStats); + events.emit(AudioReceiverStatsEvent( + stats: stats, currentBitrate: currentBitrate)); + } - prevStats = stats; + prevStats = stats; + } catch (e) { + logger.warning('failed to get sender stats: $e'); + return false; + } return true; } @@ -102,7 +108,13 @@ class RemoteAudioTrack extends RemoteTrack return null; } - final stats = await receiver!.getStats(); + late List stats; + try { + stats = await receiver!.getStats(); + } catch (e) { + rethrow; + } + AudioReceiverStats? receiverStats; for (var v in stats) { if (v.type == 'inbound-rtp') { diff --git a/lib/src/track/remote/video.dart b/lib/src/track/remote/video.dart index e057958e..49b79f41 100644 --- a/lib/src/track/remote/video.dart +++ b/lib/src/track/remote/video.dart @@ -17,6 +17,7 @@ import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc; import 'package:meta/meta.dart'; import '../../events.dart'; +import '../../logger.dart'; import '../../proto/livekit_models.pb.dart' as lk_models; import '../../types/other.dart'; import '../local/local.dart'; @@ -50,15 +51,21 @@ class RemoteVideoTrack extends RemoteTrack with VideoTrack { _currentBitrate = 0; return false; } - final stats = await getReceiverStats(); + try { + final stats = await getReceiverStats(); - if (stats != null && prevStats != null && receiver != null) { - _currentBitrate = computeBitrateForReceiverStats(stats, prevStats); - events.emit(VideoReceiverStatsEvent( - stats: stats, currentBitrate: currentBitrate)); + if (stats != null && prevStats != null && receiver != null) { + _currentBitrate = computeBitrateForReceiverStats(stats, prevStats); + events.emit(VideoReceiverStatsEvent( + stats: stats, currentBitrate: currentBitrate)); + } + + prevStats = stats; + } catch (e) { + logger.warning('Failed to monitor stats: $e'); + return false; } - prevStats = stats; return true; } @@ -67,7 +74,13 @@ class RemoteVideoTrack extends RemoteTrack with VideoTrack { return null; } - final stats = await receiver!.getStats(); + late List stats; + try { + stats = await receiver!.getStats(); + } catch (e) { + rethrow; + } + VideoReceiverStats? receiverStats; for (var v in stats) { if (v.type == 'inbound-rtp') { diff --git a/lib/src/widgets/video_track_renderer.dart b/lib/src/widgets/video_track_renderer.dart index 22615867..4addf053 100644 --- a/lib/src/widgets/video_track_renderer.dart +++ b/lib/src/widgets/video_track_renderer.dart @@ -19,6 +19,7 @@ import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc; import '../events.dart'; import '../extensions.dart'; import '../internal/events.dart'; +import '../logger.dart'; import '../managers/event.dart'; import '../support/platform.dart'; import '../track/local/local.dart'; @@ -51,29 +52,38 @@ class VideoTrackRenderer extends StatefulWidget { class _VideoTrackRendererState extends State { rtc.RTCVideoRenderer? _renderer; - bool _rendererReady = false; EventsListener? _listener; // Used to compute visibility information late GlobalKey _internalKey; + Future _initializeRenderer() async { + _renderer ??= rtc.RTCVideoRenderer(); + await _renderer!.initialize(); + await _attach(); + return _renderer; + } + + void disposeRenderer() { + try { + _renderer?.srcObject = null; + _renderer?.dispose(); + _renderer = null; + } catch (e) { + logger.warning('Got error disposing renderer: $e'); + } + } + @override void initState() { super.initState(); _internalKey = widget.track.addViewKey(); - (() async { - _renderer ??= rtc.RTCVideoRenderer(); - await _renderer?.initialize(); - await _attach(); - setState(() => _rendererReady = true); - })(); } @override void dispose() { widget.track.removeViewKey(_internalKey); _listener?.dispose(); - _renderer?.srcObject = null; - _renderer?.dispose(); + disposeRenderer(); super.dispose(); } @@ -110,24 +120,30 @@ class _VideoTrackRendererState extends State { } @override - Widget build(BuildContext context) => !_rendererReady - ? Container() - : Builder( - key: _internalKey, - builder: (ctx) { - // let it render before notifying build - WidgetsBindingCompatible.instance - ?.addPostFrameCallback((timeStamp) { - widget.track.onVideoViewBuild?.call(_internalKey); - }); - return rtc.RTCVideoView( - _renderer!, - mirror: _shouldMirror(), - filterQuality: FilterQuality.medium, - objectFit: widget.fit, - ); - }, - ); + Widget build(BuildContext context) => FutureBuilder( + future: _initializeRenderer(), + builder: (context, snapshot) { + if (snapshot.hasData && _renderer != null) { + return Builder( + key: _internalKey, + builder: (ctx) { + // let it render before notifying build + WidgetsBindingCompatible.instance + ?.addPostFrameCallback((timeStamp) { + widget.track.onVideoViewBuild?.call(_internalKey); + }); + return rtc.RTCVideoView( + _renderer!, + mirror: _shouldMirror(), + filterQuality: FilterQuality.medium, + objectFit: widget.fit, + ); + }, + ); + } + + return Container(); + }); bool _shouldMirror() { // off for screen share diff --git a/pubspec.yaml b/pubspec.yaml index 3bad92d1..e1e31d0e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,7 +38,7 @@ dependencies: uuid: '>=3.0.6' synchronized: ^3.0.0+3 protobuf: ^3.0.0 - flutter_webrtc: 0.9.46 + flutter_webrtc: 0.9.47 device_info_plus: '>=8.0.0' js: ^0.6.4 platform_detect: ^2.0.7