fix(playback): reload audio sources when switching tracks

This commit is contained in:
zarzet committed 2026-10-10 02:16:15 +07:00
1 parent 00cff9b3c3
commit 829aeb156e
2 files changed
+45 -2

No files matched your search

+9 -1
View File
@@ -151,7 +151,7 @@ class MusicPlaybackDeck {
_source = null;
_routeLost = false;
_nativeStarted = false;
await _ordinary.setSource(UrlSource(url));
await _setOrdinarySource(UrlSource(url));
}
Future<void> setSource(
@@ -245,6 +245,14 @@ class MusicPlaybackDeck {
usbAudioStatus.value = const UsbAudioStatus(reason: 'dsd_unsupported');
throw UsbDsdUnavailable();
}
await _setOrdinarySource(source);
}
Future<void> _setOrdinarySource(Source source) async {
// stop mode retains the native source. Android can reuse the same
// /proc/self/fd number for a different SAF file, so URL equality must not
// reuse the previous MediaPlayer or its pending preparation callbacks.
await _ordinary.release();
await _ordinary.setSource(source);
}
+36 -1
View File
@@ -66,6 +66,8 @@ class _AudioNative {
final live = <String>{};
final playing = <String>{};
final sources = <String, String>{};
final sourceContents = <String, String>{};
final preparedContents = <String, String>{};
final sourceGates = <String, Completer<void>>{};
final resumedSources = <String>[];
Completer<void>? resumeGate;
@@ -98,7 +100,11 @@ class _AudioNative {
case 'setSourceUrl':
final source = args['url']! as String;
await sourceGates[source]?.future;
sources[id] = source;
// Android caches equal URLs, including recycled SAF descriptors.
if (sources[id] != source) {
sources[id] = source;
preparedContents[id] = sourceContents[source] ?? source;
}
unawaited(event(id, 'audio.onPrepared', true));
if (emitsDuration) unawaited(event(id, 'audio.onDuration', 60000));
case 'seek':
@@ -110,6 +116,10 @@ class _AudioNative {
resumedSources.add(sources[id]!);
case 'pause' || 'stop':
playing.remove(id);
case 'release':
playing.remove(id);
sources.remove(id);
preparedContents.remove(id);
case 'dispose':
playing.remove(id);
live.remove(id);
@@ -937,6 +947,31 @@ void main() {
},
);
test('recycled SAF descriptor prepares the newly selected file', () async {
const descriptor = '/proc/self/fd/42';
native.sourceContents[descriptor] = 'first file';
await handler.setQueueAndPlay([
const PlayableMedia(
id: 'first',
source: descriptor,
title: 'First',
artist: 'Artist',
),
const PlayableMedia(
id: 'second',
source: descriptor,
title: 'Second',
artist: 'Artist',
),
]);
expect(native.preparedContents['music-player'], 'first file');
native.sourceContents[descriptor] = 'second file';
await handler.skipToNext();
expect(handler.mediaItem.value?.title, 'Second');
expect(native.preparedContents['music-player'], 'second file');
expect(native.playing, contains('music-player'));
});
test('replacing a queue during preparation drops the old request', () async {
final gate = Completer<void>();
native.sourceGates['/one.flac'] = gate;