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:
CloudWebRTC
2023-04-27 10:14:03 +08:00
committed by GitHub
parent f07afc10be
commit 3407221fc4
5 changed files with 92 additions and 19 deletions
+14
View File
@@ -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})';
+45 -15
View File
@@ -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);
}
}
+15 -2
View File
@@ -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();
+16
View File
@@ -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,
),
);
}