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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
// Copyright 2020 sacn Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//
// This file was modified as part of a University of St Andrews Computer Science BSC Senior Honours Dissertation Project.

//! Implementation of the sACN network protocol.
//!
//! This crate implements the Streaming ACN (sACN) network protocol as specified in ANSI E1.31-2018. Streaming ACN is built on top of and is 
//! compatible with the ACN protocol suite (ANSI E1.17-2015). This library supports sending and receiving data, universe synchronisation and
//! universe discovery. This library supports linux (fully) and windows (no receiving multicast) and IP unicast, multicast and broadcast.
//! 
//! Installation instructions are detailed within the README file.
//! 
//! 
//! 
//! This file was modified as part of a University of St Andrews Computer Science BSC Senior Honours Dissertation Project.
//! 
//! # Examples
//! 
//! Creating an sACN receiver and receiving data. This automatically handles receiving synchronised data at the right time with the array of received data
//! containing all the data which should be acted upon at the same time (so if there are 2 synchronised data packets the array will have length 2).
//! ```
//! use sacn::receive::SacnReceiver;
//! use sacn::packet::ACN_SDT_MULTICAST_PORT;
//! 
//! use std::net::{IpAddr, Ipv4Addr, SocketAddr};
//! use std::time::Duration;
//! 
//! const UNIVERSE1: u16 = 1;
//! const TIMEOUT: Option<Duration> = Some(Duration::from_secs(1)); // A timeout of None means blocking behaviour, some indicates the actual timeout.
//! 
//! let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), ACN_SDT_MULTICAST_PORT);
//!
//! let mut dmx_rcv = SacnReceiver::with_ip(addr, None).unwrap();
//!
//! dmx_rcv.listen_universes(&[UNIVERSE1]).unwrap();
//! 
//! // .recv(TIMEOUT) handles processing synchronised as-well as normal data.
//! match dmx_rcv.recv(TIMEOUT) {
//!     Err(e) => {
//!         // Print out the error.
//!         println!("{:?}", e);
//!     }
//!     Ok(p) => {
//!         // Print out the data.
//!         println!("{:?}", p);
//!     }
//! }
//! ```
//! 
//! Creating an sACN receiver and checking for discovered sources through universe discovery.
//! ```
//! use sacn::receive::SacnReceiver;
//! use sacn::packet::ACN_SDT_MULTICAST_PORT;
//! 
//! use std::net::{IpAddr, Ipv4Addr, SocketAddr};
//! use std::time::Duration;
//! 
//! const TIMEOUT: Option<Duration> = Some(Duration::from_secs(1)); // A timeout of None means blocking behaviour, some indicates the actual timeout.
//! 
//! let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), ACN_SDT_MULTICAST_PORT);
//!
//! // Creating the receiver, automatically listens for universe discovery packets.
//! let mut dmx_rcv = SacnReceiver::with_ip(addr, None).unwrap();
//! 
//! // Cause source discovery to be announced by a returned error. If this isn't true then discovery packets are still handled by the user must poll
//! // the discovered sources list periodically as there will be no announcement that a discovery packet has been processed. By default this option is
//! // off (false) based on the assumption that when receiving data the majority of the time the receiver just wants to process more data from the same
//! // universe and doesn't want to discover sources.
//! dmx_rcv.set_announce_source_discovery(true);
//! 
//! // Receive for a short period, no data is expected but this allows universe discovery packets to be received.
//! // This example will always timeout if run in isolation as there are no sources running on the network. 
//! match dmx_rcv.recv(TIMEOUT) {
//!     Err(e) => {
//!         match e.kind() {
//!             sacn::error::errors::ErrorKind::SourceDiscovered(source_name) => {
//!                 println!("Source name: {} discovered!", source_name);    
//!             }
//!             other => {
//!                 // Print out the error.
//!                 println!("{:?}", other);
//!             }
//!         }
//!     }
//!     Ok(p) => {
//!         // Print out the data. Note that no data is expected as no universes are registered for receiving data.
//!         println!("{:?}", p);
//!     }
//! }
//! ```
//! 
//! Creating a sACN sender and sending some unsychronised data. An sACNSender automatically sends universe discovery packets.
//! 
//! ```
//! use sacn::source::SacnSource;
//! use sacn::packet::ACN_SDT_MULTICAST_PORT;
//! use std::net::{IpAddr, SocketAddr};
//!
//! let local_addr: SocketAddr = SocketAddr::new(IpAddr::V4("0.0.0.0".parse().unwrap()), ACN_SDT_MULTICAST_PORT + 1);
//!
//! let mut src = SacnSource::with_ip("Source", local_addr).unwrap();
//!
//! let universe: u16 = 1;                        // Universe the data is to be sent on.
//! let sync_uni: Option<u16> = None;             // Don't want the packet to be delayed on the receiver awaiting synchronisation.
//! let priority: u8 = 100;                       // The priority for the sending data, must be 1-200 inclusive,  None means use default.
//! let dst_ip: Option<SocketAddr> = None;        // Sending the data using IP multicast so don't have a destination IP.
//!
//! src.register_universe(universe).unwrap(); // Register with the source that will be sending on the given universe.
//!
//! let mut data: Vec<u8> = vec![0, 0, 0, 0, 255, 255, 128, 128]; // Some arbitrary data, must have length <= 513 (including start-code).
//!
//! src.send(&[universe], &data, Some(priority), dst_ip, sync_uni).unwrap(); // Actually send the data
//! 
//! ```
//! 
//! Creating a sACN sender and sending some synchronised data. 
//! 
//! ```
//! use sacn::source::SacnSource;
//! use sacn::packet::ACN_SDT_MULTICAST_PORT;
//! 
//! use std::net::{IpAddr, SocketAddr};
//! use std::thread::sleep;
//! use std::time::Duration;
//!
//! let local_addr: SocketAddr = SocketAddr::new(IpAddr::V4("0.0.0.0".parse().unwrap()), ACN_SDT_MULTICAST_PORT + 1);
//!
//! let mut src = SacnSource::with_ip("Source", local_addr).unwrap();
//!
//! let universe: u16 = 1;                        // Universe the data is to be sent on.
//! let sync_uni: Option<u16> = Some(1);          // Data packets use a synchronisation address of 1.
//! let priority: u8 = 100;                       // The priority for the sending data, must be 1-200 inclusive,  None means use default.
//! let dst_ip: Option<SocketAddr> = None;        // Sending the data using IP multicast so don't have a destination IP.
//!
//! src.register_universe(universe).unwrap(); // Register with the source that will be sending on the given universe.
//!
//! let mut data: Vec<u8> = vec![0, 0, 0, 0, 255, 255, 128, 128]; // Some arbitrary data, must have length <= 513 (including start-code).
//!
//! // Actually send the data, since the sync_uni is not 0 the data will be synchronised at the receiver (if the receiver supports synchronisation).
//! src.send(&[universe], &data, Some(priority), dst_ip, sync_uni).unwrap();
//! 
//! // A small delay between sending data and sending the sync packet as recommend in ANSI E1.31-2018 Section 11.2.2.
//! sleep(Duration::from_millis(10));
//! 
//! // To actually trigger the data need to send a synchronisation packet like so.
//! src.send_sync_packet(sync_uni.unwrap(), dst_ip).unwrap();
//! ```
//! 
//! Creating a sACN sender and sending data using unicast.
//! 
//! ```
//! use sacn::source::SacnSource;
//! use sacn::packet::ACN_SDT_MULTICAST_PORT;
//! 
//! use std::net::{IpAddr, SocketAddr};
//! use std::thread::sleep;
//! use std::time::Duration;
//!
//! let local_addr: SocketAddr = SocketAddr::new(IpAddr::V4("0.0.0.0".parse().unwrap()), ACN_SDT_MULTICAST_PORT + 1);
//!
//! let mut src = SacnSource::with_ip("Source", local_addr).unwrap();
//!
//! let universe: u16 = 1;                        // Universe the data is to be sent on.
//! let sync_uni: Option<u16> = None;             // Data packets are unsynchronised in this example but unicast transmission supports synchronised and unsynchronised sending.
//! let priority: Option<u8> = Some(100);                       // The priority for the sending data, must be 1-200 inclusive,  None means use default.
//! 
//! // To send using unicast the dst_ip argument is set to a Some() value with the address to send the data to. By default the port should be the
//! // ACN_SDT_MULTICAST_PORT but this can be configured differently if required in a specific situation. Change this address to the correct address for your
//! // application, 192.168.0.1 is just a stand-in.
//! let destination_address: SocketAddr = SocketAddr::new(IpAddr::V4("192.168.0.1".parse().unwrap()), ACN_SDT_MULTICAST_PORT);
//! let dst_ip: Option<SocketAddr> = Some(destination_address);
//!
//! src.register_universe(universe).unwrap(); // Register with the source that will be sending on the given universe.
//!
//! let mut data: Vec<u8> = vec![0, 0, 0, 0, 255, 255, 128, 128]; // Some arbitrary data, must have length <= 513 (including start-code).
//!
//! // Actually send the data, since the sync_uni is not 0 the data will be synchronised at the receiver (if the receiver supports synchronisation).
//! src.send(&[universe], &data, priority, dst_ip, sync_uni).unwrap();
//! ```

#![doc(html_root_url = "https://docs.rs/sacn/")]
// #![warn(missing_docs)]
// Recursion limit for error_chain.
#![recursion_limit="1024"]

#[macro_use]
extern crate error_chain;

/// The errors within the sACN crate related to parse/pack errors.
/// Error-chain is used for errors within the library to allow chaining errors together to provide more informative backtraces.
/// This completely replaces the old error system (sACN crate version 0.4.4) which relied on a simple Enum model without proper backtraces.
pub mod sacn_parse_pack_error;

/// The errors used within the sACN crate, parse/pack errors are seperated out into sacn_parse_pack_error.
pub mod error;

/// The library is built on top of socket2 to provide the underlying UDP networking interface.
extern crate socket2;
extern crate libc;

/// The core crate is used for string processing during packet parsing/packing as well as to provide access to the Hash trait.
extern crate core;

/// The byteorder crate is used for marshalling data on/off the network in Network Byte Order.
extern crate byteorder;

/// The uuid crate is used for working with/generating UUIDs which sACN uses as part of the cid field in the protocol.
extern crate uuid;

/// The packet module handles the sACN packets including parsing/packing and sACN related constants.
pub mod packet;

/// The source module handles generation of sACN on the network.
pub mod source;

/// The receive module handles the receiving of sACN on the network.
pub mod receive;