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