This is a UPnP client library for Rust.
1<h1>UPnP Client</h1>
2<p>
3 <a href="LICENSE" target="_blank">
4 <img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-blue.svg" />
5 </a>
6 <a href="https://crates.io/crates/upnp-client" target="_blank">
7 <img src="https://img.shields.io/crates/v/upnp-client.svg" />
8 </a>
9
10 <a href="https://crates.io/crates/upnp-client" target="_blank">
11 <img src="https://img.shields.io/crates/dr/upnp-client" />
12 </a>
13
14 <a href="https://docs.rs/upnp-client" target="_blank">
15 <img src="https://docs.rs/upnp-client/badge.svg" />
16 </a>
17</p>
18
19This is a UPNP client library for Rust.
20
21### Usage
22
23Add this to your `Cargo.toml`:
24
25```toml
26[dependencies]
27upnp-client = "0.1"
28```
29
30### Example
31
32This example will print out all the devices found on the network.
33
34```rust
35use colored_json::prelude::*;
36use futures_util::StreamExt;
37
38use crate::discovery::discover_pnp_locations;
39
40mod discovery;
41mod types;
42
43#[tokio::main]
44async fn main() -> Result<(), Box<dyn std::error::Error>> {
45 let devices = discover_pnp_locations().await?;
46 tokio::pin!(devices);
47
48 while let Some(device) = devices.next().await {
49 let json = serde_json::to_string_pretty(&device)?;
50 println!("{}", json.to_colored_json_auto()?);
51 }
52
53 Ok(())
54}
55```
56
57Output:
58
59```json
60{
61 "device_type": "urn:schemas-upnp-org:device:MediaRenderer:1",
62 "friendly_name": "Kodi (MacBook-Pro-de-Tsiry-4.local)",
63 "location": "http://192.168.8.101:1825/",
64 "manufacturer": "XBMC Foundation",
65 "manufacturer_url": "http://kodi.tv/",
66 "model_description": "Kodi - Media Renderer",
67 "model_name": "Kodi",
68 "model_number": "18.4 Git:20190831-3ade758ceb",
69 "services": [
70 {
71 "control_url": "/AVTransport/d599320b-2d3b-e0d7-3224-dc1c4b074dae/control.xml",
72 "event_sub_url": "/AVTransport/d599320b-2d3b-e0d7-3224-dc1c4b074dae/event.xml",
73 "scpd_url": "/AVTransport/d599320b-2d3b-e0d7-3224-dc1c4b074dae/scpd.xml",
74 "service_id": "urn:upnp-org:serviceId:AVTransport",
75 "service_type": "urn:schemas-upnp-org:service:AVTransport:1"
76 },
77 {
78 "control_url": "/ConnectionManager/d599320b-2d3b-e0d7-3224-dc1c4b074dae/control.xml",
79 "event_sub_url": "/ConnectionManager/d599320b-2d3b-e0d7-3224-dc1c4b074dae/event.xml",
80 "scpd_url": "/ConnectionManager/d599320b-2d3b-e0d7-3224-dc1c4b074dae/scpd.xml",
81 "service_id": "urn:upnp-org:serviceId:ConnectionManager",
82 "service_type": "urn:schemas-upnp-org:service:ConnectionManager:1"
83 },
84 {
85 "control_url": "/RenderingControl/d599320b-2d3b-e0d7-3224-dc1c4b074dae/control.xml",
86 "event_sub_url": "/RenderingControl/d599320b-2d3b-e0d7-3224-dc1c4b074dae/event.xml",
87 "scpd_url": "/RenderingControl/d599320b-2d3b-e0d7-3224-dc1c4b074dae/scpd.xml",
88 "service_id": "urn:upnp-org:serviceId:RenderingControl",
89 "service_type": "urn:schemas-upnp-org:service:RenderingControl:1"
90 }
91 ]
92}
93```
94
95## Streaming
96
97```rust
98use futures_util::StreamExt;
99use upnp_client::{
100 device_client::DeviceClient,
101 discovery::discover_pnp_locations,
102 media_renderer::MediaRendererClient,
103 types::{Device, LoadOptions, Metadata, ObjectClass},
104};
105
106const KODI_MEDIA_RENDERER: &str = "Kodi - Media Renderer";
107
108#[tokio::main]
109async fn main() -> Result<(), Box<dyn std::error::Error>> {
110 let devices = discover_pnp_locations().await?;
111 tokio::pin!(devices);
112
113 let mut kodi_device: Option<Device> = None;
114 while let Some(device) = devices.next().await {
115 // Select the first Kodi device found
116 if device.model_description == Some(KODI_MEDIA_RENDERER.to_string()) {
117 kodi_device = Some(device);
118 break;
119 }
120 }
121
122 let kodi_device = kodi_device.unwrap();
123 let device_client = DeviceClient::new(&kodi_device.location)?.connect().await?;
124 let media_renderer = MediaRendererClient::new(device_client);
125
126 let options = LoadOptions {
127 dlna_features: Some(
128 "DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01700000000000000000000000000000"
129 .to_string(),
130 ),
131 content_type: Some("video/mp4".to_string()),
132 metadata: Some(Metadata {
133 title: "Big Buck Bunny".to_string(),
134 ..Default::default()
135 }),
136 autoplay: true,
137 object_class: Some(ObjectClass::Video),
138 ..Default::default()
139 };
140
141 let media_url =
142 "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4";
143
144 media_renderer.load(media_url, options).await?;
145
146 Ok(())
147}
148
149
150```
151
152See the [examples](./examples) directory for more examples.
153
154### Features
155
156- [x] Discover devices
157- [x] Control Media Renderer device (Load, Play, Pause, Stop, Seek, etc.)
158- [x] Browse Media Server device
159
160
161### References
162- [UPnP Device Architecture 1.1](http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.1.pdf)
163- [UPnP AVTransport v3 Service](http://www.upnp.org/specs/av/UPnP-av-AVTransport-v3-Service-20101231.pdf)
164- [UPnP AV ContentDirectory v3 Service](http://upnp.org/specs/av/UPnP-av-ContentDirectory-v3-Service.pdf)
165
166### License
167MIT