diff --git a/lib/services/audio_player.dart b/lib/services/audio_player.dart index 41cea529c..cc0a17ead 100644 --- a/lib/services/audio_player.dart +++ b/lib/services/audio_player.dart @@ -1,53 +1,71 @@ import 'dart:async'; import 'package:audioplayers/audioplayers.dart' as ap; -import 'package:assets_audio_player/assets_audio_player.dart' as aap; +import 'package:just_audio/just_audio.dart' as ja; import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; final audioPlayer = SpotubeAudioPlayer(); -enum PlayerState { +enum AudioPlaybackState { playing, paused, completed, buffering, stopped; - static PlayerState fromApPlayerState(ap.PlayerState state) { + static AudioPlaybackState fromApPlayerState(ap.PlayerState state) { switch (state) { case ap.PlayerState.playing: - return PlayerState.playing; + return AudioPlaybackState.playing; case ap.PlayerState.paused: - return PlayerState.paused; + return AudioPlaybackState.paused; case ap.PlayerState.stopped: - return PlayerState.stopped; + return AudioPlaybackState.stopped; case ap.PlayerState.completed: - return PlayerState.completed; + return AudioPlaybackState.completed; } } - static PlayerState fromAapPlayerState(aap.PlayerState state) { - switch (state) { - case aap.PlayerState.play: - return PlayerState.playing; - case aap.PlayerState.pause: - return PlayerState.paused; - case aap.PlayerState.stop: - return PlayerState.stopped; + static AudioPlaybackState fromJaPlayerState(ja.PlayerState state) { + if (state.playing) { + return AudioPlaybackState.playing; + } + + switch (state.processingState) { + case ja.ProcessingState.idle: + return AudioPlaybackState.stopped; + case ja.ProcessingState.ready: + return AudioPlaybackState.paused; + case ja.ProcessingState.completed: + return AudioPlaybackState.completed; + case ja.ProcessingState.loading: + case ja.ProcessingState.buffering: + return AudioPlaybackState.buffering; } } + // static PlayerState fromAapPlayerState(aap.PlayerState state) { + // switch (state) { + // case aap.PlayerState.play: + // return PlayerState.playing; + // case aap.PlayerState.pause: + // return PlayerState.paused; + // case aap.PlayerState.stop: + // return PlayerState.stopped; + // } + // } + ap.PlayerState get asAudioPlayerPlayerState { switch (this) { - case PlayerState.playing: + case AudioPlaybackState.playing: return ap.PlayerState.playing; - case PlayerState.paused: + case AudioPlaybackState.paused: return ap.PlayerState.paused; - case PlayerState.stopped: + case AudioPlaybackState.stopped: return ap.PlayerState.stopped; - case PlayerState.completed: + case AudioPlaybackState.completed: return ap.PlayerState.completed; - case PlayerState.buffering: + case AudioPlaybackState.buffering: return ap.PlayerState.paused; } } @@ -55,12 +73,11 @@ enum PlayerState { class SpotubeAudioPlayer { final ap.AudioPlayer? _audioPlayer; - final aap.AssetsAudioPlayer? _assetsAudioPlayer; + final ja.AudioPlayer? _justAudio; SpotubeAudioPlayer() : _audioPlayer = apSupportedPlatform ? ap.AudioPlayer() : null, - _assetsAudioPlayer = - !apSupportedPlatform ? aap.AssetsAudioPlayer.newPlayer() : null; + _justAudio = !apSupportedPlatform ? ja.AudioPlayer() : null; /// Whether the current platform supports the audioplayers plugin static final bool apSupportedPlatform = @@ -71,9 +88,9 @@ class SpotubeAudioPlayer { if (apSupportedPlatform) { return _audioPlayer!.onDurationChanged.asBroadcastStream(); } else { - return _assetsAudioPlayer!.onReadyToPlay + return _justAudio!.durationStream .where((event) => event != null) - .map((event) => event!.duration) + .map((event) => event!) .asBroadcastStream(); } } @@ -82,7 +99,7 @@ class SpotubeAudioPlayer { if (apSupportedPlatform) { return _audioPlayer!.onPositionChanged.asBroadcastStream(); } else { - return _assetsAudioPlayer!.currentPosition.asBroadcastStream(); + return _justAudio!.positionStream.asBroadcastStream(); } } @@ -91,7 +108,7 @@ class SpotubeAudioPlayer { // audioplayers doesn't have the capability to get buffered position return const Stream.empty().asBroadcastStream(); } else { - return const Stream.empty().asBroadcastStream(); + return _justAudio!.bufferedPositionStream.asBroadcastStream(); } } @@ -99,20 +116,10 @@ class SpotubeAudioPlayer { if (apSupportedPlatform) { return _audioPlayer!.onPlayerComplete.asBroadcastStream(); } else { - int lastValue = 0; - return positionStream.where( - (pos) { - final posS = pos.inSeconds; - final duration = _assetsAudioPlayer - ?.current.valueOrNull?.audio.duration.inSeconds ?? - 0; - final isComplete = - posS > 0 && duration > 0 && posS == duration && posS != lastValue; - - if (isComplete) lastValue = posS; - return isComplete; - }, - ).asBroadcastStream(); + return _justAudio!.playerStateStream + .where( + (event) => event.processingState == ja.ProcessingState.completed) + .asBroadcastStream(); } } @@ -122,7 +129,7 @@ class SpotubeAudioPlayer { return state == ap.PlayerState.playing; }).asBroadcastStream(); } else { - return _assetsAudioPlayer!.isPlaying.asBroadcastStream(); + return _justAudio!.playingStream; } } @@ -130,18 +137,24 @@ class SpotubeAudioPlayer { if (apSupportedPlatform) { return Stream.value(false).asBroadcastStream(); } else { - return _assetsAudioPlayer!.isBuffering.asBroadcastStream(); + return _justAudio!.playerStateStream + .map( + (event) => + event.processingState == ja.ProcessingState.buffering || + event.processingState == ja.ProcessingState.loading, + ) + .asBroadcastStream(); } } - Stream get playerStateStream { + Stream get playerStateStream { if (apSupportedPlatform) { return _audioPlayer!.onPlayerStateChanged - .map((state) => PlayerState.fromApPlayerState(state)) + .map((state) => AudioPlaybackState.fromApPlayerState(state)) .asBroadcastStream(); } else { - return _assetsAudioPlayer!.playerState - .map(PlayerState.fromAapPlayerState) + return _justAudio!.playerStateStream + .map(AudioPlaybackState.fromJaPlayerState) .asBroadcastStream(); } } @@ -152,7 +165,7 @@ class SpotubeAudioPlayer { if (apSupportedPlatform) { return await _audioPlayer!.getDuration(); } else { - return _assetsAudioPlayer!.current.valueOrNull?.audio.duration; + return _justAudio!.duration; } } @@ -160,7 +173,7 @@ class SpotubeAudioPlayer { if (apSupportedPlatform) { return await _audioPlayer!.getCurrentPosition(); } else { - return _assetsAudioPlayer!.currentPosition.valueOrNull; + return _justAudio!.position; } } @@ -177,7 +190,7 @@ class SpotubeAudioPlayer { if (apSupportedPlatform) { return _audioPlayer!.source != null; } else { - return _assetsAudioPlayer!.current.valueOrNull != null; + return _justAudio!.audioSource != null; } } @@ -186,7 +199,7 @@ class SpotubeAudioPlayer { if (apSupportedPlatform) { return _audioPlayer!.state == ap.PlayerState.playing; } else { - return _assetsAudioPlayer!.isPlaying.valueOrNull ?? false; + return _justAudio!.playing; } } @@ -194,7 +207,7 @@ class SpotubeAudioPlayer { if (apSupportedPlatform) { return _audioPlayer!.state == ap.PlayerState.paused; } else { - return !isPlaying && hasSource; + return !isPlaying; } } @@ -202,7 +215,7 @@ class SpotubeAudioPlayer { if (apSupportedPlatform) { return _audioPlayer!.state == ap.PlayerState.stopped; } else { - return !isPlaying && !hasSource; + return _justAudio!.processingState == ja.ProcessingState.idle; } } @@ -210,7 +223,7 @@ class SpotubeAudioPlayer { if (apSupportedPlatform) { return _audioPlayer!.state == ap.PlayerState.completed; } else { - return !isPlaying && hasSource && await position == await duration; + return _justAudio!.processingState == ja.ProcessingState.completed; } } @@ -219,7 +232,8 @@ class SpotubeAudioPlayer { // audioplayers doesn't have the capability to get buffering state return false; } else { - return _assetsAudioPlayer!.isBuffering.valueOrNull ?? false; + return _justAudio!.processingState == ja.ProcessingState.buffering || + _justAudio!.processingState == ja.ProcessingState.loading; } } @@ -232,9 +246,9 @@ class SpotubeAudioPlayer { } } else { if (url.startsWith("https")) { - return aap.Audio.network(url); + return ja.AudioSource.uri(Uri.parse(url)); } else { - return aap.Audio.file(url); + return ja.AudioSource.file(url); } } } @@ -254,54 +268,55 @@ class SpotubeAudioPlayer { if (apSupportedPlatform && urlType is ap.Source) { await _audioPlayer?.play(urlType); } else { - await _assetsAudioPlayer?.stop(); - await _assetsAudioPlayer?.open( - urlType as aap.Playable, - autoStart: true, - audioFocusStrategy: const aap.AudioFocusStrategy.request( - resumeAfterInterruption: true, - ), - loopMode: aap.LoopMode.none, - playInBackground: aap.PlayInBackground.enabled, - headPhoneStrategy: aap.HeadPhoneStrategy.pauseOnUnplugPlayOnPlug, - showNotification: false, - respectSilentMode: true, - ); + if (_justAudio?.audioSource is ja.ProgressiveAudioSource && + (_justAudio?.audioSource as ja.ProgressiveAudioSource) + .uri + .toString() == + url) { + await _justAudio?.play(); + } else { + await _justAudio?.stop(); + await _justAudio?.setAudioSource( + urlType as ja.AudioSource, + preload: true, + ); + await _justAudio?.play(); + } } } Future pause() async { await _audioPlayer?.pause(); - await _assetsAudioPlayer?.pause(); + await _justAudio?.pause(); } Future resume() async { await _audioPlayer?.resume(); - await _assetsAudioPlayer?.play(); + await _justAudio?.play(); } Future stop() async { await _audioPlayer?.stop(); - await _assetsAudioPlayer?.stop(); + await _justAudio?.stop(); } Future seek(Duration position) async { await _audioPlayer?.seek(position); - await _assetsAudioPlayer?.seek(position); + await _justAudio?.seek(position); } Future setVolume(double volume) async { await _audioPlayer?.setVolume(volume); - await _assetsAudioPlayer?.setVolume(volume); + await _justAudio?.setVolume(volume); } Future setSpeed(double speed) async { await _audioPlayer?.setPlaybackRate(speed); - await _assetsAudioPlayer?.setPlaySpeed(speed); + await _justAudio?.setSpeed(speed); } Future dispose() async { await _audioPlayer?.dispose(); - await _assetsAudioPlayer?.dispose(); + await _justAudio?.dispose(); } } diff --git a/lib/services/audio_services/linux_audio_service.dart b/lib/services/audio_services/linux_audio_service.dart index 69b914007..91ea3e6ec 100644 --- a/lib/services/audio_services/linux_audio_service.dart +++ b/lib/services/audio_services/linux_audio_service.dart @@ -62,15 +62,15 @@ class LinuxAudioService { final playerStateStream = audioPlayer.playerStateStream.listen((state) async { switch (state) { - case PlayerState.buffering: - case PlayerState.playing: + case AudioPlaybackState.buffering: + case AudioPlaybackState.playing: mpris.playbackStatus = MPRISPlaybackStatus.playing; break; - case PlayerState.paused: + case AudioPlaybackState.paused: mpris.playbackStatus = MPRISPlaybackStatus.paused; break; - case PlayerState.stopped: - case PlayerState.completed: + case AudioPlaybackState.stopped: + case AudioPlaybackState.completed: mpris.playbackStatus = MPRISPlaybackStatus.stopped; break; default: diff --git a/lib/services/audio_services/windows_audio_service.dart b/lib/services/audio_services/windows_audio_service.dart index 00dceba41..e17a0b566 100644 --- a/lib/services/audio_services/windows_audio_service.dart +++ b/lib/services/audio_services/windows_audio_service.dart @@ -42,17 +42,17 @@ class WindowsAudioService { final playerStateStream = audioPlayer.playerStateStream.listen((state) async { switch (state) { - case PlayerState.playing: + case AudioPlaybackState.playing: await smtc.setPlaybackStatus(PlaybackStatus.Playing); break; - case PlayerState.paused: + case AudioPlaybackState.paused: await smtc.setPlaybackStatus(PlaybackStatus.Paused); break; - case PlayerState.stopped: + case AudioPlaybackState.stopped: await smtc.setPlaybackStatus(PlaybackStatus.Stopped); await smtc.disableSmtc(); break; - case PlayerState.completed: + case AudioPlaybackState.completed: await smtc.setPlaybackStatus(PlaybackStatus.Changing); await smtc.disableSmtc(); break; diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index bde54f50f..03d2712f1 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,14 +5,13 @@ import FlutterMacOS import Foundation -import assets_audio_player -import assets_audio_player_web import audio_service import audio_session import audioplayers_darwin import catcher import device_info_plus import flutter_secure_storage_macos +import just_audio import local_notifier import package_info_plus import path_provider_foundation @@ -26,14 +25,13 @@ import window_manager import window_size func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - AssetsAudioPlayerPlugin.register(with: registry.registrar(forPlugin: "AssetsAudioPlayerPlugin")) - AssetsAudioPlayerWebPlugin.register(with: registry.registrar(forPlugin: "AssetsAudioPlayerWebPlugin")) AudioServicePlugin.register(with: registry.registrar(forPlugin: "AudioServicePlugin")) AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin")) CatcherPlugin.register(with: registry.registrar(forPlugin: "CatcherPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) + JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin")) LocalNotifierPlugin.register(with: registry.registrar(forPlugin: "LocalNotifierPlugin")) FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) diff --git a/pubspec.lock b/pubspec.lock index d0bffa1a9..551d109dd 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -97,23 +97,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.2" - assets_audio_player: - dependency: "direct main" - description: - path: "." - ref: "4cbd4bc4b7be8a329effbb52c5b3f5d3ab042b35" - resolved-ref: "4cbd4bc4b7be8a329effbb52c5b3f5d3ab042b35" - url: "https://github.com/mt633/Flutter-AssetsAudioPlayer" - source: git - version: "3.0.6" - assets_audio_player_web: - dependency: transitive - description: - name: assets_audio_player_web - sha256: "4575ec40033d818ff022d48f7d46e24c01bc632bd1cd36a4f8b58b38e9aa4a81" - url: "https://pub.dev" - source: hosted - version: "3.0.6" async: dependency: "direct main" description: @@ -1015,6 +998,30 @@ packages: url: "https://pub.dev" source: hosted version: "6.6.1" + just_audio: + dependency: "direct main" + description: + name: just_audio + sha256: "7e6d31508dacd01a066e3889caf6282e5f1eb60707c230203b21a83af5c55586" + url: "https://pub.dev" + source: hosted + version: "0.9.32" + just_audio_platform_interface: + dependency: transitive + description: + name: just_audio_platform_interface + sha256: eff112d5138bea3ba544b6338b1e0537a32b5e1425e4d0dc38f732771cda7c84 + url: "https://pub.dev" + source: hosted + version: "4.2.0" + just_audio_web: + dependency: transitive + description: + name: just_audio_web + sha256: "89d8db6f19f3821bb6bf908c4bfb846079afb2ab575b783d781a6bf119e3abaf" + url: "https://pub.dev" + source: hosted + version: "0.4.7" lints: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index c78d24981..ab96d9b7e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,12 +10,6 @@ environment: dependencies: args: ^2.3.2 - # Patch for the uncontrollable shadow instance of ExoPlayer running in bg - # https://github.com/florent37/Flutter-AssetsAudioPlayer/issues/765 - assets_audio_player: - git: - url: https://github.com/mt633/Flutter-AssetsAudioPlayer - ref: 4cbd4bc4b7be8a329effbb52c5b3f5d3ab042b35 async: ^2.9.0 audio_service: ^0.18.9 audio_session: ^0.1.13 @@ -61,6 +55,7 @@ dependencies: introduction_screen: ^3.0.2 json_annotation: ^4.8.0 json_serializable: ^6.6.0 + just_audio: ^0.9.32 logger: ^1.1.0 metadata_god: ^0.4.1 mime: ^1.0.2