1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//! # oxvif
//!
//! An async Rust client library for the [ONVIF] IP camera protocol.
//!
//! ONVIF (Open Network Video Interface Forum) is the industry standard for
//! interoperability between IP-based security cameras. This library provides
//! a complete async client covering device management, media streaming,
//! PTZ control, imaging, on-screen display, events, recording, search, and
//! replay — all over SOAP/HTTP(S) with WS-Security authentication.
//!
//! ## ONVIF Profile coverage
//!
//! | Profile | Description | Coverage |
//! |---------|-------------|----------|
//! | **Profile S** | Video streaming | ~100% |
//! | **Profile T** | Advanced streaming (H.265, focus, OSD) | ~75% |
//! | **Profile G** | Recording & playback | ~80% |
//!
//! ## Supported services
//!
//! - **Device** — capabilities, scopes, device info, hostname, NTP, reboot
//! - **Media1 / Media2** — profiles, RTSP/snapshot URIs, video + audio config, OSD
//! - **PTZ** — absolute/relative/continuous move, presets, home position, status
//! - **Imaging** — brightness/contrast/exposure settings, focus move/stop/status
//! - **Events** — pull-point subscriptions, event polling, renew, unsubscribe
//! - **Recording** — list stored recordings
//! - **Search** — find recordings by scope, collect results, end search
//! - **Replay** — get RTSP playback URI for a stored recording
//! - **WS-Discovery** — UDP multicast probe to find cameras on the local network
//!
//! ## Architecture
//!
//! ```text
//! ┌──────────────────────────────────────────────────────┐
//! │ OnvifClient │ ← public API
//! ├──────────────────────────────────────────────────────┤
//! │ soap::SoapEnvelope │ soap::WsSecurityToken │ ← SOAP layer
//! ├──────────────────────────────────────────────────────┤
//! │ Transport trait │ ← HTTP abstraction
//! │ (HttpTransport / mock in tests) │
//! └──────────────────────────────────────────────────────┘
//! ```
//!
//! ## Quick start
//!
//! ```no_run
//! use oxvif::{OnvifClient, OnvifError};
//!
//! async fn run() -> Result<(), OnvifError> {
//! let client = OnvifClient::new("http://192.168.1.100/onvif/device_service")
//! .with_credentials("admin", "password");
//!
//! // Sync device clock for WS-Security timestamps
//! let dt = client.get_system_date_and_time().await?;
//! let client = client.with_utc_offset(dt.utc_offset_secs());
//!
//! // Discover service endpoints
//! let caps = client.get_capabilities().await?;
//! let media_url = caps.media.url.as_deref().unwrap();
//!
//! // List media profiles and get the first RTSP stream URI
//! let profiles = client.get_profiles(media_url).await?;
//! let uri = client.get_stream_uri(media_url, &profiles[0].token).await?;
//! println!("RTSP stream: {}", uri.uri);
//! Ok(())
//! }
//! ```
//!
//! ## Testing without a real camera
//!
//! Implement [`transport::Transport`] to inject any XML fixture:
//!
//! ```no_run
//! use oxvif::transport::{Transport, TransportError};
//! use async_trait::async_trait;
//! use std::sync::Arc;
//!
//! struct MockTransport { xml: String }
//!
//! #[async_trait]
//! impl Transport for MockTransport {
//! async fn soap_post(&self, _url: &str, _action: &str, _body: String)
//! -> Result<String, TransportError>
//! {
//! Ok(self.xml.clone())
//! }
//! }
//!
//! # async fn example() {
//! let client = oxvif::OnvifClient::new("http://ignored")
//! .with_transport(Arc::new(MockTransport { xml: "<s:Envelope/>".into() }));
//! # }
//! ```
//!
//! [ONVIF]: https://www.onvif.org
pub use OnvifClient;
pub use DiscoveredDevice;
pub use OnvifError;
pub use ;