feature: switch between front and back cameras

This commit is contained in:
David Zhao
2021-08-06 21:20:21 -07:00
parent f1a7591ec7
commit 509a037936
6 changed files with 77 additions and 10 deletions
+38 -1
View File
@@ -5,6 +5,8 @@ import 'options.dart';
import 'video_track.dart';
class LocalVideoTrack extends VideoTrack {
RTCRtpSender? get sender => transceiver?.sender;
LocalVideoTrack(String name, MediaStreamTrack mediaTrack, MediaStream stream)
: super(name, mediaTrack, stream);
@@ -14,6 +16,41 @@ class LocalVideoTrack extends VideoTrack {
options = LocalVideoTrackOptions(params: VideoPresets.qhd);
}
try {
var stream = await _createCameraStream(options);
return LocalVideoTrack("camera", stream.getVideoTracks().first, stream);
} catch (e) {
return Future.error(e);
}
}
Future<void> restartTrack([LocalVideoTrackOptions? options]) async {
if (sender == null) {
return Future.error(TrackCreateError('could not restart track'));
}
if (options == null) {
options = LocalVideoTrackOptions(params: VideoPresets.qhd);
}
try {
var stream = await _createCameraStream(options);
var track = stream.getVideoTracks().first;
mediaStream = stream;
await mediaTrack.stop();
mediaTrack = track;
await sender?.replaceTrack(track);
} catch (e) {
return Future.error(e);
}
}
static Future<MediaStream> _createCameraStream(
LocalVideoTrackOptions? options) async {
if (options == null) {
options = LocalVideoTrackOptions(params: VideoPresets.qhd);
}
try {
var stream = await navigator.mediaDevices.getUserMedia({
"audio": false,
@@ -24,7 +61,7 @@ class LocalVideoTrack extends VideoTrack {
return Future.error(TrackCreateError());
}
return LocalVideoTrack("camera", stream.getVideoTracks().first, stream);
return stream;
} catch (e) {
return Future.error(e);
}
+5 -2
View File
@@ -3,9 +3,12 @@ class LocalVideoTrackOptions {
VideoParameter params;
LocalVideoTrackOptions({
required VideoParameter params,
VideoParameter? params,
CameraPosition? position,
}) : this.params = params {
}) : params = VideoPresets.qhd {
if (params != null) {
this.params = params;
}
if (position != null) {
this.position = position;
}
@@ -49,6 +49,9 @@ class RemoteTrackPublication extends TrackPublication {
_participant.delegate?.onTrackUnmuted(_participant, this);
_participant.roomDelegate?.onTrackUnmuted(_participant, this);
}
if (subscribed) {
track?.mediaTrack.enabled = !val;
}
_participant.muteChanged();
}
+2
View File
@@ -22,6 +22,8 @@ class Track {
Track(this.kind, this.name, this.mediaTrack);
bool get muted => mediaTrack.muted == null ? false : mediaTrack.muted!;
RTCRtpMediaType get mediaType {
switch (kind) {
case TrackType.AUDIO:
+14 -5
View File
@@ -1,18 +1,27 @@
import 'package:flutter/material.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';
import '../proto/livekit_models.pb.dart';
import 'track.dart';
class VideoTrack extends Track {
MediaStream? mediaStream;
/// A video track will notify when its mediaTrack has changed.
class VideoTrack extends Track with ChangeNotifier {
MediaStream? _mediaStream;
VideoTrack(String name, MediaStreamTrack mediaTrack, this.mediaStream)
VideoTrack(String name, MediaStreamTrack mediaTrack, this._mediaStream)
: super(TrackType.VIDEO, name, mediaTrack);
MediaStream? get mediaStream => _mediaStream;
set mediaStream(MediaStream? stream) {
_mediaStream = stream;
notifyListeners();
}
@override
stop() {
super.stop();
mediaStream?.dispose();
mediaStream = null;
_mediaStream?.dispose();
_mediaStream = null;
}
}
+15 -2
View File
@@ -23,22 +23,35 @@ class _VideoTrackRendererState extends State<VideoTrackRenderer> {
@override
void initState() {
super.initState();
widget.track.addListener(_trackChanged);
_initRenderer();
}
@override
void dispose() {
widget.track.removeListener(_trackChanged);
_renderer.dispose();
super.dispose();
}
_initRenderer() async {
await _renderer.initialize();
@override
void didUpdateWidget(covariant VideoTrackRenderer oldWidget) {
oldWidget.track.removeListener(_trackChanged);
widget.track.addListener(_trackChanged);
super.didUpdateWidget(oldWidget);
}
_trackChanged() {
setState(() {
_renderer.srcObject = widget.track.mediaStream;
});
}
_initRenderer() async {
await _renderer.initialize();
_trackChanged();
}
@override
Widget build(BuildContext context) {
var isLocal = widget.track is LocalVideoTrack;