Fix resolution/framerate/bitrate issue for publishVideoTrack (#270)
* Add screenShareCaptureOptions for setScreenShareEnabled. * update. * bump version for flutter-webrtc. * chore: add maintainResolution setting for publish screen sharing track. * chore: add CaptureOptions for setCameraEnabled/setMicrophoneEnabled/setScreenShareEnabled. * update. * revert changes for videoRids. * chore: set the default sending bitrate.
This commit is contained in:
@@ -155,6 +155,20 @@ class VideoPublishOptions {
|
||||
this.screenShareSimulcastLayers = const [],
|
||||
});
|
||||
|
||||
VideoPublishOptions copyWith({
|
||||
VideoEncoding? videoEncoding,
|
||||
bool? simulcast,
|
||||
List<VideoParameters>? videoSimulcastLayers,
|
||||
List<VideoParameters>? screenShareSimulcastLayers,
|
||||
}) =>
|
||||
VideoPublishOptions(
|
||||
videoEncoding: videoEncoding ?? this.videoEncoding,
|
||||
simulcast: simulcast ?? this.simulcast,
|
||||
videoSimulcastLayers: videoSimulcastLayers ?? this.videoSimulcastLayers,
|
||||
screenShareSimulcastLayers:
|
||||
screenShareSimulcastLayers ?? this.screenShareSimulcastLayers,
|
||||
);
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'${runtimeType}(videoEncoding: ${videoEncoding}, simulcast: ${simulcast})';
|
||||
|
||||
@@ -113,6 +113,13 @@ class LocalParticipant extends Participant<LocalTrackPublication> {
|
||||
publishOptions =
|
||||
publishOptions ?? room.roomOptions.defaultVideoPublishOptions;
|
||||
|
||||
// set the default sending bitrate
|
||||
if (publishOptions.videoEncoding == null) {
|
||||
publishOptions = publishOptions.copyWith(
|
||||
videoEncoding: track.currentOptions.params.encoding,
|
||||
);
|
||||
}
|
||||
|
||||
// use constraints passed to getUserMedia by default
|
||||
VideoDimensions dimensions = track.currentOptions.params.dimensions;
|
||||
|
||||
@@ -175,6 +182,15 @@ class LocalParticipant extends Participant<LocalTrackPublication> {
|
||||
init: transceiverInit,
|
||||
);
|
||||
|
||||
// prefer to maintainResolution for screen share
|
||||
if (track.source == TrackSource.screenShareVideo) {
|
||||
var sender = track.transceiver!.sender;
|
||||
var parameters = sender.parameters;
|
||||
parameters.degradationPreference =
|
||||
rtc.RTCDegradationPreference.MAINTAIN_RESOLUTION;
|
||||
await sender.setParameters(parameters);
|
||||
}
|
||||
|
||||
await room.engine.negotiate();
|
||||
|
||||
final pub = LocalTrackPublication<LocalVideoTrack>(
|
||||
@@ -314,27 +330,36 @@ class LocalParticipant extends Participant<LocalTrackPublication> {
|
||||
.toList();
|
||||
|
||||
/// Shortcut for publishing a [TrackSource.camera]
|
||||
Future<LocalTrackPublication?> setCameraEnabled(bool enabled) async {
|
||||
return setSourceEnabled(TrackSource.camera, enabled);
|
||||
Future<LocalTrackPublication?> setCameraEnabled(bool enabled,
|
||||
{CameraCaptureOptions? cameraCaptureOptions}) async {
|
||||
return setSourceEnabled(TrackSource.camera, enabled,
|
||||
cameraCaptureOptions: cameraCaptureOptions);
|
||||
}
|
||||
|
||||
/// Shortcut for publishing a [TrackSource.microphone]
|
||||
Future<LocalTrackPublication?> setMicrophoneEnabled(bool enabled) async {
|
||||
return setSourceEnabled(TrackSource.microphone, enabled);
|
||||
Future<LocalTrackPublication?> setMicrophoneEnabled(bool enabled,
|
||||
{AudioCaptureOptions? audioCaptureOptions}) async {
|
||||
return setSourceEnabled(TrackSource.microphone, enabled,
|
||||
audioCaptureOptions: audioCaptureOptions);
|
||||
}
|
||||
|
||||
/// Shortcut for publishing a [TrackSource.screenShareVideo]
|
||||
Future<LocalTrackPublication?> setScreenShareEnabled(bool enabled,
|
||||
{bool? captureScreenAudio}) async {
|
||||
{bool? captureScreenAudio,
|
||||
ScreenShareCaptureOptions? screenShareCaptureOptions}) async {
|
||||
return setSourceEnabled(TrackSource.screenShareVideo, enabled,
|
||||
captureScreenAudio: captureScreenAudio);
|
||||
captureScreenAudio: captureScreenAudio,
|
||||
screenShareCaptureOptions: screenShareCaptureOptions);
|
||||
}
|
||||
|
||||
/// A convenience method to publish a track for a specific [TrackSource].
|
||||
/// This is the recommended method to publish tracks.
|
||||
Future<LocalTrackPublication?> setSourceEnabled(
|
||||
TrackSource source, bool enabled,
|
||||
{bool? captureScreenAudio}) async {
|
||||
{bool? captureScreenAudio,
|
||||
AudioCaptureOptions? audioCaptureOptions,
|
||||
CameraCaptureOptions? cameraCaptureOptions,
|
||||
ScreenShareCaptureOptions? screenShareCaptureOptions}) async {
|
||||
logger.fine('setSourceEnabled(source: $source, enabled: $enabled)');
|
||||
final publication = getTrackPublicationBySource(source);
|
||||
if (publication != null) {
|
||||
@@ -351,21 +376,26 @@ class LocalParticipant extends Participant<LocalTrackPublication> {
|
||||
return publication;
|
||||
} else if (enabled) {
|
||||
if (source == TrackSource.camera) {
|
||||
final track = await LocalVideoTrack.createCameraTrack(
|
||||
room.roomOptions.defaultCameraCaptureOptions);
|
||||
CameraCaptureOptions captureOptions = cameraCaptureOptions ??
|
||||
room.roomOptions.defaultCameraCaptureOptions;
|
||||
final track = await LocalVideoTrack.createCameraTrack(captureOptions);
|
||||
return await publishVideoTrack(track);
|
||||
} else if (source == TrackSource.microphone) {
|
||||
final track = await LocalAudioTrack.create(
|
||||
room.roomOptions.defaultAudioCaptureOptions);
|
||||
AudioCaptureOptions captureOptions =
|
||||
audioCaptureOptions ?? room.roomOptions.defaultAudioCaptureOptions;
|
||||
final track = await LocalAudioTrack.create(captureOptions);
|
||||
return await publishAudioTrack(track);
|
||||
} else if (source == TrackSource.screenShareVideo) {
|
||||
ScreenShareCaptureOptions captureOptions = screenShareCaptureOptions ??
|
||||
room.roomOptions.defaultScreenShareCaptureOptions;
|
||||
|
||||
/// When capturing chrome table audio, we can't capture audio/video
|
||||
/// track separately, it has to be returned once in getDisplayMedia,
|
||||
/// so we publish it twice here, but only return videoTrack to user.
|
||||
if (captureScreenAudio != null) {
|
||||
captureOptions = captureOptions.copyWith(captureScreenAudio: true);
|
||||
final tracks = await LocalVideoTrack.createScreenShareTracksWithAudio(
|
||||
ScreenShareCaptureOptions(
|
||||
captureScreenAudio: captureScreenAudio));
|
||||
captureOptions);
|
||||
LocalTrackPublication<LocalVideoTrack>? publication;
|
||||
for (final track in tracks) {
|
||||
if (track is LocalVideoTrack) {
|
||||
@@ -378,8 +408,8 @@ class LocalParticipant extends Participant<LocalTrackPublication> {
|
||||
/// just return the video track publication
|
||||
return publication;
|
||||
}
|
||||
final track = await LocalVideoTrack.createScreenShareTrack(
|
||||
room.roomOptions.defaultScreenShareCaptureOptions);
|
||||
final track =
|
||||
await LocalVideoTrack.createScreenShareTrack(captureOptions);
|
||||
return await publishVideoTrack(track);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ class CameraCaptureOptions extends VideoCaptureOptions {
|
||||
this.cameraPosition = CameraPosition.front,
|
||||
String? deviceId,
|
||||
double? maxFrameRate,
|
||||
VideoParameters params = VideoParametersPresets.h540_169,
|
||||
VideoParameters params = VideoParametersPresets.h720_169,
|
||||
}) : super(params: params, deviceId: deviceId, maxFrameRate: maxFrameRate);
|
||||
|
||||
CameraCaptureOptions.from({required VideoCaptureOptions captureOptions})
|
||||
@@ -89,7 +89,7 @@ class ScreenShareCaptureOptions extends VideoCaptureOptions {
|
||||
this.captureScreenAudio = false,
|
||||
String? sourceId,
|
||||
double? maxFrameRate,
|
||||
VideoParameters params = VideoParametersPresets.screenShareH720FPS15,
|
||||
VideoParameters params = VideoParametersPresets.screenShareH1080FPS15,
|
||||
}) : super(params: params, deviceId: sourceId, maxFrameRate: maxFrameRate);
|
||||
|
||||
ScreenShareCaptureOptions.from(
|
||||
@@ -98,6 +98,19 @@ class ScreenShareCaptureOptions extends VideoCaptureOptions {
|
||||
required VideoCaptureOptions captureOptions})
|
||||
: super(params: captureOptions.params);
|
||||
|
||||
ScreenShareCaptureOptions copyWith({
|
||||
bool? captureScreenAudio,
|
||||
VideoParameters? params,
|
||||
String? sourceId,
|
||||
double? maxFrameRate,
|
||||
}) =>
|
||||
ScreenShareCaptureOptions(
|
||||
captureScreenAudio: captureScreenAudio ?? this.captureScreenAudio,
|
||||
params: params ?? this.params,
|
||||
sourceId: sourceId ?? deviceId,
|
||||
maxFrameRate: maxFrameRate ?? this.maxFrameRate,
|
||||
);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toMediaConstraintsMap() {
|
||||
var constraints = super.toMediaConstraintsMap();
|
||||
|
||||
@@ -288,4 +288,20 @@ extension VideoParametersPresets on VideoParameters {
|
||||
maxFramerate: 30,
|
||||
),
|
||||
);
|
||||
|
||||
static const screenShareH1440FPS30 = VideoParameters(
|
||||
dimensions: VideoDimensionsPresets.h1440_169,
|
||||
encoding: VideoEncoding(
|
||||
maxBitrate: 5 * 1000 * 1000,
|
||||
maxFramerate: 30,
|
||||
),
|
||||
);
|
||||
|
||||
static const screenShareH2160FPS30 = VideoParameters(
|
||||
dimensions: VideoDimensionsPresets.h2160_169,
|
||||
encoding: VideoEncoding(
|
||||
maxBitrate: 8 * 1000 * 1000,
|
||||
maxFramerate: 30,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
+2
-2
@@ -23,10 +23,10 @@ dependencies:
|
||||
uuid: ^3.0.6
|
||||
synchronized: ^3.0.0+3
|
||||
protobuf: ^2.1.0
|
||||
flutter_webrtc: 0.9.25
|
||||
flutter_webrtc: 0.9.26
|
||||
flutter_window_close: ^0.2.2
|
||||
device_info_plus: ^8.0.0
|
||||
webrtc_interface: 1.0.12
|
||||
webrtc_interface: 1.0.13
|
||||
dart_webrtc: 1.0.16
|
||||
platform_detect: ^2.0.7
|
||||
|
||||
|
||||
Reference in New Issue
Block a user