Skip to content

Commit

Permalink
Fix/video renderer issue (#404)
Browse files Browse the repository at this point in the history
* Capture possible exceptions when closing the room at any time and the internal process is busy.

* fix.
  • Loading branch information
cloudwebrtc authored Nov 30, 2023
1 parent 000d33b commit 0d015a2
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 53 deletions.
6 changes: 5 additions & 1 deletion lib/src/core/engine.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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');
}
}
}

Expand Down
7 changes: 6 additions & 1 deletion lib/src/core/transport.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
28 changes: 20 additions & 8 deletions lib/src/track/local/audio.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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;
}

Expand All @@ -69,7 +75,13 @@ class LocalAudioTrack extends LocalTrack
return null;
}

final stats = await sender!.getStats();
late List<rtc.StatsReport> stats;
try {
stats = await sender!.getStats();
} catch (e) {
rethrow;
}

AudioSenderStats? senderStats;
for (var v in stats) {
if (v.type == 'outbound-rtp') {
Expand Down
28 changes: 20 additions & 8 deletions lib/src/track/remote/audio.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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;
}

Expand All @@ -102,7 +108,13 @@ class RemoteAudioTrack extends RemoteTrack
return null;
}

final stats = await receiver!.getStats();
late List<rtc.StatsReport> stats;
try {
stats = await receiver!.getStats();
} catch (e) {
rethrow;
}

AudioReceiverStats? receiverStats;
for (var v in stats) {
if (v.type == 'inbound-rtp') {
Expand Down
27 changes: 20 additions & 7 deletions lib/src/track/remote/video.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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;
}

Expand All @@ -67,7 +74,13 @@ class RemoteVideoTrack extends RemoteTrack with VideoTrack {
return null;
}

final stats = await receiver!.getStats();
late List<rtc.StatsReport> stats;
try {
stats = await receiver!.getStats();
} catch (e) {
rethrow;
}

VideoReceiverStats? receiverStats;
for (var v in stats) {
if (v.type == 'inbound-rtp') {
Expand Down
70 changes: 43 additions & 27 deletions lib/src/widgets/video_track_renderer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -51,29 +52,38 @@ class VideoTrackRenderer extends StatefulWidget {

class _VideoTrackRendererState extends State<VideoTrackRenderer> {
rtc.RTCVideoRenderer? _renderer;
bool _rendererReady = false;
EventsListener<TrackEvent>? _listener;
// Used to compute visibility information
late GlobalKey _internalKey;

Future<rtc.RTCVideoRenderer?> _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();
}

Expand Down Expand Up @@ -110,24 +120,30 @@ class _VideoTrackRendererState extends State<VideoTrackRenderer> {
}

@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
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 0d015a2

Please sign in to comment.