From 7e193fb2300cf9d6d3de2fc5a0d20d7109f1d12a Mon Sep 17 00:00:00 2001 From: Eric Coissac Date: Sun, 5 Oct 2025 20:34:04 +0200 Subject: [PATCH] Je laisse Claude faire ses modification sur avtransport --- .../actions/getcurrenttransportactions.rs | 8 ++ .../mediarenderer/avtransport/actions/mod.rs | 2 + pmoupnp/src/mediarenderer/avtransport/mod.rs | 133 +++++++++++++++++- .../variables/a_arg_type_seekmode.rs | 6 +- .../variables/currentmediaduration.rs | 10 ++ .../avtransport/variables/currentplaymode.rs | 24 ++++ .../variables/currenttrackmetadata.rs | 10 ++ .../avtransport/variables/currenttrackuri.rs | 10 ++ .../avtransport/variables/mod.rs | 22 ++- .../variables/playbackstoragemedium.rs | 28 ++++ .../variables/possibleplaybackstoragemedia.rs | 10 ++ .../variables/possiblerecordstoragemedia.rs | 10 ++ .../variables/recordstoragemedium.rs | 10 ++ .../avtransport/variables/transportstate.rs | 11 +- 14 files changed, 277 insertions(+), 17 deletions(-) create mode 100644 pmoupnp/src/mediarenderer/avtransport/actions/getcurrenttransportactions.rs create mode 100644 pmoupnp/src/mediarenderer/avtransport/variables/currentmediaduration.rs create mode 100644 pmoupnp/src/mediarenderer/avtransport/variables/currentplaymode.rs create mode 100644 pmoupnp/src/mediarenderer/avtransport/variables/currenttrackmetadata.rs create mode 100644 pmoupnp/src/mediarenderer/avtransport/variables/currenttrackuri.rs create mode 100644 pmoupnp/src/mediarenderer/avtransport/variables/playbackstoragemedium.rs create mode 100644 pmoupnp/src/mediarenderer/avtransport/variables/possibleplaybackstoragemedia.rs create mode 100644 pmoupnp/src/mediarenderer/avtransport/variables/possiblerecordstoragemedia.rs create mode 100644 pmoupnp/src/mediarenderer/avtransport/variables/recordstoragemedium.rs diff --git a/pmoupnp/src/mediarenderer/avtransport/actions/getcurrenttransportactions.rs b/pmoupnp/src/mediarenderer/avtransport/actions/getcurrenttransportactions.rs new file mode 100644 index 00000000..e59a1b8d --- /dev/null +++ b/pmoupnp/src/mediarenderer/avtransport/actions/getcurrenttransportactions.rs @@ -0,0 +1,8 @@ +use crate::mediarenderer::avtransport::variables::A_ARG_TYPE_INSTANCE_ID; +use crate::define_action; + +define_action! { + pub static GETCURRENTTRANSPORTACTIONS = "GetCurrentTransportActions" { + in "InstanceID" => A_ARG_TYPE_INSTANCE_ID, + } +} diff --git a/pmoupnp/src/mediarenderer/avtransport/actions/mod.rs b/pmoupnp/src/mediarenderer/avtransport/actions/mod.rs index 427c1578..9b0ad316 100644 --- a/pmoupnp/src/mediarenderer/avtransport/actions/mod.rs +++ b/pmoupnp/src/mediarenderer/avtransport/actions/mod.rs @@ -1,3 +1,4 @@ +mod getcurrenttransportactions; mod getdevicecapabilities; mod getmediainfo; mod getpositioninfo; @@ -12,6 +13,7 @@ mod setavtransportnexturi; mod setavtransporturi; mod stop; +pub use getcurrenttransportactions::GETCURRENTTRANSPORTACTIONS; pub use getdevicecapabilities::GETDEVICECAPABILITIES; pub use getmediainfo::GETMEDIAINFO; pub use getpositioninfo::GETPOSITIONINFO; diff --git a/pmoupnp/src/mediarenderer/avtransport/mod.rs b/pmoupnp/src/mediarenderer/avtransport/mod.rs index 70550ac4..eed3f79a 100644 --- a/pmoupnp/src/mediarenderer/avtransport/mod.rs +++ b/pmoupnp/src/mediarenderer/avtransport/mod.rs @@ -1,21 +1,137 @@ +//! # AVTransport Service - Service de contrôle de transport UPnP +//! +//! Ce module implémente le service AVTransport:1 selon la spécification UPnP AV. +//! Le service AVTransport permet de contrôler la lecture de médias **audio** +//! sur des rendus multimédias (MediaRenderer Audio). +//! +//! ## Fonctionnalités +//! +//! Le service AVTransport permet : +//! - **Contrôle de lecture** : Play, Pause, Stop +//! - **Navigation** : Next, Previous, Seek +//! - **Gestion des URIs** : SetAVTransportURI, SetNextAVTransportURI +//! - **Information d'état** : GetTransportInfo, GetPositionInfo, GetMediaInfo +//! - **Capacités** : GetDeviceCapabilities, GetCurrentTransportActions +//! +//! ## Conformité UPnP +//! +//! Cette implémentation suit la spécification **UPnP AVTransport:1 Service Template**. +//! Toutes les actions obligatoires (Required) sont implémentées : +//! +//! - ✅ SetAVTransportURI +//! - ✅ GetMediaInfo +//! - ✅ GetTransportInfo +//! - ✅ GetPositionInfo +//! - ✅ GetDeviceCapabilities +//! - ✅ GetTransportSettings +//! - ✅ GetCurrentTransportActions +//! - ✅ Stop, Play, Pause +//! +//! Et certaines actions optionnelles : +//! - ✅ SetNextAVTransportURI +//! - ✅ Seek, Next, Previous +//! +//! ## Variables d'état +//! +//! Le service expose 24 variables d'état conformes à la spécification : +//! +//! ### État du transport +//! - [`TRANSPORTSTATE`] : État actuel (PLAYING, STOPPED, PAUSED_PLAYBACK, etc.) +//! - [`TRANSPORTSTATUS`] : Status du transport (OK, ERROR_OCCURRED) +//! - [`TRANSPORTPLAYSPEED`] : Vitesse de lecture +//! +//! ### Information sur les pistes +//! - [`CURRENTTRACK`] : Numéro de la piste actuelle +//! - [`NUMBEROFTRACKS`] : Nombre total de pistes +//! - [`CURRENTTRACKDURATION`] : Durée de la piste actuelle +//! - [`CURRENTTRACKURI`] : URI de la piste actuelle +//! - [`CURRENTTRACKMETADATA`] : Métadonnées de la piste +//! +//! ### Positionnement +//! - [`RELATIVETIMEPOSITION`] : Position relative dans la piste +//! - [`ABSOLUTETIMEPOSITION`] : Position absolue +//! +//! ### URIs et métadonnées +//! - [`AVTRANSPORTURI`] : URI de la ressource en cours +//! - [`AVTRANSPORTURIMETADATA`] : Métadonnées associées +//! - [`AVTRANSPORTNEXTURI`] : URI de la ressource suivante +//! - [`AVTRANSPORTNEXTURIMETADATA`] : Métadonnées de la ressource suivante +//! +//! ### Modes et capacités +//! - [`CURRENTPLAYMODE`] : Mode de lecture (NORMAL, SHUFFLE, REPEAT_ONE, etc.) +//! - [`PLAYBACKSTORAGEMEDIUM`] : Support de lecture (NETWORK, HDD, CD-DA, etc.) +//! - [`POSSIBLEPLAYBACKSTORAGEMEDIA`] : Supports de lecture possibles +//! +//! ## Examples +//! +//! ```rust +//! use pmoupnp::mediarenderer::avtransport::AVTTRANSPORT; +//! +//! // Accéder au service +//! let service = &*AVTTRANSPORT; +//! println!("Service: {}", service.name()); +//! println!("Type: {}", service.service_type()); +//! +//! // Lister les actions disponibles +//! for action in service.actions() { +//! println!(" Action: {}", action.get_name()); +//! } +//! +//! // Lister les variables d'état +//! for variable in service.variables() { +//! println!(" Variable: {}", variable.get_name()); +//! } +//! ``` +//! +//! ## Références +//! +//! - [UPnP AVTransport:1 Service Template](https://www.upnp.org/specs/av/UPnP-av-AVTransport-v1-Service.pdf) +//! - [UPnP AV Architecture](https://upnp.org/specs/av/) + use crate::define_service; pub mod variables; pub mod actions; use actions::{ - GETDEVICECAPABILITIES, GETMEDIAINFO, GETPOSITIONINFO, GETTRANSPORTINFO, - GETTRANSPORTSETTINGS, NEXT, PAUSE, PLAY, PREVIOUS, SEEK, - SETNEXTAVTRANSPORTURI, SETAVTRANSPORTURI, STOP + GETCURRENTTRANSPORTACTIONS, GETDEVICECAPABILITIES, GETMEDIAINFO, + GETPOSITIONINFO, GETTRANSPORTINFO, GETTRANSPORTSETTINGS, NEXT, PAUSE, + PLAY, PREVIOUS, SEEK, SETNEXTAVTRANSPORTURI, SETAVTRANSPORTURI, STOP }; use variables::{ ABSOLUTETIMEPOSITION, AVTRANSPORTNEXTURI, AVTRANSPORTNEXTURIMETADATA, AVTRANSPORTURI, AVTRANSPORTURIMETADATA, A_ARG_TYPE_INSTANCE_ID, - A_ARG_TYPE_PLAY_SPEED, A_ARG_TYPE_SEEKMODE, CURRENTTRACK, - CURRENTTRACKDURATION, NUMBEROFTRACKS, RELATIVETIMEPOSITION, SEEKMODE, + A_ARG_TYPE_PLAY_SPEED, A_ARG_TYPE_SEEKMODE, CURRENTMEDIADURATION, + CURRENTPLAYMODE, CURRENTTRACK, CURRENTTRACKDURATION, CURRENTTRACKMETADATA, + CURRENTTRACKURI, NUMBEROFTRACKS, PLAYBACKSTORAGEMEDIUM, + POSSIBLEPLAYBACKSTORAGEMEDIA, RELATIVETIMEPOSITION, SEEKMODE, TRANSPORTPLAYSPEED, TRANSPORTSTATE, TRANSPORTSTATUS }; +/// Service AVTransport:1 conforme à la spécification UPnP AV. +/// +/// Ce service permet de contrôler le transport de médias **audio** sur un MediaRenderer. +/// +/// # Initialisation +/// +/// Le service est initialisé paresseusement (lazy) au premier accès via la macro +/// [`define_service!`]. Toutes les variables d'état et actions sont automatiquement +/// enregistrées. +/// +/// # Exemples +/// +/// ```rust +/// use pmoupnp::mediarenderer::avtransport::AVTTRANSPORT; +/// +/// let service = &*AVTTRANSPORT; +/// assert_eq!(service.name(), "AVTransport"); +/// assert_eq!(service.version(), 1); +/// ``` +/// +/// # Voir aussi +/// +/// - Module [`actions`] : Définition de toutes les actions UPnP +/// - Module [`variables`] : Définition de toutes les variables d'état define_service! { pub static AVTTRANSPORT = "AVTransport" { variables: [ @@ -27,9 +143,15 @@ define_service! { AVTRANSPORTNEXTURIMETADATA, AVTRANSPORTURI, AVTRANSPORTURIMETADATA, + CURRENTMEDIADURATION, + CURRENTPLAYMODE, CURRENTTRACK, CURRENTTRACKDURATION, + CURRENTTRACKMETADATA, + CURRENTTRACKURI, NUMBEROFTRACKS, + PLAYBACKSTORAGEMEDIUM, + POSSIBLEPLAYBACKSTORAGEMEDIA, RELATIVETIMEPOSITION, SEEKMODE, TRANSPORTPLAYSPEED, @@ -37,6 +159,7 @@ define_service! { TRANSPORTSTATUS, ], actions: [ + GETCURRENTTRANSPORTACTIONS, GETDEVICECAPABILITIES, GETMEDIAINFO, GETPOSITIONINFO, diff --git a/pmoupnp/src/mediarenderer/avtransport/variables/a_arg_type_seekmode.rs b/pmoupnp/src/mediarenderer/avtransport/variables/a_arg_type_seekmode.rs index c36312df..6452322c 100644 --- a/pmoupnp/src/mediarenderer/avtransport/variables/a_arg_type_seekmode.rs +++ b/pmoupnp/src/mediarenderer/avtransport/variables/a_arg_type_seekmode.rs @@ -5,13 +5,13 @@ use crate::variable_types::{StateValue, StateVarType}; use once_cell::sync::Lazy; pub static A_ARG_TYPE_SEEKMODE: Lazy> = Lazy::new(|| -> Arc { - let mut sv = StateVariable::new(StateVarType::UI4, "A_ARG_TYPE_SeekMode".to_string()); + let mut sv = StateVariable::new(StateVarType::String, "A_ARG_TYPE_SeekMode".to_string()); - sv.extend_allowed_values(&[ + sv.extend_allowed_values(&[ StateValue::String("TRACK_NR".to_string()), StateValue::String("REL_TIME".to_string()), StateValue::String("ABS_TIME".to_string()), - ]).expect("Cannot set default value"); + ]).expect("Cannot set allowed values"); Arc::new(sv) }); diff --git a/pmoupnp/src/mediarenderer/avtransport/variables/currentmediaduration.rs b/pmoupnp/src/mediarenderer/avtransport/variables/currentmediaduration.rs new file mode 100644 index 00000000..11d977dc --- /dev/null +++ b/pmoupnp/src/mediarenderer/avtransport/variables/currentmediaduration.rs @@ -0,0 +1,10 @@ +use std::sync::Arc; + +use crate::state_variables::StateVariable; +use crate::variable_types::StateVarType; +use once_cell::sync::Lazy; + +pub static CURRENTMEDIADURATION: Lazy> = Lazy::new(|| -> Arc { + let sv = StateVariable::new(StateVarType::String, "CurrentMediaDuration".to_string()); + Arc::new(sv) +}); diff --git a/pmoupnp/src/mediarenderer/avtransport/variables/currentplaymode.rs b/pmoupnp/src/mediarenderer/avtransport/variables/currentplaymode.rs new file mode 100644 index 00000000..2d69c7f9 --- /dev/null +++ b/pmoupnp/src/mediarenderer/avtransport/variables/currentplaymode.rs @@ -0,0 +1,24 @@ +use std::sync::Arc; + +use crate::state_variables::StateVariable; +use crate::variable_types::{StateValue, StateVarType}; +use once_cell::sync::Lazy; + +pub static CURRENTPLAYMODE: Lazy> = Lazy::new(|| -> Arc { + let mut sv = StateVariable::new(StateVarType::String, "CurrentPlayMode".to_string()); + + sv.extend_allowed_values(&[ + StateValue::String("NORMAL".to_string()), + StateValue::String("SHUFFLE".to_string()), + StateValue::String("REPEAT_ONE".to_string()), + StateValue::String("REPEAT_ALL".to_string()), + StateValue::String("RANDOM".to_string()), + StateValue::String("DIRECT_1".to_string()), + StateValue::String("INTRO".to_string()), + ]).expect("Cannot set allowed values"); + + sv.set_default(&StateValue::String("NORMAL".to_string())) + .expect("Cannot set default value"); + + Arc::new(sv) +}); diff --git a/pmoupnp/src/mediarenderer/avtransport/variables/currenttrackmetadata.rs b/pmoupnp/src/mediarenderer/avtransport/variables/currenttrackmetadata.rs new file mode 100644 index 00000000..b2c2f2ed --- /dev/null +++ b/pmoupnp/src/mediarenderer/avtransport/variables/currenttrackmetadata.rs @@ -0,0 +1,10 @@ +use std::sync::Arc; + +use crate::state_variables::StateVariable; +use crate::variable_types::StateVarType; +use once_cell::sync::Lazy; + +pub static CURRENTTRACKMETADATA: Lazy> = Lazy::new(|| -> Arc { + let sv = StateVariable::new(StateVarType::String, "CurrentTrackMetaData".to_string()); + Arc::new(sv) +}); diff --git a/pmoupnp/src/mediarenderer/avtransport/variables/currenttrackuri.rs b/pmoupnp/src/mediarenderer/avtransport/variables/currenttrackuri.rs new file mode 100644 index 00000000..33ddf3c8 --- /dev/null +++ b/pmoupnp/src/mediarenderer/avtransport/variables/currenttrackuri.rs @@ -0,0 +1,10 @@ +use std::sync::Arc; + +use crate::state_variables::StateVariable; +use crate::variable_types::StateVarType; +use once_cell::sync::Lazy; + +pub static CURRENTTRACKURI: Lazy> = Lazy::new(|| -> Arc { + let sv = StateVariable::new(StateVarType::String, "CurrentTrackURI".to_string()); + Arc::new(sv) +}); diff --git a/pmoupnp/src/mediarenderer/avtransport/variables/mod.rs b/pmoupnp/src/mediarenderer/avtransport/variables/mod.rs index 2c70341d..00cf43fd 100644 --- a/pmoupnp/src/mediarenderer/avtransport/variables/mod.rs +++ b/pmoupnp/src/mediarenderer/avtransport/variables/mod.rs @@ -3,9 +3,17 @@ mod a_arg_type_playspeed; mod a_arg_type_seekmode; mod avtransporturi; mod avtransporturimetadata; +mod currentmediaduration; +mod currentplaymode; +mod currenttrackmetadata; +mod currenttrackuri; +mod playbackstoragemedium; +mod possibleplaybackstoragemedia; +mod possiblerecordstoragemedia; +mod recordstoragemedium; +mod seekmode; mod track; mod trackduration; -mod seekmode; mod transportplayspeed; mod transportstate; mod transportstatus; @@ -17,12 +25,20 @@ pub use avtransporturi::AVTRANSPORTURI; pub use avtransporturi::AVTRANSPORTNEXTURI; pub use avtransporturimetadata::AVTRANSPORTURIMETADATA; pub use avtransporturimetadata::AVTRANSPORTNEXTURIMETADATA; +pub use currentmediaduration::CURRENTMEDIADURATION; +pub use currentplaymode::CURRENTPLAYMODE; +pub use currenttrackmetadata::CURRENTTRACKMETADATA; +pub use currenttrackuri::CURRENTTRACKURI; +pub use playbackstoragemedium::PLAYBACKSTORAGEMEDIUM; +pub use possibleplaybackstoragemedia::POSSIBLEPLAYBACKSTORAGEMEDIA; +pub use possiblerecordstoragemedia::POSSIBLERECORDSTORAGEMEDIA; +pub use recordstoragemedium::RECORDSTORAGEMEDIUM; +pub use seekmode::SEEKMODE; pub use track::CURRENTTRACK; pub use track::NUMBEROFTRACKS; -pub use trackduration::CURRENTTRACKDURATION; pub use trackduration::ABSOLUTETIMEPOSITION; +pub use trackduration::CURRENTTRACKDURATION; pub use trackduration::RELATIVETIMEPOSITION; -pub use seekmode::SEEKMODE; pub use transportplayspeed::TRANSPORTPLAYSPEED; pub use transportstate::TRANSPORTSTATE; pub use transportstatus::TRANSPORTSTATUS; diff --git a/pmoupnp/src/mediarenderer/avtransport/variables/playbackstoragemedium.rs b/pmoupnp/src/mediarenderer/avtransport/variables/playbackstoragemedium.rs new file mode 100644 index 00000000..6fed20c0 --- /dev/null +++ b/pmoupnp/src/mediarenderer/avtransport/variables/playbackstoragemedium.rs @@ -0,0 +1,28 @@ +use std::sync::Arc; + +use crate::state_variables::StateVariable; +use crate::variable_types::{StateValue, StateVarType}; +use once_cell::sync::Lazy; + +pub static PLAYBACKSTORAGEMEDIUM: Lazy> = Lazy::new(|| -> Arc { + let mut sv = StateVariable::new(StateVarType::String, "PlaybackStorageMedium".to_string()); + + // Valeurs pour un MediaRenderer audio uniquement (suppression des formats vidéo) + sv.extend_allowed_values(&[ + StateValue::String("UNKNOWN".to_string()), + StateValue::String("CD-ROM".to_string()), + StateValue::String("CD-DA".to_string()), + StateValue::String("CD-R".to_string()), + StateValue::String("CD-RW".to_string()), + StateValue::String("SACD".to_string()), + StateValue::String("MD-AUDIO".to_string()), + StateValue::String("DVD-AUDIO".to_string()), + StateValue::String("DAT".to_string()), + StateValue::String("HDD".to_string()), + StateValue::String("NETWORK".to_string()), + StateValue::String("NONE".to_string()), + StateValue::String("NOT_IMPLEMENTED".to_string()), + ]).expect("Cannot set allowed values"); + + Arc::new(sv) +}); diff --git a/pmoupnp/src/mediarenderer/avtransport/variables/possibleplaybackstoragemedia.rs b/pmoupnp/src/mediarenderer/avtransport/variables/possibleplaybackstoragemedia.rs new file mode 100644 index 00000000..0cb247c2 --- /dev/null +++ b/pmoupnp/src/mediarenderer/avtransport/variables/possibleplaybackstoragemedia.rs @@ -0,0 +1,10 @@ +use std::sync::Arc; + +use crate::state_variables::StateVariable; +use crate::variable_types::StateVarType; +use once_cell::sync::Lazy; + +pub static POSSIBLEPLAYBACKSTORAGEMEDIA: Lazy> = Lazy::new(|| -> Arc { + let sv = StateVariable::new(StateVarType::String, "PossiblePlaybackStorageMedia".to_string()); + Arc::new(sv) +}); diff --git a/pmoupnp/src/mediarenderer/avtransport/variables/possiblerecordstoragemedia.rs b/pmoupnp/src/mediarenderer/avtransport/variables/possiblerecordstoragemedia.rs new file mode 100644 index 00000000..2d0ef55c --- /dev/null +++ b/pmoupnp/src/mediarenderer/avtransport/variables/possiblerecordstoragemedia.rs @@ -0,0 +1,10 @@ +use std::sync::Arc; + +use crate::state_variables::StateVariable; +use crate::variable_types::StateVarType; +use once_cell::sync::Lazy; + +pub static POSSIBLERECORDSTORAGEMEDIA: Lazy> = Lazy::new(|| -> Arc { + let sv = StateVariable::new(StateVarType::String, "PossibleRecordStorageMedia".to_string()); + Arc::new(sv) +}); diff --git a/pmoupnp/src/mediarenderer/avtransport/variables/recordstoragemedium.rs b/pmoupnp/src/mediarenderer/avtransport/variables/recordstoragemedium.rs new file mode 100644 index 00000000..19a42660 --- /dev/null +++ b/pmoupnp/src/mediarenderer/avtransport/variables/recordstoragemedium.rs @@ -0,0 +1,10 @@ +use std::sync::Arc; + +use crate::state_variables::StateVariable; +use crate::variable_types::StateVarType; +use once_cell::sync::Lazy; + +pub static RECORDSTORAGEMEDIUM: Lazy> = Lazy::new(|| -> Arc { + let sv = StateVariable::new(StateVarType::String, "RecordStorageMedium".to_string()); + Arc::new(sv) +}); diff --git a/pmoupnp/src/mediarenderer/avtransport/variables/transportstate.rs b/pmoupnp/src/mediarenderer/avtransport/variables/transportstate.rs index 6cb80597..9b20ba8c 100644 --- a/pmoupnp/src/mediarenderer/avtransport/variables/transportstate.rs +++ b/pmoupnp/src/mediarenderer/avtransport/variables/transportstate.rs @@ -7,16 +7,15 @@ use once_cell::sync::Lazy; pub static TRANSPORTSTATE: Lazy> = Lazy::new(|| -> Arc { let mut sv = StateVariable::new(StateVarType::String, "TransportState".to_string()); - sv.extend_allowed_values(&[ + // États pour un MediaRenderer audio uniquement (suppression des états d'enregistrement) + sv.extend_allowed_values(&[ StateValue::String("STOPPED".to_string()), StateValue::String("PLAYING".to_string()), - StateValue::String("RECORDING".to_string()), StateValue::String("TRANSITIONING".to_string()), StateValue::String("PAUSED_PLAYBACK".to_string()), - StateValue::String("PAUSED_RECORDING".to_string()), - StateValue::String("NO_MEDIA_PRESENT".to_string()), - ]).expect("Cannt set default value"); - + StateValue::String("NO_MEDIA_PRESENT".to_string()), + ]).expect("Cannot set allowed values"); + sv.set_send_notification(); Arc::new(sv)