Automatic mirrorMode for VideoView (#119)

* update protos

* impl 1

* re-compute when options update

* minor fix
This commit is contained in:
Hiroshi Horie
2022-05-17 10:51:38 +09:00
committed by GitHub
parent 6e65fe30f7
commit ff65370cbc
3 changed files with 54 additions and 4 deletions
+12
View File
@@ -4,6 +4,8 @@ import 'package:meta/meta.dart';
import '../events.dart'; import '../events.dart';
import '../proto/livekit_models.pb.dart' as lk_models; import '../proto/livekit_models.pb.dart' as lk_models;
import '../proto/livekit_rtc.pb.dart' as lk_rtc; import '../proto/livekit_rtc.pb.dart' as lk_rtc;
import '../track/local/local.dart';
import '../track/options.dart';
import '../track/track.dart'; import '../track/track.dart';
import '../types/other.dart'; import '../types/other.dart';
@@ -59,6 +61,16 @@ class TrackStreamUpdatedEvent with TrackEvent, InternalEvent {
}); });
} }
@internal
class LocalTrackOptionsUpdatedEvent with TrackEvent, InternalEvent {
final LocalTrack track;
final LocalTrackOptions options;
const LocalTrackOptionsUpdatedEvent({
required this.track,
required this.options,
});
}
// Used to notify muted state from Track to TrackPublication. // Used to notify muted state from Track to TrackPublication.
@internal @internal
class InternalTrackMuteUpdatedEvent with TrackEvent, InternalEvent { class InternalTrackMuteUpdatedEvent with TrackEvent, InternalEvent {
+7
View File
@@ -5,6 +5,7 @@ import 'package:meta/meta.dart';
import '../../events.dart'; import '../../events.dart';
import '../../exceptions.dart'; import '../../exceptions.dart';
import '../../extensions.dart'; import '../../extensions.dart';
import '../../internal/events.dart';
import '../../logger.dart'; import '../../logger.dart';
import '../../participant/remote.dart'; import '../../participant/remote.dart';
import '../../proto/livekit_models.pb.dart' as lk_models; import '../../proto/livekit_models.pb.dart' as lk_models;
@@ -172,6 +173,12 @@ abstract class LocalTrack extends Track {
// mark as started // mark as started
await start(); await start();
// notify so VideoView can re-compute mirror mode if necessary
events.emit(LocalTrackOptionsUpdatedEvent(
track: this,
options: currentOptions,
));
} }
@internal @internal
+35 -4
View File
@@ -7,15 +7,24 @@ import '../internal/events.dart';
import '../managers/event.dart'; import '../managers/event.dart';
import '../track/local/local.dart'; import '../track/local/local.dart';
import '../track/local/video.dart'; import '../track/local/video.dart';
import '../track/options.dart';
enum VideoViewMirrorMode {
auto,
off,
mirror,
}
/// Widget that renders a [VideoTrack]. /// Widget that renders a [VideoTrack].
class VideoTrackRenderer extends StatefulWidget { class VideoTrackRenderer extends StatefulWidget {
final VideoTrack track; final VideoTrack track;
final rtc.RTCVideoViewObjectFit fit; final rtc.RTCVideoViewObjectFit fit;
final VideoViewMirrorMode mirrorMode;
const VideoTrackRenderer( const VideoTrackRenderer(
this.track, { this.track, {
this.fit = rtc.RTCVideoViewObjectFit.RTCVideoViewObjectFitContain, this.fit = rtc.RTCVideoViewObjectFit.RTCVideoViewObjectFitContain,
this.mirrorMode = VideoViewMirrorMode.auto,
Key? key, Key? key,
}) : super(key: key); }) : super(key: key);
@@ -56,9 +65,13 @@ class _VideoTrackRendererState extends State<VideoTrackRenderer> {
await _listener?.dispose(); await _listener?.dispose();
_listener = widget.track.createListener() _listener = widget.track.createListener()
..on<TrackStreamUpdatedEvent>((event) { ..on<TrackStreamUpdatedEvent>((event) {
if (mounted) { if (!mounted) return;
_renderer.srcObject = event.stream; _renderer.srcObject = event.stream;
} })
..on<LocalTrackOptionsUpdatedEvent>((event) {
if (!mounted) return;
// force recompute of mirror mode
setState(() {});
}); });
} }
@@ -89,10 +102,28 @@ class _VideoTrackRendererState extends State<VideoTrackRenderer> {
}); });
return rtc.RTCVideoView( return rtc.RTCVideoView(
_renderer, _renderer,
mirror: widget.track is LocalVideoTrack, mirror: _shouldMirror(),
filterQuality: FilterQuality.medium, filterQuality: FilterQuality.medium,
objectFit: widget.fit, objectFit: widget.fit,
); );
}, },
); );
bool _shouldMirror() {
// on
if (widget.mirrorMode == VideoViewMirrorMode.mirror) return true;
// auto
if (widget.mirrorMode == VideoViewMirrorMode.auto) {
final track = widget.track;
if (track is LocalVideoTrack) {
final options = track.currentOptions;
if (options is CameraCaptureOptions) {
// mirror if front camera
return options.cameraPosition == CameraPosition.front;
}
}
}
// default to false
return false;
}
} }