feat: promote linux native audio path

This commit is contained in:
Edison Jwa
2026-05-25 17:42:06 +09:00
parent c19de3a370
commit a2d686d9d0
73 changed files with 26156 additions and 467 deletions
+106
View File
@@ -226,6 +226,9 @@ class _BetaHomeState extends State<_BetaHome> with WidgetsBindingObserver {
AndroidPermissionsService();
final IosPermissionsService _iosPermissions = IosPermissionsService();
final UiPreferencesService _uiPreferences = const UiPreferencesService();
Map<String, ClientPlaybackPreference> _clientPlaybackPrefs = const {};
final Map<BigInt, double> _appliedClientPlaybackVolumes = {};
String _clientPlaybackPrefsHost = '';
late final BackIntentService _backIntentService;
int _modalRouteDepth = 0;
@@ -314,6 +317,105 @@ class _BetaHomeState extends State<_BetaHome> with WidgetsBindingObserver {
} catch (_) {}
}
Future<void> _ensureClientPlaybackPreferencesLoadedForCurrentHost() async {
final host = _hostCtl.text.trim().toLowerCase();
if (host.isEmpty) {
_clientPlaybackPrefsHost = '';
_clientPlaybackPrefs = const {};
_appliedClientPlaybackVolumes.clear();
return;
}
if (_clientPlaybackPrefsHost == host) return;
_appliedClientPlaybackVolumes.clear();
try {
_clientPlaybackPrefs = await _uiPreferences
.loadClientPlaybackPreferencesForServer(host);
_clientPlaybackPrefsHost = host;
} catch (_) {
_clientPlaybackPrefsHost = host;
_clientPlaybackPrefs = const {};
}
}
Future<void> _applyClientPlaybackPreferencesToSnapshot(
rust.BridgeSnapshot snap,
) async {
await _ensureClientPlaybackPreferencesLoadedForCurrentHost();
if (_clientPlaybackPrefs.isEmpty) return;
for (final client in snap.clients) {
if (client.id == snap.ownClientId ||
client.isServerQuery ||
client.uid.isEmpty) {
continue;
}
final pref = _clientPlaybackPrefs[client.uid];
if (pref == null) continue;
if (_appliedClientPlaybackVolumes[client.id] == pref.appliedVolume) {
continue;
}
try {
await rust.setClientVolume(
clientId: client.id,
volume: pref.appliedVolume,
);
_appliedClientPlaybackVolumes[client.id] = pref.appliedVolume;
} catch (_) {
// Best-effort: queues may not exist yet for silent users.
}
}
}
Future<void> _setClientPlaybackPreference(
rust.BridgeClient client,
ClientPlaybackPreference preference,
) async {
if (client.id == _snapshot?.ownClientId ||
client.isServerQuery ||
client.uid.isEmpty) {
return;
}
final host = _hostCtl.text.trim().toLowerCase();
if (host.isEmpty) return;
await _ensureClientPlaybackPreferencesLoadedForCurrentHost();
final nextPrefs = Map<String, ClientPlaybackPreference>.from(
_clientPlaybackPrefs,
);
if (preference.volume == 1.0 && !preference.muted) {
nextPrefs.remove(client.uid);
} else {
nextPrefs[client.uid] = preference;
}
if (mounted) {
setState(() => _clientPlaybackPrefs = nextPrefs);
} else {
_clientPlaybackPrefs = nextPrefs;
}
try {
await _uiPreferences.saveClientPlaybackPreference(
serverHost: host,
userUid: client.uid,
volume: preference.volume,
muted: preference.muted,
);
} catch (error) {
_recordUiDiagnostic('save client playback preference', error);
}
try {
await rust.setClientVolume(
clientId: client.id,
volume: preference.appliedVolume,
);
_appliedClientPlaybackVolumes[client.id] = preference.appliedVolume;
} catch (error) {
_recordUiDiagnostic('set client volume', error);
}
}
Future<void> _requestRecordAudioOnStartup() async {
try {
if (Platform.isAndroid) {
@@ -1482,6 +1584,7 @@ class _BetaHomeState extends State<_BetaHome> with WidgetsBindingObserver {
void _applySnapshot(rust.BridgeSnapshot snap) {
_snapshot = snap;
unawaited(_applyClientPlaybackPreferencesToSnapshot(snap));
final own = ownClientSnapshotState(snap);
if (own == null) return;
_inputMuted = own.inputMuted;
@@ -2013,6 +2116,9 @@ class _BetaHomeState extends State<_BetaHome> with WidgetsBindingObserver {
onJoinChannel: (ch) => _onJoinChannel(ch),
onJoinChannelWithPassword: (ch) =>
_onJoinChannel(ch, askForPassword: true),
clientPlaybackPreferences: _clientPlaybackPrefs,
onClientPlaybackPreferenceChanged:
_setClientPlaybackPreference,
onTs3ServerLink: _onTs3ServerLink,
);
final ownClientState = _ownClientState;