refactor: M2-Call-Pilot – Module call_signaling + voice_channel mit Fassaden (Entscheidung 2)

- CallSignalingService/callSignalingProvider und VoiceChannelService/
  voiceChannelProvider als einzige oeffentliche Schnittstellen
- voip_manager.dart / livekit_call_manager.dart in ihre Module verschoben,
  Logik unangetastet (nur Klassen-Koepfe, @override, Imports, Provider-Namen)
- Alle Konsumenten entkoppelt; Kompositions-Punkt matrix_client.dart als
  dokumentierte Ausnahme. analyze sauber, 29 Tests gruen, Windows-Start ok.
  Call-Klick-/Geraetetest steht aus (PROGRESS.md)
This commit is contained in:
Bernd Steckmeister
2026-07-06 12:42:59 +02:00
parent f64398d3c6
commit 3c7eb9ddca
20 changed files with 383 additions and 53 deletions
@@ -0,0 +1,67 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc;
import 'package:matrix/matrix.dart';
import 'package:pyramid/features/call_signaling/voip_manager.dart';
/// Öffentliche Schnittstelle des Moduls `call_signaling` natives
/// Matrix-1:1-VoIP (`m.call.*`-Events, direkte WebRTC-Peer-Connection,
/// kein SFU). Schnitt nach `docs/M2_MODULE_SCHNITT.md`.
///
/// Andere Module (UI, Settings, Shell) konsumieren AUSSCHLIESSLICH diese
/// Schnittstelle über [callSignalingProvider] nie `voip_manager.dart`
/// direkt. Einzige Ausnahme ist der Kompositions-Punkt in
/// `matrix_client.dart`, der die Implementierung konstruiert.
///
/// Bewusste Abweichungen vom Entwurf im Doc (Verhaltensgleichheit vor
/// Schönheit, heiliger Call-Pfad):
/// * ChangeNotifier statt Streams die gesamte UI hängt heute an
/// `ref.watch(...)` mit notifyListeners; ein Stream-Umbau wäre eine
/// Verhaltensänderung ohne Not.
/// * [currentCall] bleibt als matrix-SDK-`CallSession` sichtbar (die UI
/// braucht state/room/answer/reject), ebenso die WebRTC-Renderer
/// das Doc sieht Letzteres ausdrücklich vor.
abstract class CallSignalingService extends ChangeNotifier {
/// Der laufende 1:1-Call (null = keiner). UI liest state/room und
/// beantwortet eingehende Calls über [safeAction] + answer()/reject().
CallSession? get currentCall;
rtc.RTCVideoRenderer get localRenderer;
rtc.RTCVideoRenderer get remoteRenderer;
bool get isMicMuted;
bool get isCameraMuted;
bool get isScreensharing;
bool get isRemoteScreensharing;
bool get isDeafened;
/// Sende-Qualität ('sd' | 'hd' | 'fhd' | '4k').
String get currentQualityKey;
Future<void> startCall(String roomId, {bool video});
Future<void> hangup();
Future<void> toggleMic();
Future<void> toggleCamera();
Future<void> toggleDeafen();
/// Auf Windows öffnet ein [context] den Quellen-Picker fürs Screensharing.
Future<void> toggleScreenSharing([BuildContext? context]);
Future<void> changeQuality(String key);
/// Wendet die in den Einstellungen gewählte Ausgabelautstärke auf den
/// Remote-Stream an. Ohne [value] wird der Pref-Wert gelesen.
Future<void> applyOutputVolume([double? value]);
/// Führt eine Call-Aktion (answer/reject/…) fehlertolerant aus und stößt
/// danach die interne Zustands-/Renderer-Aktualisierung an.
Future<void> safeAction(Future<dynamic> Function() action);
}
/// Einziger Zugriffsweg der UI auf das 1:1-VoIP-Modul. Die Instanz wird beim
/// Client-Aufbau in `matrix_client.dart` erzeugt (existiert also, sobald die
/// eingeloggte Shell steht).
final callSignalingProvider =
ChangeNotifierProvider<CallSignalingService>((ref) {
return PyramidVoipManager.instance;
});