Automatic mirrorMode for VideoView (#119)
* update protos * impl 1 * re-compute when options update * minor fix
This commit is contained in:
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user