diff --git a/annix/Cargo.lock b/annix/Cargo.lock index ea6b8ef6..651afcc6 100644 --- a/annix/Cargo.lock +++ b/annix/Cargo.lock @@ -176,12 +176,12 @@ dependencies = [ [[package]] name = "anni-player" version = "0.1.0" -source = "git+https://github.com/snylonue/anni-player?rev=2afcc8c#2afcc8c83ff5331e590e8a46c07d9be627e05f85" +source = "git+https://github.com/snylonue/anni-player?rev=9edc57a#9edc57add0c7f2674838a6a963ebf7beac91d456" dependencies = [ "anni-playback", "anni-provider", "anyhow", - "env_logger", + "env_logger 0.10.2", "log", "reqwest", "uuid", @@ -239,6 +239,7 @@ dependencies = [ "anni-repo", "anyhow", "crossbeam", + "env_logger 0.11.2", "flutter_rust_bridge", "flutter_rust_bridge_codegen", "log", @@ -249,9 +250,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.5" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" dependencies = [ "anstyle", "anstyle-parse", @@ -263,9 +264,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] name = "anstyle-parse" @@ -938,6 +939,16 @@ dependencies = [ "syn 2.0.46", ] +[[package]] +name = "env_filter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +dependencies = [ + "log", + "regex", +] + [[package]] name = "env_logger" version = "0.10.2" @@ -951,6 +962,19 @@ dependencies = [ "termcolor", ] +[[package]] +name = "env_logger" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c012a26a7f605efc424dd53697843a72be7dc86ad2d01f7814337794a12231d" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + [[package]] name = "equivalent" version = "1.0.1" diff --git a/annix/Cargo.toml b/annix/Cargo.toml index c2c24102..71ce4913 100644 --- a/annix/Cargo.toml +++ b/annix/Cargo.toml @@ -16,9 +16,10 @@ uuid = "1" crossbeam = { version = "0.8.2", features = ["crossbeam-channel"] } anyhow = "1.0.75" log = "0.4.20" +env_logger = "0.11" anni-playback = { git = "https://github.com/ProjectAnni/anni", rev = "a91695e" } -anni-player = { git = "https://github.com/snylonue/anni-player", rev = "2afcc8c" } +anni-player = { git = "https://github.com/snylonue/anni-player", rev = "9edc57a" } [build-dependencies] flutter_rust_bridge_codegen = { version = "=1.81", features = ["uuid"] } diff --git a/annix/src/api.rs b/annix/src/api.rs index 64842766..22926564 100644 --- a/annix/src/api.rs +++ b/annix/src/api.rs @@ -228,13 +228,15 @@ CREATE TABLE IF NOT EXISTS store( // Audio pub use anni_playback::types::*; -use flutter_rust_bridge::StreamSink; use flutter_rust_bridge::frb; +use flutter_rust_bridge::StreamSink; // pub use crate::player::player::Player; pub use crate::player::PlayerStateEvent; pub use anni_player::AnniPlayer; use anni_player::TypedPriorityProvider; +#[cfg(target_os = "windows")] +use once_cell::sync::OnceCell; #[frb(mirror(ProgressState))] pub struct _ProgressState { @@ -263,7 +265,8 @@ fn update_player_state_stream( pub type StreamWrapper = Arc>>>>; -// impl DartSafe for AnniPlayerWrapper {} +#[cfg(target_os = "windows")] +static LOGGER_INIT: OnceCell<()> = OnceCell::new(); pub struct AnnixPlayer { pub player: RustOpaque, @@ -272,8 +275,12 @@ pub struct AnnixPlayer { } impl AnnixPlayer { - pub fn new() -> SyncReturn { - let (player, receiver) = AnniPlayer::new(TypedPriorityProvider::new(vec![]), "./cache".into()); + pub fn new(cache_path: String) -> SyncReturn { + #[cfg(target_os = "windows")] + LOGGER_INIT.get_or_init(|| env_logger::init()); + + let (player, receiver) = + AnniPlayer::new(TypedPriorityProvider::new(vec![]), cache_path.into()); let progress = Arc::new(OnceLock::new()); let player_state = Arc::new(OnceLock::new()); @@ -320,6 +327,10 @@ impl AnnixPlayer { self.player.open_file(path) } + pub fn open(&self, identifier: String) -> anyhow::Result<()> { + self.player.open(identifier.parse()?) + } + pub fn set_volume(&self, volume: f32) { self.player.set_volume(volume); } @@ -336,6 +347,14 @@ impl AnnixPlayer { SyncReturn(self.player.player.is_playing()) } + pub fn add_provider(&self, url: String, auth: String, priority: i32) { + self.player.add_provider(url, auth, priority); + } + + pub fn clear_provider(&self) { + self.player.clear_provider(); + } + pub fn player_state_stream(&self, stream: StreamSink) { *self ._state diff --git a/annix/src/bridge_generated.io.rs b/annix/src/bridge_generated.io.rs index d9b7efc9..adc4c5ab 100644 --- a/annix/src/bridge_generated.io.rs +++ b/annix/src/bridge_generated.io.rs @@ -118,8 +118,10 @@ pub extern "C" fn wire_clear__method__LocalStore( } #[no_mangle] -pub extern "C" fn wire_new__static_method__AnnixPlayer() -> support::WireSyncReturn { - wire_new__static_method__AnnixPlayer_impl() +pub extern "C" fn wire_new__static_method__AnnixPlayer( + cache_path: *mut wire_uint_8_list, +) -> support::WireSyncReturn { + wire_new__static_method__AnnixPlayer_impl(cache_path) } #[no_mangle] @@ -141,6 +143,15 @@ pub extern "C" fn wire_open_file__method__AnnixPlayer( wire_open_file__method__AnnixPlayer_impl(port_, that, path) } +#[no_mangle] +pub extern "C" fn wire_open__method__AnnixPlayer( + port_: i64, + that: *mut wire_AnnixPlayer, + identifier: *mut wire_uint_8_list, +) { + wire_open__method__AnnixPlayer_impl(port_, that, identifier) +} + #[no_mangle] pub extern "C" fn wire_set_volume__method__AnnixPlayer( port_: i64, @@ -171,6 +182,25 @@ pub extern "C" fn wire_is_playing__method__AnnixPlayer( wire_is_playing__method__AnnixPlayer_impl(that) } +#[no_mangle] +pub extern "C" fn wire_add_provider__method__AnnixPlayer( + port_: i64, + that: *mut wire_AnnixPlayer, + url: *mut wire_uint_8_list, + auth: *mut wire_uint_8_list, + priority: i32, +) { + wire_add_provider__method__AnnixPlayer_impl(port_, that, url, auth, priority) +} + +#[no_mangle] +pub extern "C" fn wire_clear_provider__method__AnnixPlayer( + port_: i64, + that: *mut wire_AnnixPlayer, +) { + wire_clear_provider__method__AnnixPlayer_impl(port_, that) +} + #[no_mangle] pub extern "C" fn wire_player_state_stream__method__AnnixPlayer( port_: i64, diff --git a/annix/src/bridge_generated.rs b/annix/src/bridge_generated.rs index 7bc11a1f..1372ee33 100644 --- a/annix/src/bridge_generated.rs +++ b/annix/src/bridge_generated.rs @@ -299,14 +299,19 @@ fn wire_clear__method__LocalStore_impl( }, ) } -fn wire_new__static_method__AnnixPlayer_impl() -> support::WireSyncReturn { +fn wire_new__static_method__AnnixPlayer_impl( + cache_path: impl Wire2Api + UnwindSafe, +) -> support::WireSyncReturn { FLUTTER_RUST_BRIDGE_HANDLER.wrap_sync( WrapInfo { debug_name: "new__static_method__AnnixPlayer", port: None, mode: FfiCallMode::Sync, }, - move || Ok(AnnixPlayer::new()), + move || { + let api_cache_path = cache_path.wire2api(); + Ok(AnnixPlayer::new(api_cache_path)) + }, ) } fn wire_play__method__AnnixPlayer_impl( @@ -359,6 +364,24 @@ fn wire_open_file__method__AnnixPlayer_impl( }, ) } +fn wire_open__method__AnnixPlayer_impl( + port_: MessagePort, + that: impl Wire2Api + UnwindSafe, + identifier: impl Wire2Api + UnwindSafe, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, ()>( + WrapInfo { + debug_name: "open__method__AnnixPlayer", + port: Some(port_), + mode: FfiCallMode::Normal, + }, + move || { + let api_that = that.wire2api(); + let api_identifier = identifier.wire2api(); + move |task_callback| AnnixPlayer::open(&api_that, api_identifier) + }, + ) +} fn wire_set_volume__method__AnnixPlayer_impl( port_: MessagePort, that: impl Wire2Api + UnwindSafe, @@ -426,6 +449,51 @@ fn wire_is_playing__method__AnnixPlayer_impl( }, ) } +fn wire_add_provider__method__AnnixPlayer_impl( + port_: MessagePort, + that: impl Wire2Api + UnwindSafe, + url: impl Wire2Api + UnwindSafe, + auth: impl Wire2Api + UnwindSafe, + priority: impl Wire2Api + UnwindSafe, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, ()>( + WrapInfo { + debug_name: "add_provider__method__AnnixPlayer", + port: Some(port_), + mode: FfiCallMode::Normal, + }, + move || { + let api_that = that.wire2api(); + let api_url = url.wire2api(); + let api_auth = auth.wire2api(); + let api_priority = priority.wire2api(); + move |task_callback| { + Ok(AnnixPlayer::add_provider( + &api_that, + api_url, + api_auth, + api_priority, + )) + } + }, + ) +} +fn wire_clear_provider__method__AnnixPlayer_impl( + port_: MessagePort, + that: impl Wire2Api + UnwindSafe, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, ()>( + WrapInfo { + debug_name: "clear_provider__method__AnnixPlayer", + port: Some(port_), + mode: FfiCallMode::Normal, + }, + move || { + let api_that = that.wire2api(); + move |task_callback| Ok(AnnixPlayer::clear_provider(&api_that)) + }, + ) +} fn wire_player_state_stream__method__AnnixPlayer_impl( port_: MessagePort, that: impl Wire2Api + UnwindSafe, diff --git a/ios/Runner/bridge_generated.h b/ios/Runner/bridge_generated.h index 2802cffa..b650fea3 100644 --- a/ios/Runner/bridge_generated.h +++ b/ios/Runner/bridge_generated.h @@ -113,7 +113,7 @@ void wire_clear__method__LocalStore(int64_t port_, struct wire_LocalStore *that, struct wire_uint_8_list *category); -WireSyncReturn wire_new__static_method__AnnixPlayer(void); +WireSyncReturn wire_new__static_method__AnnixPlayer(struct wire_uint_8_list *cache_path); void wire_play__method__AnnixPlayer(int64_t port_, struct wire_AnnixPlayer *that); @@ -123,6 +123,10 @@ void wire_open_file__method__AnnixPlayer(int64_t port_, struct wire_AnnixPlayer *that, struct wire_uint_8_list *path); +void wire_open__method__AnnixPlayer(int64_t port_, + struct wire_AnnixPlayer *that, + struct wire_uint_8_list *identifier); + void wire_set_volume__method__AnnixPlayer(int64_t port_, struct wire_AnnixPlayer *that, float volume); @@ -135,6 +139,14 @@ void wire_seek__method__AnnixPlayer(int64_t port_, WireSyncReturn wire_is_playing__method__AnnixPlayer(struct wire_AnnixPlayer *that); +void wire_add_provider__method__AnnixPlayer(int64_t port_, + struct wire_AnnixPlayer *that, + struct wire_uint_8_list *url, + struct wire_uint_8_list *auth, + int32_t priority); + +void wire_clear_provider__method__AnnixPlayer(int64_t port_, struct wire_AnnixPlayer *that); + void wire_player_state_stream__method__AnnixPlayer(int64_t port_, struct wire_AnnixPlayer *that); void wire_progress_stream__method__AnnixPlayer(int64_t port_, struct wire_AnnixPlayer *that); @@ -202,10 +214,13 @@ static int64_t dummy_method_to_enforce_bundling(void) { dummy_var ^= ((int64_t) (void*) wire_play__method__AnnixPlayer); dummy_var ^= ((int64_t) (void*) wire_pause__method__AnnixPlayer); dummy_var ^= ((int64_t) (void*) wire_open_file__method__AnnixPlayer); + dummy_var ^= ((int64_t) (void*) wire_open__method__AnnixPlayer); dummy_var ^= ((int64_t) (void*) wire_set_volume__method__AnnixPlayer); dummy_var ^= ((int64_t) (void*) wire_stop__method__AnnixPlayer); dummy_var ^= ((int64_t) (void*) wire_seek__method__AnnixPlayer); dummy_var ^= ((int64_t) (void*) wire_is_playing__method__AnnixPlayer); + dummy_var ^= ((int64_t) (void*) wire_add_provider__method__AnnixPlayer); + dummy_var ^= ((int64_t) (void*) wire_clear_provider__method__AnnixPlayer); dummy_var ^= ((int64_t) (void*) wire_player_state_stream__method__AnnixPlayer); dummy_var ^= ((int64_t) (void*) wire_progress_stream__method__AnnixPlayer); dummy_var ^= ((int64_t) (void*) new_AnniPlayer); diff --git a/lib/bridge/bridge_definitions.dart b/lib/bridge/bridge_definitions.dart index d4f37d68..ec2ed21f 100644 --- a/lib/bridge/bridge_definitions.dart +++ b/lib/bridge/bridge_definitions.dart @@ -74,7 +74,7 @@ abstract class AnnixNative { FlutterRustBridgeTaskConstMeta get kClearMethodLocalStoreConstMeta; - AnnixPlayer newStaticMethodAnnixPlayer({dynamic hint}); + AnnixPlayer newStaticMethodAnnixPlayer({required String cachePath, dynamic hint}); FlutterRustBridgeTaskConstMeta get kNewStaticMethodAnnixPlayerConstMeta; @@ -90,6 +90,10 @@ abstract class AnnixNative { FlutterRustBridgeTaskConstMeta get kOpenFileMethodAnnixPlayerConstMeta; + Future openMethodAnnixPlayer({required AnnixPlayer that, required String identifier, dynamic hint}); + + FlutterRustBridgeTaskConstMeta get kOpenMethodAnnixPlayerConstMeta; + Future setVolumeMethodAnnixPlayer({required AnnixPlayer that, required double volume, dynamic hint}); FlutterRustBridgeTaskConstMeta get kSetVolumeMethodAnnixPlayerConstMeta; @@ -106,6 +110,15 @@ abstract class AnnixNative { FlutterRustBridgeTaskConstMeta get kIsPlayingMethodAnnixPlayerConstMeta; + Future addProviderMethodAnnixPlayer( + {required AnnixPlayer that, required String url, required String auth, required int priority, dynamic hint}); + + FlutterRustBridgeTaskConstMeta get kAddProviderMethodAnnixPlayerConstMeta; + + Future clearProviderMethodAnnixPlayer({required AnnixPlayer that, dynamic hint}); + + FlutterRustBridgeTaskConstMeta get kClearProviderMethodAnnixPlayerConstMeta; + Stream playerStateStreamMethodAnnixPlayer({required AnnixPlayer that, dynamic hint}); FlutterRustBridgeTaskConstMeta get kPlayerStateStreamMethodAnnixPlayerConstMeta; @@ -114,6 +127,10 @@ abstract class AnnixNative { FlutterRustBridgeTaskConstMeta get kProgressStreamMethodAnnixPlayerConstMeta; + DropFnType get dropOpaqueAnniPlayer; + ShareFnType get shareOpaqueAnniPlayer; + OpaqueTypeFinalizer get AnniPlayerFinalizer; + DropFnType get dropOpaqueMutexConnection; ShareFnType get shareOpaqueMutexConnection; OpaqueTypeFinalizer get MutexConnectionFinalizer; @@ -122,10 +139,6 @@ abstract class AnnixNative { ShareFnType get shareOpaqueMutexRepoDatabaseRead; OpaqueTypeFinalizer get MutexRepoDatabaseReadFinalizer; - DropFnType get dropOpaquePlayer; - ShareFnType get shareOpaquePlayer; - OpaqueTypeFinalizer get PlayerFinalizer; - DropFnType get dropOpaqueStreamWrapperPlayerStateEvent; ShareFnType get shareOpaqueStreamWrapperPlayerStateEvent; OpaqueTypeFinalizer get StreamWrapperPlayerStateEventFinalizer; @@ -135,6 +148,20 @@ abstract class AnnixNative { OpaqueTypeFinalizer get StreamWrapperProgressStateFinalizer; } +@sealed +class AnniPlayer extends FrbOpaque { + final AnnixNative bridge; + AnniPlayer.fromRaw(int ptr, int size, this.bridge) : super.unsafe(ptr, size); + @override + DropFnType get dropFn => bridge.dropOpaqueAnniPlayer; + + @override + ShareFnType get shareFn => bridge.shareOpaqueAnniPlayer; + + @override + OpaqueTypeFinalizer get staticFinalizer => bridge.AnniPlayerFinalizer; +} + @sealed class MutexConnection extends FrbOpaque { final AnnixNative bridge; @@ -163,20 +190,6 @@ class MutexRepoDatabaseRead extends FrbOpaque { OpaqueTypeFinalizer get staticFinalizer => bridge.MutexRepoDatabaseReadFinalizer; } -@sealed -class Player extends FrbOpaque { - final AnnixNative bridge; - Player.fromRaw(int ptr, int size, this.bridge) : super.unsafe(ptr, size); - @override - DropFnType get dropFn => bridge.dropOpaquePlayer; - - @override - ShareFnType get shareFn => bridge.shareOpaquePlayer; - - @override - OpaqueTypeFinalizer get staticFinalizer => bridge.PlayerFinalizer; -} - @sealed class StreamWrapperPlayerStateEvent extends FrbOpaque { final AnnixNative bridge; @@ -207,7 +220,7 @@ class StreamWrapperProgressState extends FrbOpaque { class AnnixPlayer { final AnnixNative bridge; - final Player player; + final AnniPlayer player; final StreamWrapperPlayerStateEvent state; final StreamWrapperProgressState progress; @@ -218,8 +231,8 @@ class AnnixPlayer { required this.progress, }); - static AnnixPlayer newAnnixPlayer({required AnnixNative bridge, dynamic hint}) => - bridge.newStaticMethodAnnixPlayer(hint: hint); + static AnnixPlayer newAnnixPlayer({required AnnixNative bridge, required String cachePath, dynamic hint}) => + bridge.newStaticMethodAnnixPlayer(cachePath: cachePath, hint: hint); Future play({dynamic hint}) => bridge.playMethodAnnixPlayer( that: this, @@ -234,6 +247,11 @@ class AnnixPlayer { path: path, ); + Future open({required String identifier, dynamic hint}) => bridge.openMethodAnnixPlayer( + that: this, + identifier: identifier, + ); + Future setVolume({required double volume, dynamic hint}) => bridge.setVolumeMethodAnnixPlayer( that: this, volume: volume, @@ -252,6 +270,18 @@ class AnnixPlayer { that: this, ); + Future addProvider({required String url, required String auth, required int priority, dynamic hint}) => + bridge.addProviderMethodAnnixPlayer( + that: this, + url: url, + auth: auth, + priority: priority, + ); + + Future clearProvider({dynamic hint}) => bridge.clearProviderMethodAnnixPlayer( + that: this, + ); + Stream playerStateStream({dynamic hint}) => bridge.playerStateStreamMethodAnnixPlayer( that: this, ); diff --git a/lib/bridge/bridge_generated.dart b/lib/bridge/bridge_generated.dart index c21c8faa..b368169b 100644 --- a/lib/bridge/bridge_generated.dart +++ b/lib/bridge/bridge_generated.dart @@ -286,19 +286,20 @@ class AnnixNativeImpl implements AnnixNative { argNames: ["that", "category"], ); - AnnixPlayer newStaticMethodAnnixPlayer({dynamic hint}) { + AnnixPlayer newStaticMethodAnnixPlayer({required String cachePath, dynamic hint}) { + var arg0 = _platform.api2wire_String(cachePath); return _platform.executeSync(FlutterRustBridgeSyncTask( - callFfi: () => _platform.inner.wire_new__static_method__AnnixPlayer(), + callFfi: () => _platform.inner.wire_new__static_method__AnnixPlayer(arg0), parseSuccessData: _wire2api_annix_player, constMeta: kNewStaticMethodAnnixPlayerConstMeta, - argValues: [], + argValues: [cachePath], hint: hint, )); } FlutterRustBridgeTaskConstMeta get kNewStaticMethodAnnixPlayerConstMeta => const FlutterRustBridgeTaskConstMeta( debugName: "new__static_method__AnnixPlayer", - argNames: [], + argNames: ["cachePath"], ); Future playMethodAnnixPlayer({required AnnixPlayer that, dynamic hint}) { @@ -350,6 +351,23 @@ class AnnixNativeImpl implements AnnixNative { argNames: ["that", "path"], ); + Future openMethodAnnixPlayer({required AnnixPlayer that, required String identifier, dynamic hint}) { + var arg0 = _platform.api2wire_box_autoadd_annix_player(that); + var arg1 = _platform.api2wire_String(identifier); + return _platform.executeNormal(FlutterRustBridgeTask( + callFfi: (port_) => _platform.inner.wire_open__method__AnnixPlayer(port_, arg0, arg1), + parseSuccessData: _wire2api_unit, + constMeta: kOpenMethodAnnixPlayerConstMeta, + argValues: [that, identifier], + hint: hint, + )); + } + + FlutterRustBridgeTaskConstMeta get kOpenMethodAnnixPlayerConstMeta => const FlutterRustBridgeTaskConstMeta( + debugName: "open__method__AnnixPlayer", + argNames: ["that", "identifier"], + ); + Future setVolumeMethodAnnixPlayer({required AnnixPlayer that, required double volume, dynamic hint}) { var arg0 = _platform.api2wire_box_autoadd_annix_player(that); var arg1 = api2wire_f32(volume); @@ -416,6 +434,42 @@ class AnnixNativeImpl implements AnnixNative { argNames: ["that"], ); + Future addProviderMethodAnnixPlayer( + {required AnnixPlayer that, required String url, required String auth, required int priority, dynamic hint}) { + var arg0 = _platform.api2wire_box_autoadd_annix_player(that); + var arg1 = _platform.api2wire_String(url); + var arg2 = _platform.api2wire_String(auth); + var arg3 = api2wire_i32(priority); + return _platform.executeNormal(FlutterRustBridgeTask( + callFfi: (port_) => _platform.inner.wire_add_provider__method__AnnixPlayer(port_, arg0, arg1, arg2, arg3), + parseSuccessData: _wire2api_unit, + constMeta: kAddProviderMethodAnnixPlayerConstMeta, + argValues: [that, url, auth, priority], + hint: hint, + )); + } + + FlutterRustBridgeTaskConstMeta get kAddProviderMethodAnnixPlayerConstMeta => const FlutterRustBridgeTaskConstMeta( + debugName: "add_provider__method__AnnixPlayer", + argNames: ["that", "url", "auth", "priority"], + ); + + Future clearProviderMethodAnnixPlayer({required AnnixPlayer that, dynamic hint}) { + var arg0 = _platform.api2wire_box_autoadd_annix_player(that); + return _platform.executeNormal(FlutterRustBridgeTask( + callFfi: (port_) => _platform.inner.wire_clear_provider__method__AnnixPlayer(port_, arg0), + parseSuccessData: _wire2api_unit, + constMeta: kClearProviderMethodAnnixPlayerConstMeta, + argValues: [that], + hint: hint, + )); + } + + FlutterRustBridgeTaskConstMeta get kClearProviderMethodAnnixPlayerConstMeta => const FlutterRustBridgeTaskConstMeta( + debugName: "clear_provider__method__AnnixPlayer", + argNames: ["that"], + ); + Stream playerStateStreamMethodAnnixPlayer({required AnnixPlayer that, dynamic hint}) { var arg0 = _platform.api2wire_box_autoadd_annix_player(that); return _platform.executeStream(FlutterRustBridgeTask( @@ -449,6 +503,10 @@ class AnnixNativeImpl implements AnnixNative { argNames: ["that"], ); + DropFnType get dropOpaqueAnniPlayer => _platform.inner.drop_opaque_AnniPlayer; + ShareFnType get shareOpaqueAnniPlayer => _platform.inner.share_opaque_AnniPlayer; + OpaqueTypeFinalizer get AnniPlayerFinalizer => _platform.AnniPlayerFinalizer; + DropFnType get dropOpaqueMutexConnection => _platform.inner.drop_opaque_MutexConnection; ShareFnType get shareOpaqueMutexConnection => _platform.inner.share_opaque_MutexConnection; OpaqueTypeFinalizer get MutexConnectionFinalizer => _platform.MutexConnectionFinalizer; @@ -457,10 +515,6 @@ class AnnixNativeImpl implements AnnixNative { ShareFnType get shareOpaqueMutexRepoDatabaseRead => _platform.inner.share_opaque_MutexRepoDatabaseRead; OpaqueTypeFinalizer get MutexRepoDatabaseReadFinalizer => _platform.MutexRepoDatabaseReadFinalizer; - DropFnType get dropOpaquePlayer => _platform.inner.drop_opaque_Player; - ShareFnType get shareOpaquePlayer => _platform.inner.share_opaque_Player; - OpaqueTypeFinalizer get PlayerFinalizer => _platform.PlayerFinalizer; - DropFnType get dropOpaqueStreamWrapperPlayerStateEvent => _platform.inner.drop_opaque_StreamWrapperPlayerStateEvent; ShareFnType get shareOpaqueStreamWrapperPlayerStateEvent => _platform.inner.share_opaque_StreamWrapperPlayerStateEvent; @@ -475,6 +529,10 @@ class AnnixNativeImpl implements AnnixNative { } // Section: wire2api + AnniPlayer _wire2api_AnniPlayer(dynamic raw) { + return AnniPlayer.fromRaw(raw[0], raw[1], this); + } + MutexConnection _wire2api_MutexConnection(dynamic raw) { return MutexConnection.fromRaw(raw[0], raw[1], this); } @@ -483,10 +541,6 @@ class AnnixNativeImpl implements AnnixNative { return MutexRepoDatabaseRead.fromRaw(raw[0], raw[1], this); } - Player _wire2api_Player(dynamic raw) { - return Player.fromRaw(raw[0], raw[1], this); - } - StreamWrapperPlayerStateEvent _wire2api_StreamWrapperPlayerStateEvent(dynamic raw) { return StreamWrapperPlayerStateEvent.fromRaw(raw[0], raw[1], this); } @@ -513,7 +567,7 @@ class AnnixNativeImpl implements AnnixNative { if (arr.length != 3) throw Exception('unexpected arr length: expect 3 but see ${arr.length}'); return AnnixPlayer( bridge: this, - player: _wire2api_Player(arr[0]), + player: _wire2api_AnniPlayer(arr[0]), state: _wire2api_StreamWrapperPlayerStateEvent(arr[1]), progress: _wire2api_StreamWrapperProgressState(arr[2]), ); @@ -635,6 +689,13 @@ class AnnixNativePlatform extends FlutterRustBridgeBase { // Section: api2wire + @protected + wire_AnniPlayer api2wire_AnniPlayer(AnniPlayer raw) { + final ptr = inner.new_AnniPlayer(); + _api_fill_to_wire_AnniPlayer(raw, ptr); + return ptr; + } + @protected wire_MutexConnection api2wire_MutexConnection(MutexConnection raw) { final ptr = inner.new_MutexConnection(); @@ -649,13 +710,6 @@ class AnnixNativePlatform extends FlutterRustBridgeBase { return ptr; } - @protected - wire_Player api2wire_Player(Player raw) { - final ptr = inner.new_Player(); - _api_fill_to_wire_Player(raw, ptr); - return ptr; - } - @protected wire_StreamWrapperPlayerStateEvent api2wire_StreamWrapperPlayerStateEvent(StreamWrapperPlayerStateEvent raw) { final ptr = inner.new_StreamWrapperPlayerStateEvent(); @@ -726,13 +780,13 @@ class AnnixNativePlatform extends FlutterRustBridgeBase { } // Section: finalizer + late final OpaqueTypeFinalizer _AnniPlayerFinalizer = OpaqueTypeFinalizer(inner._drop_opaque_AnniPlayerPtr); + OpaqueTypeFinalizer get AnniPlayerFinalizer => _AnniPlayerFinalizer; late final OpaqueTypeFinalizer _MutexConnectionFinalizer = OpaqueTypeFinalizer(inner._drop_opaque_MutexConnectionPtr); OpaqueTypeFinalizer get MutexConnectionFinalizer => _MutexConnectionFinalizer; late final OpaqueTypeFinalizer _MutexRepoDatabaseReadFinalizer = OpaqueTypeFinalizer(inner._drop_opaque_MutexRepoDatabaseReadPtr); OpaqueTypeFinalizer get MutexRepoDatabaseReadFinalizer => _MutexRepoDatabaseReadFinalizer; - late final OpaqueTypeFinalizer _PlayerFinalizer = OpaqueTypeFinalizer(inner._drop_opaque_PlayerPtr); - OpaqueTypeFinalizer get PlayerFinalizer => _PlayerFinalizer; late final OpaqueTypeFinalizer _StreamWrapperPlayerStateEventFinalizer = OpaqueTypeFinalizer(inner._drop_opaque_StreamWrapperPlayerStateEventPtr); OpaqueTypeFinalizer get StreamWrapperPlayerStateEventFinalizer => _StreamWrapperPlayerStateEventFinalizer; @@ -741,15 +795,15 @@ class AnnixNativePlatform extends FlutterRustBridgeBase { OpaqueTypeFinalizer get StreamWrapperProgressStateFinalizer => _StreamWrapperProgressStateFinalizer; // Section: api_fill_to_wire - void _api_fill_to_wire_MutexConnection(MutexConnection apiObj, wire_MutexConnection wireObj) { + void _api_fill_to_wire_AnniPlayer(AnniPlayer apiObj, wire_AnniPlayer wireObj) { wireObj.ptr = apiObj.shareOrMove(); } - void _api_fill_to_wire_MutexRepoDatabaseRead(MutexRepoDatabaseRead apiObj, wire_MutexRepoDatabaseRead wireObj) { + void _api_fill_to_wire_MutexConnection(MutexConnection apiObj, wire_MutexConnection wireObj) { wireObj.ptr = apiObj.shareOrMove(); } - void _api_fill_to_wire_Player(Player apiObj, wire_Player wireObj) { + void _api_fill_to_wire_MutexRepoDatabaseRead(MutexRepoDatabaseRead apiObj, wire_MutexRepoDatabaseRead wireObj) { wireObj.ptr = apiObj.shareOrMove(); } @@ -764,7 +818,7 @@ class AnnixNativePlatform extends FlutterRustBridgeBase { } void _api_fill_to_wire_annix_player(AnnixPlayer apiObj, wire_AnnixPlayer wireObj) { - wireObj.player = api2wire_Player(apiObj.player); + wireObj.player = api2wire_AnniPlayer(apiObj.player); wireObj._state = api2wire_StreamWrapperPlayerStateEvent(apiObj.state); wireObj._progress = api2wire_StreamWrapperProgressState(apiObj.progress); } @@ -1141,14 +1195,19 @@ class AnnixNativeWire implements FlutterRustBridgeWireBase { late final _wire_clear__method__LocalStore = _wire_clear__method__LocalStorePtr .asFunction, ffi.Pointer)>(); - WireSyncReturn wire_new__static_method__AnnixPlayer() { - return _wire_new__static_method__AnnixPlayer(); + WireSyncReturn wire_new__static_method__AnnixPlayer( + ffi.Pointer cache_path, + ) { + return _wire_new__static_method__AnnixPlayer( + cache_path, + ); } late final _wire_new__static_method__AnnixPlayerPtr = - _lookup>('wire_new__static_method__AnnixPlayer'); + _lookup)>>( + 'wire_new__static_method__AnnixPlayer'); late final _wire_new__static_method__AnnixPlayer = - _wire_new__static_method__AnnixPlayerPtr.asFunction(); + _wire_new__static_method__AnnixPlayerPtr.asFunction)>(); void wire_play__method__AnnixPlayer( int port_, @@ -1201,6 +1260,25 @@ class AnnixNativeWire implements FlutterRustBridgeWireBase { late final _wire_open_file__method__AnnixPlayer = _wire_open_file__method__AnnixPlayerPtr .asFunction, ffi.Pointer)>(); + void wire_open__method__AnnixPlayer( + int port_, + ffi.Pointer that, + ffi.Pointer identifier, + ) { + return _wire_open__method__AnnixPlayer( + port_, + that, + identifier, + ); + } + + late final _wire_open__method__AnnixPlayerPtr = _lookup< + ffi + .NativeFunction, ffi.Pointer)>>( + 'wire_open__method__AnnixPlayer'); + late final _wire_open__method__AnnixPlayer = _wire_open__method__AnnixPlayerPtr + .asFunction, ffi.Pointer)>(); + void wire_set_volume__method__AnnixPlayer( int port_, ffi.Pointer that, @@ -1267,6 +1345,46 @@ class AnnixNativeWire implements FlutterRustBridgeWireBase { late final _wire_is_playing__method__AnnixPlayer = _wire_is_playing__method__AnnixPlayerPtr.asFunction)>(); + void wire_add_provider__method__AnnixPlayer( + int port_, + ffi.Pointer that, + ffi.Pointer url, + ffi.Pointer auth, + int priority, + ) { + return _wire_add_provider__method__AnnixPlayer( + port_, + that, + url, + auth, + priority, + ); + } + + late final _wire_add_provider__method__AnnixPlayerPtr = _lookup< + ffi.NativeFunction< + ffi.Void Function(ffi.Int64, ffi.Pointer, ffi.Pointer, + ffi.Pointer, ffi.Int32)>>('wire_add_provider__method__AnnixPlayer'); + late final _wire_add_provider__method__AnnixPlayer = _wire_add_provider__method__AnnixPlayerPtr.asFunction< + void Function( + int, ffi.Pointer, ffi.Pointer, ffi.Pointer, int)>(); + + void wire_clear_provider__method__AnnixPlayer( + int port_, + ffi.Pointer that, + ) { + return _wire_clear_provider__method__AnnixPlayer( + port_, + that, + ); + } + + late final _wire_clear_provider__method__AnnixPlayerPtr = + _lookup)>>( + 'wire_clear_provider__method__AnnixPlayer'); + late final _wire_clear_provider__method__AnnixPlayer = + _wire_clear_provider__method__AnnixPlayerPtr.asFunction)>(); + void wire_player_state_stream__method__AnnixPlayer( int port_, ffi.Pointer that, @@ -1299,6 +1417,13 @@ class AnnixNativeWire implements FlutterRustBridgeWireBase { late final _wire_progress_stream__method__AnnixPlayer = _wire_progress_stream__method__AnnixPlayerPtr.asFunction)>(); + wire_AnniPlayer new_AnniPlayer() { + return _new_AnniPlayer(); + } + + late final _new_AnniPlayerPtr = _lookup>('new_AnniPlayer'); + late final _new_AnniPlayer = _new_AnniPlayerPtr.asFunction(); + wire_MutexConnection new_MutexConnection() { return _new_MutexConnection(); } @@ -1316,13 +1441,6 @@ class AnnixNativeWire implements FlutterRustBridgeWireBase { late final _new_MutexRepoDatabaseRead = _new_MutexRepoDatabaseReadPtr.asFunction(); - wire_Player new_Player() { - return _new_Player(); - } - - late final _new_PlayerPtr = _lookup>('new_Player'); - late final _new_Player = _new_PlayerPtr.asFunction(); - wire_StreamWrapperPlayerStateEvent new_StreamWrapperPlayerStateEvent() { return _new_StreamWrapperPlayerStateEvent(); } @@ -1390,6 +1508,31 @@ class AnnixNativeWire implements FlutterRustBridgeWireBase { _lookup Function(ffi.Int32)>>('new_uint_8_list_0'); late final _new_uint_8_list_0 = _new_uint_8_list_0Ptr.asFunction Function(int)>(); + void drop_opaque_AnniPlayer( + ffi.Pointer ptr, + ) { + return _drop_opaque_AnniPlayer( + ptr, + ); + } + + late final _drop_opaque_AnniPlayerPtr = + _lookup)>>('drop_opaque_AnniPlayer'); + late final _drop_opaque_AnniPlayer = _drop_opaque_AnniPlayerPtr.asFunction)>(); + + ffi.Pointer share_opaque_AnniPlayer( + ffi.Pointer ptr, + ) { + return _share_opaque_AnniPlayer( + ptr, + ); + } + + late final _share_opaque_AnniPlayerPtr = + _lookup Function(ffi.Pointer)>>('share_opaque_AnniPlayer'); + late final _share_opaque_AnniPlayer = + _share_opaque_AnniPlayerPtr.asFunction Function(ffi.Pointer)>(); + void drop_opaque_MutexConnection( ffi.Pointer ptr, ) { @@ -1444,31 +1587,6 @@ class AnnixNativeWire implements FlutterRustBridgeWireBase { late final _share_opaque_MutexRepoDatabaseRead = _share_opaque_MutexRepoDatabaseReadPtr.asFunction Function(ffi.Pointer)>(); - void drop_opaque_Player( - ffi.Pointer ptr, - ) { - return _drop_opaque_Player( - ptr, - ); - } - - late final _drop_opaque_PlayerPtr = - _lookup)>>('drop_opaque_Player'); - late final _drop_opaque_Player = _drop_opaque_PlayerPtr.asFunction)>(); - - ffi.Pointer share_opaque_Player( - ffi.Pointer ptr, - ) { - return _share_opaque_Player( - ptr, - ); - } - - late final _share_opaque_PlayerPtr = - _lookup Function(ffi.Pointer)>>('share_opaque_Player'); - late final _share_opaque_Player = - _share_opaque_PlayerPtr.asFunction Function(ffi.Pointer)>(); - void drop_opaque_StreamWrapperPlayerStateEvent( ffi.Pointer ptr, ) { @@ -1566,7 +1684,7 @@ final class wire_LocalStore extends ffi.Struct { external wire_MutexConnection conn; } -final class wire_Player extends ffi.Struct { +final class wire_AnniPlayer extends ffi.Struct { external ffi.Pointer ptr; } @@ -1579,7 +1697,7 @@ final class wire_StreamWrapperProgressState extends ffi.Struct { } final class wire_AnnixPlayer extends ffi.Struct { - external wire_Player player; + external wire_AnniPlayer player; external wire_StreamWrapperPlayerStateEvent _state; diff --git a/lib/services/path.dart b/lib/services/path.dart index f2570f1a..663d6227 100644 --- a/lib/services/path.dart +++ b/lib/services/path.dart @@ -41,4 +41,5 @@ class PathService { String localDbPath() => p.join(PathService.dataRoot, 'local.db'); String audioCachePath() => p.join(PathService.storageRoot, 'audio'); +String playerCachePath() => p.join(PathService.storageRoot, 'audio_cache'); String coverCachePath() => p.join(PathService.storageRoot, 'cover'); diff --git a/lib/services/playback/playback_service.dart b/lib/services/playback/playback_service.dart index 81f115c3..8ee35d36 100644 --- a/lib/services/playback/playback_service.dart +++ b/lib/services/playback/playback_service.dart @@ -8,6 +8,7 @@ import 'package:annix/services/annil/annil.dart'; import 'package:annix/services/anniv/anniv.dart'; import 'package:annix/services/anniv/anniv_model.dart'; import 'package:annix/services/metadata/metadata_model.dart'; +import 'package:annix/services/path.dart'; import 'package:annix/services/playback/playback.dart'; import 'package:annix/ui/widgets/utils/property_value_notifier.dart'; import 'package:audio_session/audio_session.dart' hide AVAudioSessionCategory; @@ -41,7 +42,7 @@ void playFullList({ } class PlaybackService extends ChangeNotifier { - static final AnnixPlayer player = api.newStaticMethodAnnixPlayer(); + static final AnnixPlayer player = api.newStaticMethodAnnixPlayer(cachePath: playerCachePath()); // TODO: cache this map static final PropertyValueNotifier> durationMap = @@ -128,6 +129,16 @@ class PlaybackService extends ChangeNotifier { WidgetsBinding.instance.addPostFrameCallback((final _) => play(reload: true, setSourceOnly: true, trackPlayback: false)); + + final db = ref.read(localDatabaseProvider); + final annilServersStream = db.sortedAnnilServers().watch(); + annilServersStream.listen((servers) { + PlaybackService.player.clearProvider(); + for (final server in servers) { + PlaybackService.player.addProvider( + url: server.url, auth: server.token, priority: server.priority); + } + }); } Future play({ @@ -166,7 +177,6 @@ class PlaybackService extends ChangeNotifier { await stop(); return; } - final currentIndex = playingIndex!; // stop previous playback FLog.trace(text: 'Start playing'); @@ -184,46 +194,7 @@ class PlaybackService extends ChangeNotifier { } } - final toPlayId = source.id; - if (!source.preloaded) { - // current track is not preloaded, buffering - playerStatus = PlayerStatus.buffering; - notifyListeners(); - } - - // preload the next track - if (queue.length > currentIndex + 1) { - queue[currentIndex + 1].preload(ref); - } - - try { - source.preload(ref); - // wait for audio file to download and play it - source.setOnPlayer(PlaybackService.player); - if (setSourceOnly) { - loadedAndPaused = true; - } else { - await PlaybackService.player.play(); - } - } catch (e) { - if (e is AudioCancelledError) { - return; - } - - // TODO: tell user why paused - FLog.error(text: 'Failed to play', exception: e); - await pause(); - } - - // when playback starts, set state to playing - if (playing.id == toPlayId && playerStatus == PlayerStatus.buffering) { - if (setSourceOnly) { - playerStatus = PlayerStatus.paused; - } else { - playerStatus = PlayerStatus.playing; - } - notifyListeners(); - } + PlaybackService.player.open(identifier: source.identifier.toString()); } Future pause() async { diff --git a/macos/Runner/bridge_generated.h b/macos/Runner/bridge_generated.h index 2802cffa..b650fea3 100644 --- a/macos/Runner/bridge_generated.h +++ b/macos/Runner/bridge_generated.h @@ -113,7 +113,7 @@ void wire_clear__method__LocalStore(int64_t port_, struct wire_LocalStore *that, struct wire_uint_8_list *category); -WireSyncReturn wire_new__static_method__AnnixPlayer(void); +WireSyncReturn wire_new__static_method__AnnixPlayer(struct wire_uint_8_list *cache_path); void wire_play__method__AnnixPlayer(int64_t port_, struct wire_AnnixPlayer *that); @@ -123,6 +123,10 @@ void wire_open_file__method__AnnixPlayer(int64_t port_, struct wire_AnnixPlayer *that, struct wire_uint_8_list *path); +void wire_open__method__AnnixPlayer(int64_t port_, + struct wire_AnnixPlayer *that, + struct wire_uint_8_list *identifier); + void wire_set_volume__method__AnnixPlayer(int64_t port_, struct wire_AnnixPlayer *that, float volume); @@ -135,6 +139,14 @@ void wire_seek__method__AnnixPlayer(int64_t port_, WireSyncReturn wire_is_playing__method__AnnixPlayer(struct wire_AnnixPlayer *that); +void wire_add_provider__method__AnnixPlayer(int64_t port_, + struct wire_AnnixPlayer *that, + struct wire_uint_8_list *url, + struct wire_uint_8_list *auth, + int32_t priority); + +void wire_clear_provider__method__AnnixPlayer(int64_t port_, struct wire_AnnixPlayer *that); + void wire_player_state_stream__method__AnnixPlayer(int64_t port_, struct wire_AnnixPlayer *that); void wire_progress_stream__method__AnnixPlayer(int64_t port_, struct wire_AnnixPlayer *that); @@ -202,10 +214,13 @@ static int64_t dummy_method_to_enforce_bundling(void) { dummy_var ^= ((int64_t) (void*) wire_play__method__AnnixPlayer); dummy_var ^= ((int64_t) (void*) wire_pause__method__AnnixPlayer); dummy_var ^= ((int64_t) (void*) wire_open_file__method__AnnixPlayer); + dummy_var ^= ((int64_t) (void*) wire_open__method__AnnixPlayer); dummy_var ^= ((int64_t) (void*) wire_set_volume__method__AnnixPlayer); dummy_var ^= ((int64_t) (void*) wire_stop__method__AnnixPlayer); dummy_var ^= ((int64_t) (void*) wire_seek__method__AnnixPlayer); dummy_var ^= ((int64_t) (void*) wire_is_playing__method__AnnixPlayer); + dummy_var ^= ((int64_t) (void*) wire_add_provider__method__AnnixPlayer); + dummy_var ^= ((int64_t) (void*) wire_clear_provider__method__AnnixPlayer); dummy_var ^= ((int64_t) (void*) wire_player_state_stream__method__AnnixPlayer); dummy_var ^= ((int64_t) (void*) wire_progress_stream__method__AnnixPlayer); dummy_var ^= ((int64_t) (void*) new_AnniPlayer);