diff --git a/lib/playback/playback_engine.dart b/lib/playback/playback_engine.dart index 03e1d5f..4eceee7 100644 --- a/lib/playback/playback_engine.dart +++ b/lib/playback/playback_engine.dart @@ -141,13 +141,15 @@ class PlaybackController extends StateNotifier required String? Function() serverKeyGetter, required void Function(Uri artUri) onArt, required void Function(Song song) onPlay, + @visibleForTesting bool? audioEnabled, }) : _streamUriFor = streamUriFor, _coverArtUriFor = coverArtUriFor, _serverKeyGetter = serverKeyGetter, _onArt = onArt, _onPlay = onPlay, - super(PlaybackState(supported: _audioSupported)) { - if (_audioSupported) { + _audioEnabled = audioEnabled ?? _audioSupported, + super(PlaybackState(supported: audioEnabled ?? _audioSupported)) { + if (_audioEnabled) { _player = AudioPlayer(); _wireStreams(); } @@ -161,6 +163,12 @@ class PlaybackController extends StateNotifier final void Function(Uri artUri) _onArt; final void Function(Song song) _onPlay; + /// Whether a platform [AudioPlayer] was created. Defaults to [_audioSupported] + /// but tests force it false so a headless CI host (macOS/iOS, where + /// [_audioSupported] is true) doesn't touch uninitialized just_audio platform + /// channels. The queue/state logic runs identically either way. + final bool _audioEnabled; + AudioPlayer? _player; final Random _random = Random(); diff --git a/test/remote_integration_test.dart b/test/remote_integration_test.dart index 3009a6a..737de0d 100644 --- a/test/remote_integration_test.dart +++ b/test/remote_integration_test.dart @@ -23,13 +23,17 @@ void main() { final sessions = []; PlaybackController buildController() => PlaybackController( - // Non-null so songs count as streamable; no real player exists on the - // test host (audio unsupported), so this URI is never opened. + // Non-null so songs count as streamable; no real player is created + // (audioEnabled: false), so this URI is never opened. Forcing audio off + // keeps the test headless on any host — a macOS/iOS CI runner would + // otherwise build a just_audio AudioPlayer against uninitialized + // platform channels and throw. streamUriFor: (s) => Uri.parse('http://host.local/stream/${s.id}'), coverArtUriFor: (_) => null, serverKeyGetter: () => serverKey, onArt: (_) {}, onPlay: (_) {}, + audioEnabled: false, ); RemoteSession newSession(