feat: 60-FPS-Streaming-Presets (hd60/fhd60) fuer Bildschirm-Streams (M4)

Nach docs/STREAMING_60FPS.md: neue Presets 720p/1080p mit 60 FPS und
hoher Bitrate (5/8 Mbit/s), Preset-Aufloesung+FPS werden jetzt bis in
die Capture-Constraints durchgereicht (vorher blieb der LiveKit-Default
1080p/15 aktiv), 60-FPS-Presets publishen ohne Simulcast mit
DegradationPreference.maintainFramerate (unter Last Aufloesung statt
Frames opfern). contentHint 'motion' ist in flutter_webrtc 1.4.1 aus
Dart nicht setzbar (geprueft) - im Code dokumentiert.
4 neue Vertragstests fuer die Preset-Tabellen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Bernd Steckmeister
2026-07-06 22:19:25 +02:00
parent 9f797279eb
commit ffd70caffd
4 changed files with 101 additions and 10 deletions
+55
View File
@@ -0,0 +1,55 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:livekit_client/livekit_client.dart';
import 'package:pyramid/features/voice_channel/livekit_call_manager.dart';
/// Vertragstests für die Streaming-Qualitäts-Presets (M4,
/// `docs/STREAMING_60FPS.md`). Nagelt fest, was `startScreenShare` und das
/// SENDEN-Menü voraussetzen: jede Auflösung hat eine Encoding-Zeile, die
/// 60-FPS-Presets tragen wirklich 60 FPS und genug Bitrate dafür.
/// (Das echte Publish-Verhalten sender.parameters.encodings im Call
/// braucht zwei verbundene Clients und bleibt ein Gerätetest.)
void main() {
test('Jedes Auflösungs-Preset hat genau eine Encoding-Zeile (und umgekehrt)',
() {
expect(
LiveKitCallManager.qualityPresets.keys.toSet(),
LiveKitCallManager.screenShareEncodings.keys.toSet(),
reason: 'qualityPresets und screenShareEncodings müssen dieselben '
'Keys haben sonst fällt ein Menü-Eintrag auf den Fallback zurück',
);
});
test('60-FPS-Presets: wirklich 60 FPS, hohe Bitrate, richtige Auflösung',
() {
for (final key in ['hd60', 'fhd60']) {
final enc = LiveKitCallManager.screenShareEncodings[key]!;
expect(enc.maxFramerate, 60, reason: '$key muss 60 FPS tragen');
expect(enc.maxBitrate, greaterThanOrEqualTo(4_000_000),
reason: '$key: zu wenig Bitrate für 60 FPS → Encoder ruckelt');
expect(LiveKitCallManager.isHighFpsPreset(key), isTrue);
}
expect(LiveKitCallManager.qualityPresets['hd60']!.dimensions,
VideoParametersPresets.h720_169.dimensions);
expect(LiveKitCallManager.qualityPresets['fhd60']!.dimensions,
VideoParametersPresets.h1080_169.dimensions);
});
test('60-FPS-Preset hat mehr Bitrate als sein Standard-Pendant', () {
final enc = LiveKitCallManager.screenShareEncodings;
expect(enc['hd60']!.maxBitrate, greaterThan(enc['hd']!.maxBitrate));
expect(enc['fhd60']!.maxBitrate, greaterThan(enc['fhd']!.maxBitrate));
});
test('Bestands-Presets unverändert (kein Verhaltenssprung für Uta)', () {
final enc = LiveKitCallManager.screenShareEncodings;
expect(enc['sd'], const VideoEncoding(maxBitrate: 500_000, maxFramerate: 10));
expect(enc['hd'], const VideoEncoding(maxBitrate: 1_500_000, maxFramerate: 15));
expect(enc['fhd'], const VideoEncoding(maxBitrate: 2_500_000, maxFramerate: 20));
expect(enc['4k'], const VideoEncoding(maxBitrate: 4_000_000, maxFramerate: 30));
for (final key in ['sd', 'hd', 'fhd', '4k']) {
expect(LiveKitCallManager.isHighFpsPreset(key), isFalse,
reason: '$key darf NICHT als 60-FPS-Preset behandelt werden '
'(sonst verliert es Simulcast)');
}
});
}