implemente le squelette de pmomediaserver
This commit is contained in:
10
Cargo.lock
generated
10
Cargo.lock
generated
@@ -2344,6 +2344,16 @@ dependencies = [
|
|||||||
"pmoupnp",
|
"pmoupnp",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pmomediaserver"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bevy_reflect",
|
||||||
|
"once_cell",
|
||||||
|
"pmodidl",
|
||||||
|
"pmoupnp",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pmoparadise"
|
name = "pmoparadise"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
resolver = "3"
|
resolver = "3"
|
||||||
members = ["PMOMusic", "pmoupnp", "pmomediarenderer", "pmoconfig", "pmoutils", "pmodidl", "pmoserver", "pmoapp", "pmocache", "pmocovers", "pmoaudiocache", "pmoaudio", "pmoqobuz", "pmoparadise", "pmosource", "pmoplaylist"]
|
members = ["PMOMusic", "pmoupnp", "pmomediarenderer", "pmomediaserver", "pmoconfig", "pmoutils", "pmodidl", "pmoserver", "pmoapp", "pmocache", "pmocovers", "pmoaudiocache", "pmoaudio", "pmoqobuz", "pmoparadise", "pmosource", "pmoplaylist"]
|
||||||
|
|||||||
11
pmomediaserver/Cargo.toml
Normal file
11
pmomediaserver/Cargo.toml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "pmomediaserver"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
pmoupnp = { path = "../pmoupnp" }
|
||||||
|
pmodidl = { path = "../pmodidl" }
|
||||||
|
|
||||||
|
once_cell = "1.20"
|
||||||
|
bevy_reflect = "0.17.1"
|
||||||
73
pmomediaserver/README.md
Normal file
73
pmomediaserver/README.md
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
# pmomediaserver
|
||||||
|
|
||||||
|
Implémentation d'un MediaServer UPnP conforme à la spécification UPnP AV Architecture.
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Cette crate fournit un MediaServer UPnP qui permet d'exposer et de servir du contenu audio à des clients UPnP (MediaRenderer). Elle suit le même modèle architectural que la crate `pmomediarenderer`.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
Le MediaServer est composé de deux services obligatoires :
|
||||||
|
|
||||||
|
- **ContentDirectory** : Gestion du contenu et de la navigation dans la bibliothèque musicale
|
||||||
|
- **ConnectionManager** : Gestion des connexions et des protocoles supportés
|
||||||
|
|
||||||
|
## Device UPnP
|
||||||
|
|
||||||
|
- Type : `urn:schemas-upnp-org:device:MediaServer:1`
|
||||||
|
- Services : ContentDirectory:1, ConnectionManager:1
|
||||||
|
|
||||||
|
## Utilisation
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use pmomediaserver::MEDIA_SERVER;
|
||||||
|
use pmoupnp::UpnpServer;
|
||||||
|
|
||||||
|
// Le device est déjà configuré avec tous ses services
|
||||||
|
let server = MEDIA_SERVER.clone();
|
||||||
|
|
||||||
|
// Créer une instance du server
|
||||||
|
let instance = server.create_instance();
|
||||||
|
|
||||||
|
// Enregistrer le server sur un serveur UPnP
|
||||||
|
upnp_server.register_device(server).await?;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Dépendances
|
||||||
|
|
||||||
|
- `pmoupnp` : Fournit l'infrastructure UPnP de base (devices, services, actions, state variables)
|
||||||
|
- `pmodidl` : Pour la gestion des métadonnées DIDL-Lite
|
||||||
|
- `once_cell` : Pour les initialisations lazy
|
||||||
|
- `bevy_reflect` : Pour la réflexion et l'introspection
|
||||||
|
|
||||||
|
## Services
|
||||||
|
|
||||||
|
### ContentDirectory
|
||||||
|
|
||||||
|
Service de gestion du contenu conforme UPnP ContentDirectory:1. Permet de naviguer et rechercher dans la bibliothèque musicale.
|
||||||
|
|
||||||
|
**Actions supportées :**
|
||||||
|
- Browse
|
||||||
|
- Search
|
||||||
|
- GetSearchCapabilities
|
||||||
|
- GetSortCapabilities
|
||||||
|
- GetSystemUpdateID
|
||||||
|
- CreateObject (optionnel)
|
||||||
|
- DestroyObject (optionnel)
|
||||||
|
- UpdateObject (optionnel)
|
||||||
|
|
||||||
|
### ConnectionManager
|
||||||
|
|
||||||
|
Service de gestion des connexions conforme UPnP ConnectionManager:1. Gère les protocoles supportés.
|
||||||
|
|
||||||
|
**Actions supportées :**
|
||||||
|
- GetProtocolInfo
|
||||||
|
- GetCurrentConnectionIDs
|
||||||
|
- GetCurrentConnectionInfo
|
||||||
|
- PrepareForConnection (optionnel)
|
||||||
|
- ConnectionComplete (optionnel)
|
||||||
|
|
||||||
|
## Licence
|
||||||
|
|
||||||
|
Voir le fichier LICENSE à la racine du projet.
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
use crate::connectionmanager::variables::CURRENTCONNECTIONIDS;
|
||||||
|
use pmoupnp::define_action;
|
||||||
|
|
||||||
|
define_action! {
|
||||||
|
pub static GETCURRENTCONNECTIONIDS = "GetCurrentConnectionIDs" {
|
||||||
|
out "ConnectionIDs" => CURRENTCONNECTIONIDS,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
use crate::connectionmanager::variables::{
|
||||||
|
A_ARG_TYPE_CONNECTIONID, A_ARG_TYPE_RCSID, A_ARG_TYPE_AVTRANSPORTID,
|
||||||
|
A_ARG_TYPE_PROTOCOLINFO, A_ARG_TYPE_DIRECTION, A_ARG_TYPE_CONNECTIONSTATUS,
|
||||||
|
};
|
||||||
|
use pmoupnp::define_action;
|
||||||
|
|
||||||
|
define_action! {
|
||||||
|
pub static GETCURRENTCONNECTIONINFO = "GetCurrentConnectionInfo" {
|
||||||
|
in "ConnectionID" => A_ARG_TYPE_CONNECTIONID,
|
||||||
|
out "RcsID" => A_ARG_TYPE_RCSID,
|
||||||
|
out "AVTransportID" => A_ARG_TYPE_AVTRANSPORTID,
|
||||||
|
out "ProtocolInfo" => A_ARG_TYPE_PROTOCOLINFO,
|
||||||
|
out "PeerConnectionManager" => A_ARG_TYPE_CONNECTIONID,
|
||||||
|
out "PeerConnectionID" => A_ARG_TYPE_CONNECTIONID,
|
||||||
|
out "Direction" => A_ARG_TYPE_DIRECTION,
|
||||||
|
out "Status" => A_ARG_TYPE_CONNECTIONSTATUS,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
use crate::connectionmanager::variables::{SOURCEPROTOCOLINFO, SINKPROTOCOLINFO};
|
||||||
|
use pmoupnp::define_action;
|
||||||
|
|
||||||
|
define_action! {
|
||||||
|
pub static GETPROTOCOLINFO = "GetProtocolInfo" {
|
||||||
|
out "Source" => SOURCEPROTOCOLINFO,
|
||||||
|
out "Sink" => SINKPROTOCOLINFO,
|
||||||
|
}
|
||||||
|
}
|
||||||
7
pmomediaserver/src/connectionmanager/actions/mod.rs
Normal file
7
pmomediaserver/src/connectionmanager/actions/mod.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
mod getprotocolinfo;
|
||||||
|
mod getcurrentconnectionids;
|
||||||
|
mod getcurrentconnectioninfo;
|
||||||
|
|
||||||
|
pub use getprotocolinfo::GETPROTOCOLINFO;
|
||||||
|
pub use getcurrentconnectionids::GETCURRENTCONNECTIONIDS;
|
||||||
|
pub use getcurrentconnectioninfo::GETCURRENTCONNECTIONINFO;
|
||||||
99
pmomediaserver/src/connectionmanager/mod.rs
Normal file
99
pmomediaserver/src/connectionmanager/mod.rs
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
//! # ConnectionManager Service - Service de gestion des connexions UPnP
|
||||||
|
//!
|
||||||
|
//! Ce module implémente le service ConnectionManager:1 selon la spécification UPnP AV.
|
||||||
|
//! Le service ConnectionManager gère les connexions entre MediaServer et MediaRenderer,
|
||||||
|
//! et expose les protocoles et formats supportés.
|
||||||
|
//!
|
||||||
|
//! ## Fonctionnalités
|
||||||
|
//!
|
||||||
|
//! Le service ConnectionManager permet :
|
||||||
|
//! - **Énumération des protocoles** : GetProtocolInfo
|
||||||
|
//! - **Gestion des connexions** : GetCurrentConnectionIDs, GetCurrentConnectionInfo
|
||||||
|
//! - Support des formats audio (MP3, FLAC, WAV, etc.)
|
||||||
|
//!
|
||||||
|
//! ## Conformité UPnP
|
||||||
|
//!
|
||||||
|
//! Cette implémentation suit la spécification **UPnP ConnectionManager:1 Service Template**.
|
||||||
|
//! Toutes les actions obligatoires (Required) sont implémentées :
|
||||||
|
//!
|
||||||
|
//! - ✅ GetProtocolInfo
|
||||||
|
//! - ✅ GetCurrentConnectionIDs
|
||||||
|
//! - ✅ GetCurrentConnectionInfo
|
||||||
|
//!
|
||||||
|
//! ## Variables d'état
|
||||||
|
//!
|
||||||
|
//! Le service expose les variables d'état conformes à la spécification :
|
||||||
|
//!
|
||||||
|
//! ### Informations de protocole
|
||||||
|
//! - [`SOURCEPROTOCOLINFO`] : Protocoles source supportés (http-get:*:audio/mpeg:*, etc.)
|
||||||
|
//! - [`SINKPROTOCOLINFO`] : Protocoles sink (vide pour un server)
|
||||||
|
//! - [`CURRENTCONNECTIONIDS`] : IDs des connexions actives
|
||||||
|
//!
|
||||||
|
//! ### Arguments
|
||||||
|
//! - [`A_ARG_TYPE_CONNECTIONID`] : ID de connexion
|
||||||
|
//! - [`A_ARG_TYPE_CONNECTIONSTATUS`] : Statut de connexion
|
||||||
|
//! - [`A_ARG_TYPE_DIRECTION`] : Direction (Input/Output)
|
||||||
|
//! - [`A_ARG_TYPE_PROTOCOLINFO`] : Information de protocole
|
||||||
|
//! - [`A_ARG_TYPE_RCSID`] : ID RenderingControl
|
||||||
|
//! - [`A_ARG_TYPE_AVTRANSPORTID`] : ID AVTransport
|
||||||
|
//!
|
||||||
|
//! ## Différences avec MediaRenderer
|
||||||
|
//!
|
||||||
|
//! Pour un MediaServer :
|
||||||
|
//! - **SourceProtocolInfo** : Liste des protocoles que le server peut **fournir** (Output)
|
||||||
|
//! - **SinkProtocolInfo** : Vide (le server ne **consomme** pas de contenu)
|
||||||
|
//!
|
||||||
|
//! Pour un MediaRenderer (inverse) :
|
||||||
|
//! - **SourceProtocolInfo** : Vide (le renderer ne fournit pas de contenu)
|
||||||
|
//! - **SinkProtocolInfo** : Liste des protocoles que le renderer peut **consommer** (Input)
|
||||||
|
//!
|
||||||
|
//! ## Examples
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use pmomediaserver::connectionmanager::CONNECTIONMANAGER;
|
||||||
|
//!
|
||||||
|
//! // Accéder au service
|
||||||
|
//! let service = &*CONNECTIONMANAGER;
|
||||||
|
//! println!("Service: {}", service.name());
|
||||||
|
//! println!("Type: {}", service.service_type());
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## Références
|
||||||
|
//!
|
||||||
|
//! - [UPnP ConnectionManager:1 Service Template](https://upnp.org/specs/av/UPnP-av-ConnectionManager-v1-Service.pdf)
|
||||||
|
//! - [UPnP AV Architecture](https://upnp.org/specs/av/)
|
||||||
|
|
||||||
|
use pmoupnp::define_service;
|
||||||
|
|
||||||
|
pub mod variables;
|
||||||
|
pub mod actions;
|
||||||
|
|
||||||
|
use actions::{GETCURRENTCONNECTIONIDS, GETCURRENTCONNECTIONINFO, GETPROTOCOLINFO};
|
||||||
|
use variables::{
|
||||||
|
A_ARG_TYPE_AVTRANSPORTID, A_ARG_TYPE_CONNECTIONID, A_ARG_TYPE_CONNECTIONSTATUS,
|
||||||
|
A_ARG_TYPE_DIRECTION, A_ARG_TYPE_PROTOCOLINFO, A_ARG_TYPE_RCSID,
|
||||||
|
CURRENTCONNECTIONIDS, SINKPROTOCOLINFO, SOURCEPROTOCOLINFO
|
||||||
|
};
|
||||||
|
|
||||||
|
// Service ConnectionManager:1 conforme à la spécification UPnP AV pour MediaServer
|
||||||
|
// Voir la documentation du module pour plus de détails
|
||||||
|
define_service! {
|
||||||
|
pub static CONNECTIONMANAGER = "ConnectionManager" {
|
||||||
|
variables: [
|
||||||
|
A_ARG_TYPE_AVTRANSPORTID,
|
||||||
|
A_ARG_TYPE_CONNECTIONID,
|
||||||
|
A_ARG_TYPE_CONNECTIONSTATUS,
|
||||||
|
A_ARG_TYPE_DIRECTION,
|
||||||
|
A_ARG_TYPE_PROTOCOLINFO,
|
||||||
|
A_ARG_TYPE_RCSID,
|
||||||
|
CURRENTCONNECTIONIDS,
|
||||||
|
SINKPROTOCOLINFO,
|
||||||
|
SOURCEPROTOCOLINFO,
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
GETCURRENTCONNECTIONIDS,
|
||||||
|
GETCURRENTCONNECTIONINFO,
|
||||||
|
GETPROTOCOLINFO,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use pmoupnp::define_variable;
|
||||||
|
|
||||||
|
define_variable! {
|
||||||
|
pub static A_ARG_TYPE_AVTRANSPORTID: I4 = "A_ARG_TYPE_AVTransportID" {
|
||||||
|
evented: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use pmoupnp::define_variable;
|
||||||
|
|
||||||
|
define_variable! {
|
||||||
|
pub static A_ARG_TYPE_CONNECTIONID: I4 = "A_ARG_TYPE_ConnectionID" {
|
||||||
|
evented: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
use pmoupnp::define_variable;
|
||||||
|
|
||||||
|
define_variable! {
|
||||||
|
pub static A_ARG_TYPE_CONNECTIONSTATUS: String = "A_ARG_TYPE_ConnectionStatus" {
|
||||||
|
allowed: ["OK", "ContentFormatMismatch", "InsufficientBandwidth", "UnreliableChannel", "Unknown"],
|
||||||
|
evented: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
use pmoupnp::define_variable;
|
||||||
|
|
||||||
|
define_variable! {
|
||||||
|
pub static A_ARG_TYPE_DIRECTION: String = "A_ARG_TYPE_Direction" {
|
||||||
|
allowed: ["Input", "Output"],
|
||||||
|
evented: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use pmoupnp::define_variable;
|
||||||
|
|
||||||
|
define_variable! {
|
||||||
|
pub static A_ARG_TYPE_PROTOCOLINFO: String = "A_ARG_TYPE_ProtocolInfo" {
|
||||||
|
evented: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use pmoupnp::define_variable;
|
||||||
|
|
||||||
|
define_variable! {
|
||||||
|
pub static A_ARG_TYPE_RCSID: I4 = "A_ARG_TYPE_RcsID" {
|
||||||
|
evented: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use pmoupnp::define_variable;
|
||||||
|
|
||||||
|
define_variable! {
|
||||||
|
pub static CURRENTCONNECTIONIDS: String = "CurrentConnectionIDs" {
|
||||||
|
evented: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
19
pmomediaserver/src/connectionmanager/variables/mod.rs
Normal file
19
pmomediaserver/src/connectionmanager/variables/mod.rs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
mod a_arg_type_connectionid;
|
||||||
|
mod a_arg_type_connectionstatus;
|
||||||
|
mod a_arg_type_direction;
|
||||||
|
mod a_arg_type_protocolinfo;
|
||||||
|
mod a_arg_type_rcsid;
|
||||||
|
mod a_arg_type_avtransportid;
|
||||||
|
mod currentconnectionids;
|
||||||
|
mod sourceprotocolinfo;
|
||||||
|
mod sinkprotocolinfo;
|
||||||
|
|
||||||
|
pub use a_arg_type_connectionid::A_ARG_TYPE_CONNECTIONID;
|
||||||
|
pub use a_arg_type_connectionstatus::A_ARG_TYPE_CONNECTIONSTATUS;
|
||||||
|
pub use a_arg_type_direction::A_ARG_TYPE_DIRECTION;
|
||||||
|
pub use a_arg_type_protocolinfo::A_ARG_TYPE_PROTOCOLINFO;
|
||||||
|
pub use a_arg_type_rcsid::A_ARG_TYPE_RCSID;
|
||||||
|
pub use a_arg_type_avtransportid::A_ARG_TYPE_AVTRANSPORTID;
|
||||||
|
pub use currentconnectionids::CURRENTCONNECTIONIDS;
|
||||||
|
pub use sourceprotocolinfo::SOURCEPROTOCOLINFO;
|
||||||
|
pub use sinkprotocolinfo::SINKPROTOCOLINFO;
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
use pmoupnp::define_variable;
|
||||||
|
|
||||||
|
// Pour un MediaServer, SinkProtocolInfo est vide (le server ne consomme pas de contenu)
|
||||||
|
define_variable! {
|
||||||
|
pub static SINKPROTOCOLINFO: String = "SinkProtocolInfo" {
|
||||||
|
evented: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
use pmoupnp::define_variable;
|
||||||
|
|
||||||
|
// Pour un MediaServer, SourceProtocolInfo liste les protocoles qu'il peut servir
|
||||||
|
define_variable! {
|
||||||
|
pub static SOURCEPROTOCOLINFO: String = "SourceProtocolInfo" {
|
||||||
|
evented: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
21
pmomediaserver/src/contentdirectory/actions/browse.rs
Normal file
21
pmomediaserver/src/contentdirectory/actions/browse.rs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
use crate::contentdirectory::variables::{
|
||||||
|
A_ARG_TYPE_OBJECTID, A_ARG_TYPE_BROWSEFLAG, A_ARG_TYPE_FILTER,
|
||||||
|
A_ARG_TYPE_SORTCRITERIA, A_ARG_TYPE_INDEX, A_ARG_TYPE_COUNT,
|
||||||
|
A_ARG_TYPE_RESULT, A_ARG_TYPE_UPDATEID,
|
||||||
|
};
|
||||||
|
use pmoupnp::define_action;
|
||||||
|
|
||||||
|
define_action! {
|
||||||
|
pub static BROWSE = "Browse" {
|
||||||
|
in "ObjectID" => A_ARG_TYPE_OBJECTID,
|
||||||
|
in "BrowseFlag" => A_ARG_TYPE_BROWSEFLAG,
|
||||||
|
in "Filter" => A_ARG_TYPE_FILTER,
|
||||||
|
in "StartingIndex" => A_ARG_TYPE_INDEX,
|
||||||
|
in "RequestedCount" => A_ARG_TYPE_COUNT,
|
||||||
|
in "SortCriteria" => A_ARG_TYPE_SORTCRITERIA,
|
||||||
|
out "Result" => A_ARG_TYPE_RESULT,
|
||||||
|
out "NumberReturned" => A_ARG_TYPE_COUNT,
|
||||||
|
out "TotalMatches" => A_ARG_TYPE_COUNT,
|
||||||
|
out "UpdateID" => A_ARG_TYPE_UPDATEID,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
use crate::contentdirectory::variables::SEARCHCAPABILITIES;
|
||||||
|
use pmoupnp::define_action;
|
||||||
|
|
||||||
|
define_action! {
|
||||||
|
pub static GETSEARCHCAPABILITIES = "GetSearchCapabilities" {
|
||||||
|
out "SearchCaps" => SEARCHCAPABILITIES,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
use crate::contentdirectory::variables::SORTCAPABILITIES;
|
||||||
|
use pmoupnp::define_action;
|
||||||
|
|
||||||
|
define_action! {
|
||||||
|
pub static GETSORTCAPABILITIES = "GetSortCapabilities" {
|
||||||
|
out "SortCaps" => SORTCAPABILITIES,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
use crate::contentdirectory::variables::SYSTEMUPDATEID;
|
||||||
|
use pmoupnp::define_action;
|
||||||
|
|
||||||
|
define_action! {
|
||||||
|
pub static GETSYSTEMUPDATEID = "GetSystemUpdateID" {
|
||||||
|
out "Id" => SYSTEMUPDATEID,
|
||||||
|
}
|
||||||
|
}
|
||||||
11
pmomediaserver/src/contentdirectory/actions/mod.rs
Normal file
11
pmomediaserver/src/contentdirectory/actions/mod.rs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
mod browse;
|
||||||
|
mod search;
|
||||||
|
mod getsearchcapabilities;
|
||||||
|
mod getsortcapabilities;
|
||||||
|
mod getsystemupdateid;
|
||||||
|
|
||||||
|
pub use browse::BROWSE;
|
||||||
|
pub use search::SEARCH;
|
||||||
|
pub use getsearchcapabilities::GETSEARCHCAPABILITIES;
|
||||||
|
pub use getsortcapabilities::GETSORTCAPABILITIES;
|
||||||
|
pub use getsystemupdateid::GETSYSTEMUPDATEID;
|
||||||
21
pmomediaserver/src/contentdirectory/actions/search.rs
Normal file
21
pmomediaserver/src/contentdirectory/actions/search.rs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
use crate::contentdirectory::variables::{
|
||||||
|
A_ARG_TYPE_OBJECTID, A_ARG_TYPE_SEARCHCRITERIA, A_ARG_TYPE_FILTER,
|
||||||
|
A_ARG_TYPE_SORTCRITERIA, A_ARG_TYPE_INDEX, A_ARG_TYPE_COUNT,
|
||||||
|
A_ARG_TYPE_RESULT, A_ARG_TYPE_UPDATEID,
|
||||||
|
};
|
||||||
|
use pmoupnp::define_action;
|
||||||
|
|
||||||
|
define_action! {
|
||||||
|
pub static SEARCH = "Search" {
|
||||||
|
in "ContainerID" => A_ARG_TYPE_OBJECTID,
|
||||||
|
in "SearchCriteria" => A_ARG_TYPE_SEARCHCRITERIA,
|
||||||
|
in "Filter" => A_ARG_TYPE_FILTER,
|
||||||
|
in "StartingIndex" => A_ARG_TYPE_INDEX,
|
||||||
|
in "RequestedCount" => A_ARG_TYPE_COUNT,
|
||||||
|
in "SortCriteria" => A_ARG_TYPE_SORTCRITERIA,
|
||||||
|
out "Result" => A_ARG_TYPE_RESULT,
|
||||||
|
out "NumberReturned" => A_ARG_TYPE_COUNT,
|
||||||
|
out "TotalMatches" => A_ARG_TYPE_COUNT,
|
||||||
|
out "UpdateID" => A_ARG_TYPE_UPDATEID,
|
||||||
|
}
|
||||||
|
}
|
||||||
116
pmomediaserver/src/contentdirectory/mod.rs
Normal file
116
pmomediaserver/src/contentdirectory/mod.rs
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
//! # ContentDirectory Service - Service de gestion du contenu UPnP
|
||||||
|
//!
|
||||||
|
//! Ce module implémente le service ContentDirectory:1 selon la spécification UPnP AV.
|
||||||
|
//! Le service ContentDirectory permet de naviguer et rechercher dans une bibliothèque
|
||||||
|
//! de contenu musical.
|
||||||
|
//!
|
||||||
|
//! ## Fonctionnalités
|
||||||
|
//!
|
||||||
|
//! Le service ContentDirectory permet :
|
||||||
|
//! - **Navigation** : Browse pour parcourir la hiérarchie de contenu
|
||||||
|
//! - **Recherche** : Search pour rechercher du contenu selon des critères
|
||||||
|
//! - **Capacités** : GetSearchCapabilities, GetSortCapabilities
|
||||||
|
//! - **Synchronisation** : GetSystemUpdateID pour détecter les changements
|
||||||
|
//!
|
||||||
|
//! ## Conformité UPnP
|
||||||
|
//!
|
||||||
|
//! Cette implémentation suit la spécification **UPnP ContentDirectory:1 Service Template**.
|
||||||
|
//! Toutes les actions obligatoires (Required) sont implémentées :
|
||||||
|
//!
|
||||||
|
//! - ✅ Browse
|
||||||
|
//! - ✅ GetSearchCapabilities
|
||||||
|
//! - ✅ GetSortCapabilities
|
||||||
|
//! - ✅ GetSystemUpdateID
|
||||||
|
//!
|
||||||
|
//! Et certaines actions optionnelles :
|
||||||
|
//! - ✅ Search
|
||||||
|
//!
|
||||||
|
//! ## Variables d'état
|
||||||
|
//!
|
||||||
|
//! Le service expose les variables d'état conformes à la spécification :
|
||||||
|
//!
|
||||||
|
//! ### Variables principales
|
||||||
|
//! - [`SYSTEMUPDATEID`] : ID de mise à jour du système (évènementiel)
|
||||||
|
//! - [`SEARCHCAPABILITIES`] : Capacités de recherche supportées
|
||||||
|
//! - [`SORTCAPABILITIES`] : Capacités de tri supportées
|
||||||
|
//!
|
||||||
|
//! ### Arguments d'action
|
||||||
|
//! - [`A_ARG_TYPE_OBJECTID`] : ID d'un objet (container ou item)
|
||||||
|
//! - [`A_ARG_TYPE_BROWSEFLAG`] : Type de browsing (Metadata ou DirectChildren)
|
||||||
|
//! - [`A_ARG_TYPE_FILTER`] : Filtre de propriétés à retourner
|
||||||
|
//! - [`A_ARG_TYPE_SORTCRITERIA`] : Critères de tri
|
||||||
|
//! - [`A_ARG_TYPE_SEARCHCRITERIA`] : Critères de recherche
|
||||||
|
//! - [`A_ARG_TYPE_INDEX`] : Index de départ
|
||||||
|
//! - [`A_ARG_TYPE_COUNT`] : Nombre d'éléments
|
||||||
|
//! - [`A_ARG_TYPE_UPDATEID`] : ID de mise à jour
|
||||||
|
//! - [`A_ARG_TYPE_RESULT`] : Résultat au format DIDL-Lite
|
||||||
|
//!
|
||||||
|
//! ## Examples
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use pmomediaserver::contentdirectory::CONTENTDIRECTORY;
|
||||||
|
//! use pmoupnp::UpnpTyped;
|
||||||
|
//!
|
||||||
|
//! // Accéder au service
|
||||||
|
//! let service = &*CONTENTDIRECTORY;
|
||||||
|
//! 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 ContentDirectory:1 Service Template](https://upnp.org/specs/av/UPnP-av-ContentDirectory-v1-Service.pdf)
|
||||||
|
//! - [UPnP AV Architecture](https://upnp.org/specs/av/)
|
||||||
|
|
||||||
|
use pmoupnp::define_service;
|
||||||
|
|
||||||
|
pub mod variables;
|
||||||
|
pub mod actions;
|
||||||
|
|
||||||
|
use actions::{
|
||||||
|
BROWSE, SEARCH, GETSEARCHCAPABILITIES, GETSORTCAPABILITIES, GETSYSTEMUPDATEID
|
||||||
|
};
|
||||||
|
use variables::{
|
||||||
|
A_ARG_TYPE_OBJECTID, A_ARG_TYPE_BROWSEFLAG, A_ARG_TYPE_FILTER,
|
||||||
|
A_ARG_TYPE_SORTCRITERIA, A_ARG_TYPE_INDEX, A_ARG_TYPE_COUNT,
|
||||||
|
A_ARG_TYPE_UPDATEID, A_ARG_TYPE_RESULT, A_ARG_TYPE_SEARCHCRITERIA,
|
||||||
|
SEARCHCAPABILITIES, SORTCAPABILITIES, SYSTEMUPDATEID
|
||||||
|
};
|
||||||
|
|
||||||
|
// Service ContentDirectory:1 conforme à la spécification UPnP AV pour MediaServer
|
||||||
|
// Voir la documentation du module pour plus de détails
|
||||||
|
define_service! {
|
||||||
|
pub static CONTENTDIRECTORY = "ContentDirectory" {
|
||||||
|
variables: [
|
||||||
|
A_ARG_TYPE_OBJECTID,
|
||||||
|
A_ARG_TYPE_BROWSEFLAG,
|
||||||
|
A_ARG_TYPE_FILTER,
|
||||||
|
A_ARG_TYPE_SORTCRITERIA,
|
||||||
|
A_ARG_TYPE_INDEX,
|
||||||
|
A_ARG_TYPE_COUNT,
|
||||||
|
A_ARG_TYPE_UPDATEID,
|
||||||
|
A_ARG_TYPE_RESULT,
|
||||||
|
A_ARG_TYPE_SEARCHCRITERIA,
|
||||||
|
SEARCHCAPABILITIES,
|
||||||
|
SORTCAPABILITIES,
|
||||||
|
SYSTEMUPDATEID,
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
BROWSE,
|
||||||
|
SEARCH,
|
||||||
|
GETSEARCHCAPABILITIES,
|
||||||
|
GETSORTCAPABILITIES,
|
||||||
|
GETSYSTEMUPDATEID,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
use pmoupnp::define_variable;
|
||||||
|
|
||||||
|
define_variable! {
|
||||||
|
pub static A_ARG_TYPE_BROWSEFLAG: String = "A_ARG_TYPE_BrowseFlag" {
|
||||||
|
allowed: ["BrowseMetadata", "BrowseDirectChildren"],
|
||||||
|
evented: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use pmoupnp::define_variable;
|
||||||
|
|
||||||
|
define_variable! {
|
||||||
|
pub static A_ARG_TYPE_COUNT: UI4 = "A_ARG_TYPE_Count" {
|
||||||
|
evented: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use pmoupnp::define_variable;
|
||||||
|
|
||||||
|
define_variable! {
|
||||||
|
pub static A_ARG_TYPE_FILTER: String = "A_ARG_TYPE_Filter" {
|
||||||
|
evented: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use pmoupnp::define_variable;
|
||||||
|
|
||||||
|
define_variable! {
|
||||||
|
pub static A_ARG_TYPE_INDEX: UI4 = "A_ARG_TYPE_Index" {
|
||||||
|
evented: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use pmoupnp::define_variable;
|
||||||
|
|
||||||
|
define_variable! {
|
||||||
|
pub static A_ARG_TYPE_OBJECTID: String = "A_ARG_TYPE_ObjectID" {
|
||||||
|
evented: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use pmoupnp::define_variable;
|
||||||
|
|
||||||
|
define_variable! {
|
||||||
|
pub static A_ARG_TYPE_RESULT: String = "A_ARG_TYPE_Result" {
|
||||||
|
evented: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use pmoupnp::define_variable;
|
||||||
|
|
||||||
|
define_variable! {
|
||||||
|
pub static A_ARG_TYPE_SEARCHCRITERIA: String = "A_ARG_TYPE_SearchCriteria" {
|
||||||
|
evented: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use pmoupnp::define_variable;
|
||||||
|
|
||||||
|
define_variable! {
|
||||||
|
pub static A_ARG_TYPE_SORTCRITERIA: String = "A_ARG_TYPE_SortCriteria" {
|
||||||
|
evented: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use pmoupnp::define_variable;
|
||||||
|
|
||||||
|
define_variable! {
|
||||||
|
pub static A_ARG_TYPE_UPDATEID: UI4 = "A_ARG_TYPE_UpdateID" {
|
||||||
|
evented: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
25
pmomediaserver/src/contentdirectory/variables/mod.rs
Normal file
25
pmomediaserver/src/contentdirectory/variables/mod.rs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
mod a_arg_type_objectid;
|
||||||
|
mod a_arg_type_browseflag;
|
||||||
|
mod a_arg_type_filter;
|
||||||
|
mod a_arg_type_sortcriteria;
|
||||||
|
mod a_arg_type_index;
|
||||||
|
mod a_arg_type_count;
|
||||||
|
mod a_arg_type_updateid;
|
||||||
|
mod a_arg_type_result;
|
||||||
|
mod a_arg_type_searchcriteria;
|
||||||
|
mod searchcapabilities;
|
||||||
|
mod sortcapabilities;
|
||||||
|
mod systemupdateid;
|
||||||
|
|
||||||
|
pub use a_arg_type_objectid::A_ARG_TYPE_OBJECTID;
|
||||||
|
pub use a_arg_type_browseflag::A_ARG_TYPE_BROWSEFLAG;
|
||||||
|
pub use a_arg_type_filter::A_ARG_TYPE_FILTER;
|
||||||
|
pub use a_arg_type_sortcriteria::A_ARG_TYPE_SORTCRITERIA;
|
||||||
|
pub use a_arg_type_index::A_ARG_TYPE_INDEX;
|
||||||
|
pub use a_arg_type_count::A_ARG_TYPE_COUNT;
|
||||||
|
pub use a_arg_type_updateid::A_ARG_TYPE_UPDATEID;
|
||||||
|
pub use a_arg_type_result::A_ARG_TYPE_RESULT;
|
||||||
|
pub use a_arg_type_searchcriteria::A_ARG_TYPE_SEARCHCRITERIA;
|
||||||
|
pub use searchcapabilities::SEARCHCAPABILITIES;
|
||||||
|
pub use sortcapabilities::SORTCAPABILITIES;
|
||||||
|
pub use systemupdateid::SYSTEMUPDATEID;
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use pmoupnp::define_variable;
|
||||||
|
|
||||||
|
define_variable! {
|
||||||
|
pub static SEARCHCAPABILITIES: String = "SearchCapabilities" {
|
||||||
|
evented: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use pmoupnp::define_variable;
|
||||||
|
|
||||||
|
define_variable! {
|
||||||
|
pub static SORTCAPABILITIES: String = "SortCapabilities" {
|
||||||
|
evented: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use pmoupnp::define_variable;
|
||||||
|
|
||||||
|
define_variable! {
|
||||||
|
pub static SYSTEMUPDATEID: UI4 = "SystemUpdateID" {
|
||||||
|
evented: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
62
pmomediaserver/src/device.rs
Normal file
62
pmomediaserver/src/device.rs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
//! Définition du device MediaServer.
|
||||||
|
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use pmoupnp::devices::Device;
|
||||||
|
use crate::{
|
||||||
|
contentdirectory::CONTENTDIRECTORY,
|
||||||
|
connectionmanager::CONNECTIONMANAGER,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Device MediaServer UPnP.
|
||||||
|
///
|
||||||
|
/// MediaServer conforme UPnP AV Architecture 1.0.
|
||||||
|
///
|
||||||
|
/// # Services inclus
|
||||||
|
///
|
||||||
|
/// - **ContentDirectory:1** : Gestion du contenu et navigation
|
||||||
|
/// - **ConnectionManager:1** : Gestion des connexions
|
||||||
|
///
|
||||||
|
/// # Spécifications
|
||||||
|
///
|
||||||
|
/// - Device Type : `urn:schemas-upnp-org:device:MediaServer:1`
|
||||||
|
/// - Version : 1
|
||||||
|
/// - Manufacturer : PMOMusic
|
||||||
|
/// - Model : PMOMusic Media Server
|
||||||
|
///
|
||||||
|
/// # Exemple
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// use pmomediaserver::MEDIA_SERVER;
|
||||||
|
/// use pmoupnp::UpnpModel;
|
||||||
|
///
|
||||||
|
/// // Créer une instance du server
|
||||||
|
/// let server_instance = MEDIA_SERVER.create_instance();
|
||||||
|
///
|
||||||
|
/// // Accéder aux services
|
||||||
|
/// if let Some(content_directory) = server_instance.get_service("ContentDirectory") {
|
||||||
|
/// // Gérer le contenu...
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub static MEDIA_SERVER: Lazy<Arc<Device>> = Lazy::new(|| {
|
||||||
|
let mut device = Device::new(
|
||||||
|
"MediaServer".to_string(),
|
||||||
|
"MediaServer".to_string(),
|
||||||
|
"PMOMusic Media Server".to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
|
device.set_manufacturer("PMOMusic".to_string());
|
||||||
|
device.set_model_name("PMOMusic Media Server".to_string());
|
||||||
|
device.set_model_description("UPnP AV MediaServer for audio streaming".to_string());
|
||||||
|
device.set_udn_prefix("pmomusic".to_string());
|
||||||
|
|
||||||
|
// Ajouter les deux services obligatoires
|
||||||
|
device.add_service(Arc::clone(&CONTENTDIRECTORY))
|
||||||
|
.expect("Failed to add ContentDirectory service");
|
||||||
|
|
||||||
|
device.add_service(Arc::clone(&CONNECTIONMANAGER))
|
||||||
|
.expect("Failed to add ConnectionManager service");
|
||||||
|
|
||||||
|
Arc::new(device)
|
||||||
|
});
|
||||||
33
pmomediaserver/src/lib.rs
Normal file
33
pmomediaserver/src/lib.rs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
//! Module MediaServer UPnP.
|
||||||
|
//!
|
||||||
|
//! Ce module implémente un MediaServer UPnP conforme à la spécification
|
||||||
|
//! UPnP AV Architecture. Un MediaServer permet d'exposer et de servir du contenu audio
|
||||||
|
//! à des clients UPnP (MediaRenderer).
|
||||||
|
//!
|
||||||
|
//! # Architecture
|
||||||
|
//!
|
||||||
|
//! Le MediaServer est composé de deux services obligatoires :
|
||||||
|
//!
|
||||||
|
//! - **ContentDirectory** : Gestion du contenu et navigation dans la bibliothèque musicale
|
||||||
|
//! - **ConnectionManager** : Gestion des connexions et des protocoles supportés
|
||||||
|
//!
|
||||||
|
//! # Device UPnP
|
||||||
|
//!
|
||||||
|
//! - Type : `urn:schemas-upnp-org:device:MediaServer:1`
|
||||||
|
//! - Services : ContentDirectory:1, ConnectionManager:1
|
||||||
|
//!
|
||||||
|
//! # Utilisation
|
||||||
|
//!
|
||||||
|
//! ```ignore
|
||||||
|
//! use pmomediaserver::MEDIA_SERVER;
|
||||||
|
//!
|
||||||
|
//! // Le device est déjà configuré avec tous ses services
|
||||||
|
//! let server = MEDIA_SERVER.clone();
|
||||||
|
//! let instance = server.create_instance();
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
pub mod contentdirectory;
|
||||||
|
pub mod connectionmanager;
|
||||||
|
pub mod device;
|
||||||
|
|
||||||
|
pub use device::MEDIA_SERVER;
|
||||||
Reference in New Issue
Block a user