├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── portaudio.lib ├── portaudio_x64.dll └── src ├── analysis ├── analysis.rs ├── mod.rs ├── pa_source.rs ├── rms.rs ├── soundio_source.rs └── traits.rs ├── client_test └── main.rs ├── lib.rs ├── server ├── main.rs ├── messages.rs └── mod.rs └── test └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock 7 | Cargo.lock 8 | target 9 | Cargo.lock 10 | 11 | *.sublime-project 12 | *.sublime-workspace 13 | 14 | .vscode -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "audio-analysis" 3 | version = "0.1.0" 4 | authors = ["tzaeru "] 5 | 6 | [dependencies] 7 | portaudio = "0.7.0" 8 | lazy_static = "0.2" 9 | soundio = {git = "https://github.com/Timmmm/soundio-rs"} 10 | 11 | [[bin]] 12 | name = "server" 13 | path = "src/server/main.rs" 14 | 15 | [[bin]] 16 | name = "client-test" 17 | path = "src/client_test/main.rs" 18 | 19 | [[bin]] 20 | name = "test" 21 | path = "src/test/main.rs" 22 | 23 | [lib] 24 | name = "raa" 25 | path = "src/lib.rs" 26 | crate-type = ["cdylib", "rlib"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 tzaeru 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # rust-audio-analysis 3 | RAA! 4 | 5 | RAA is an audio analysis framework, for Rust. It aims to be relatively extensible. Audio analysis is done via chains, which have a source and multiple nodes. 6 | 7 | The basic workflow is that you create a chain, add a source node to it and add analysis nodes to it. Then you can pick out values from the analysis nodes. This way, you can combine filters and analysis algorithms in any way you like. You can also use the same source node for multiple chains, thus saving on performance. 8 | 9 | One might, for example, combine FFT with a high-pass filter and RMS with a peak detection and use the same source for both. 10 | 11 | RAA is still work under progress and many of its features are missing. 12 | 13 | Currently it has: 14 | 15 | - libsoundio support. 16 | - PortAudio support. 17 | - Basic structure for chains and nodes. 18 | - RMS node. 19 | - Server component for remote use. 20 | 21 | Currently it's missing: 22 | 23 | - Reading audio from a file. 24 | - All interesting algorithms (FFT, high/low pass filters, etc) 25 | - Proper file structure & cleanup.. 26 | 27 | Examples coming at some point (sooner if there's interest for someone to contribute, later if there's not!) 28 | -------------------------------------------------------------------------------- /portaudio.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tzaeru/rust-audio-analysis/5204e59872698e433d24a69c80260bc006f309c5/portaudio.lib -------------------------------------------------------------------------------- /portaudio_x64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tzaeru/rust-audio-analysis/5204e59872698e433d24a69c80260bc006f309c5/portaudio_x64.dll -------------------------------------------------------------------------------- /src/analysis/analysis.rs: -------------------------------------------------------------------------------- 1 | //! A demonstration of constructing and using a non-blocking stream. 2 | //! 3 | //! Audio from the default input device is passed directly to the default output device in a duplex 4 | //! stream, so beware of feedback! 5 | 6 | extern crate soundio; 7 | 8 | use std::collections::HashMap; 9 | use analysis::traits::Sourcable; 10 | use analysis::traits::Chainable; 11 | 12 | use std::sync::Arc; 13 | use std::sync::RwLock; 14 | 15 | pub struct Arena { 16 | pub sourcables: HashMap>>, 17 | pub chainables: HashMap>>, 18 | 19 | created_nodes: u64, 20 | } 21 | 22 | impl Arena { 23 | pub fn new() -> Arena { 24 | Arena { 25 | sourcables: HashMap::new(), 26 | chainables: HashMap::new(), 27 | created_nodes: 0, 28 | } 29 | } 30 | 31 | pub fn add_sourcable(&mut self, sourcable: Arc>) -> u64 { 32 | let id = self.created_nodes; 33 | 34 | self.sourcables.clear(); 35 | self.sourcables.insert(id, sourcable); 36 | self.created_nodes += 1; 37 | 38 | return id; 39 | } 40 | 41 | pub fn add_chainable(&mut self, chainable: Arc>) -> u64 { 42 | let id = self.created_nodes; 43 | 44 | self.chainables.insert(id, chainable); 45 | self.created_nodes += 1; 46 | 47 | return id; 48 | } 49 | 50 | pub fn remove_sourcable(&mut self, id: u64) { 51 | self.sourcables.remove(&id); 52 | } 53 | 54 | pub fn remove_chainable(&mut self, id: u64) { 55 | self.chainables.remove(&id); 56 | } 57 | } 58 | 59 | pub struct Chain { 60 | arena: Arc>, 61 | 62 | source: Option, 63 | nodes: Vec, 64 | 65 | pub running: bool, 66 | } 67 | 68 | impl Chain { 69 | pub fn new(arena: Arc>) -> Chain { 70 | Chain { 71 | arena: arena, 72 | 73 | source: Option::None, 74 | nodes: Vec::new(), 75 | 76 | running: false, 77 | } 78 | } 79 | 80 | 81 | pub fn start(&mut self, self_ref: Arc>) { 82 | match self.source { 83 | Some(source) => 84 | { 85 | let arena_borrow = self.arena.read().unwrap(); 86 | arena_borrow.sourcables[&source].write().unwrap().start(self_ref); 87 | self.running = true; 88 | }, 89 | None => println!("No sourcable set."), 90 | } 91 | } 92 | 93 | pub fn stop(&mut self) { 94 | self.running = false; 95 | match self.source { 96 | Some(source) => 97 | { 98 | let arena_borrow = self.arena.read().unwrap(); 99 | arena_borrow.sourcables[&source].write().unwrap().stop(); 100 | self.running = true; 101 | }, 102 | None => println!("No sourcable set for chain."), 103 | } 104 | } 105 | 106 | pub fn source_cb(&self, buffer: Vec>, _frames: usize) { 107 | if self.running == true 108 | { 109 | for i in 0..self.nodes.len() { 110 | let node = &self.arena.read().unwrap().chainables[&self.nodes[i]]; 111 | node.write().unwrap().update(&buffer); 112 | } 113 | } 114 | } 115 | 116 | pub fn set_source(&mut self, source: u64) { 117 | self.source = Option::Some(source); 118 | } 119 | 120 | pub fn add_node(&mut self, node: u64) { 121 | self.nodes.push(node); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/analysis/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod analysis; 2 | pub mod traits; 3 | pub mod pa_source; 4 | pub mod soundio_source; 5 | pub mod rms; -------------------------------------------------------------------------------- /src/analysis/pa_source.rs: -------------------------------------------------------------------------------- 1 | 2 | extern crate portaudio as pa; 3 | 4 | use analysis::traits::Sourcable; 5 | use analysis::analysis::Chain; 6 | use std::sync::Arc; 7 | use std::sync::RwLock; 8 | use std::collections::HashMap; 9 | 10 | const SAMPLE_RATE: f64 = 44_100.0; 11 | const FRAMES: u32 = 256; 12 | const INTERLEAVED: bool = true; 13 | 14 | lazy_static! { 15 | static ref PORTAUDIO: pa::PortAudio = { 16 | let pa = pa::PortAudio::new(); 17 | match pa 18 | { 19 | Result::Ok(val) => val, 20 | Result::Err(err) => 21 | panic!("called `Result::unwrap()` on an `Err` value: {:?}", err), 22 | } 23 | }; 24 | } 25 | 26 | pub struct PASource { 27 | device: u32, 28 | channels: Vec, 29 | 30 | stream: Option>>, 31 | 32 | error: String 33 | } 34 | 35 | impl PASource { 36 | pub fn new(device: String, channels: Vec) -> PASource { 37 | PASource { 38 | device: device.parse::().unwrap(), 39 | channels: channels, 40 | 41 | stream: Option::None, 42 | 43 | error: "".to_string() 44 | } 45 | } 46 | } 47 | 48 | impl Sourcable for PASource { 49 | fn start(&mut self, chain: Arc>) -> () { 50 | let device_info = PORTAUDIO.device_info(pa::DeviceIndex { 0: self.device }).unwrap(); 51 | 52 | let input_params = pa::StreamParameters::::new(pa::DeviceIndex { 0: self.device }, 53 | device_info.max_input_channels, 54 | INTERLEAVED, 55 | 0.0f64); 56 | 57 | let channels = self.channels.to_vec(); 58 | let audio_callback = move |pa::InputStreamCallbackArgs { buffer, frames, .. }| { 59 | // Unleave 60 | let mut unleaved_buffer:Vec> = Vec::new(); 61 | 62 | // Initialize with empty arrays for each channel 63 | for _ in 0..channels.len() 64 | { 65 | unleaved_buffer.push(Vec::new()); 66 | } 67 | // Iterate through the whole interleaved buffer, moving it to unleaved buffer. 68 | let mut i = 0i32; 69 | while i < buffer.len() as i32 70 | { 71 | // Iterate through all the channels we want. 72 | for j in 0..channels.len() 73 | { 74 | // Since 'i' points to 1st channel, we'll take element i + channel index (starting from 0) from the interleaved buffer. 75 | unleaved_buffer[j].push(buffer[i as usize + channels[j] as usize]); 76 | } 77 | 78 | // Increase index to next set of channels. I.e. index points to 1st interleaved channel for each sample frame. 79 | i += device_info.max_input_channels; 80 | } 81 | 82 | chain.write().unwrap().source_cb(unleaved_buffer, frames); 83 | 84 | if chain.write().unwrap().running == true 85 | { 86 | pa::Continue 87 | } 88 | else { 89 | pa::Complete 90 | } 91 | }; 92 | 93 | 94 | let settings = pa::InputStreamSettings::new(input_params, SAMPLE_RATE, FRAMES); 95 | let mut stream = PORTAUDIO.open_non_blocking_stream(settings, audio_callback).unwrap(); 96 | println!("Starting stream for realz.."); 97 | 98 | let _ = stream.start(); 99 | 100 | self.stream = Option::Some(stream); 101 | } 102 | 103 | fn stop(&mut self) -> () {} 104 | 105 | fn is_active(&self) -> bool 106 | { 107 | match self.stream 108 | { 109 | Some(ref stream) => return stream.is_active().unwrap(), 110 | None => return false 111 | } 112 | } 113 | 114 | fn get_devices() -> Result, ()> where Self: Sized 115 | { 116 | let mut devices = HashMap::new(); 117 | 118 | let default_host = PORTAUDIO.default_host_api().unwrap(); 119 | 120 | for i in 0..PORTAUDIO.host_api_info(default_host).unwrap().device_count { 121 | let device_index = 122 | PORTAUDIO.api_device_index_to_device_index(default_host, i as i32).unwrap(); 123 | let input_info = PORTAUDIO.device_info(device_index).unwrap(); 124 | 125 | if input_info.max_input_channels <= 0 126 | { 127 | continue; 128 | } 129 | 130 | devices.insert(device_index.0.to_string(), 131 | (input_info.name.to_string(), input_info.max_input_channels)); 132 | } 133 | 134 | return Ok(devices); 135 | } 136 | 137 | fn get_and_clear_error(&self) -> Option 138 | { 139 | return None; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/analysis/rms.rs: -------------------------------------------------------------------------------- 1 | use analysis::traits::Chainable; 2 | 3 | pub struct RMS { 4 | buffer: Vec, 5 | } 6 | 7 | impl RMS { 8 | pub fn new() -> RMS { 9 | RMS { buffer: Vec::new() } 10 | } 11 | } 12 | 13 | impl Chainable for RMS { 14 | fn update(&mut self, buffer: &Vec>) { 15 | 16 | let mut rms = 0f32; 17 | for i in 0..buffer.len() 18 | { 19 | let mut square_sum = 0.0f32; 20 | for x in 0..buffer[i].len() { 21 | square_sum += buffer[i][x] * buffer[i][x]; 22 | } 23 | 24 | let square_mean = square_sum * 1.0f32 / buffer.len() as f32; 25 | 26 | rms += f32::sqrt(square_mean); 27 | } 28 | 29 | rms /= buffer.len() as f32; 30 | 31 | self.buffer = Vec::new(); 32 | self.buffer.push(rms); 33 | } 34 | 35 | fn output(&self) -> &Vec { 36 | &self.buffer 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/analysis/soundio_source.rs: -------------------------------------------------------------------------------- 1 | extern crate soundio; 2 | 3 | use std::collections::HashMap; 4 | use analysis::traits::Sourcable; 5 | use analysis::traits::Chainable; 6 | use analysis::analysis::Chain; 7 | 8 | use std; 9 | 10 | use std::sync::Arc; 11 | use std::sync::RwLock; 12 | 13 | lazy_static! { 14 | static ref SOUNDIO_CTX: soundio::Context<'static> = { 15 | let mut ctx = soundio::Context::new(); 16 | ctx.set_app_name("RAA!"); 17 | ctx.connect().unwrap(); 18 | ctx.flush_events(); 19 | 20 | println!("Soundio version: {}", soundio::version_string()); 21 | println!("Current backend: {:?}", ctx.current_backend()); 22 | for dev in ctx.input_devices().unwrap() { 23 | println!("Device {} ", dev.name()); 24 | println!("Is raw: {}", dev.is_raw()); 25 | } 26 | return ctx; 27 | }; 28 | } 29 | 30 | pub struct SoundioSource<'a> { 31 | device: String, 32 | channels: Vec, 33 | 34 | stream: Option>, 35 | 36 | error: Arc> 37 | } 38 | 39 | impl<'a> SoundioSource<'a> { 40 | pub fn new (device: String, channels: Vec) -> SoundioSource<'a> { 41 | SoundioSource { 42 | device: device, 43 | channels: channels, 44 | 45 | stream: Option::None, 46 | 47 | error: Arc::new(RwLock::new("".to_string())) 48 | } 49 | } 50 | } 51 | 52 | impl<'a> Sourcable for SoundioSource<'a> { 53 | fn start(&mut self, chain: Arc>) -> () { 54 | 55 | let channels = self.channels.to_vec(); 56 | let audio_callback = move |stream: &mut soundio::InStreamReader| { 57 | // Unleave 58 | let mut unleaved_buffer:Vec> = Vec::new(); 59 | 60 | // Initialize with empty arrays for each channel 61 | for _ in 0..channels.len() 62 | { 63 | unleaved_buffer.push(Vec::new()); 64 | } 65 | // Iterate through the whole interleaved buffer, moving it to unleaved buffer. 66 | let mut frames_left = stream.frame_count_max(); 67 | loop { 68 | if let Err(e) = stream.begin_read(frames_left) { 69 | println!("Error reading from stream: {}", e); 70 | return; 71 | } 72 | 73 | for f in 0..stream.frame_count() { 74 | for ch_i in 0..channels.len() { 75 | if f%5000 == 0 76 | { 77 | //println!("{}", stream.sample::(channels[ch_i] as usize, f)); 78 | } 79 | 80 | let mut value = (stream.sample::(channels[ch_i] as usize, f) as f32)/std::i32::MAX as f32; 81 | if !value.is_normal() 82 | { 83 | value = 0.0f32; 84 | } 85 | unleaved_buffer[ch_i].push(value); 86 | } 87 | } 88 | 89 | frames_left -= stream.frame_count(); 90 | if frames_left <= 0 { 91 | break; 92 | } 93 | 94 | stream.end_read(); 95 | } 96 | match chain.try_write() { 97 | Ok(lock) => lock.source_cb(unleaved_buffer, stream.frame_count()), 98 | Err(e) => println!("Error writing to chain: {:?}", e) 99 | } 100 | 101 | return (); 102 | }; 103 | 104 | let error_capture = self.error.clone(); 105 | let error_callback = move |error: soundio::Error| { 106 | println!("Error: {:?}", error); 107 | let mut write_lock = error_capture.write().unwrap(); 108 | *write_lock = error.to_string(); 109 | }; 110 | 111 | let soundio_format = soundio::Format::S16LE; 112 | println!("Going to get default input device.."); 113 | // pa::input, pa::NonBlocking 114 | let mut devices = SOUNDIO_CTX.input_devices().unwrap(); 115 | let mut input_dev = &mut SOUNDIO_CTX.default_input_device().map_err(|_| "Error getting default input device".to_string()).unwrap(); 116 | for device in devices.iter_mut() 117 | { 118 | if device.id() == self.device 119 | { 120 | println!("Found a match: {}", device.id()); 121 | input_dev = device; 122 | break; 123 | } 124 | } 125 | 126 | let sample_rate = input_dev.nearest_sample_rate(44100); 127 | 128 | input_dev.sort_channel_layouts(); 129 | let layout = input_dev.layouts()[0].clone(); 130 | println!("Got default input device: {:?}", input_dev.name()); 131 | println!("Aim: {:?}", input_dev.aim()); 132 | println!("Formats: {:?}", input_dev.formats()); 133 | println!("Sample rates: {:?}", input_dev.sample_rates()); 134 | println!("Layouts: {:?}", input_dev.layouts()); 135 | let mut stream = input_dev.open_instream( 136 | sample_rate, 137 | soundio_format, 138 | layout, 139 | (1.0/20.0 * sample_rate as f64) / sample_rate as f64, 140 | audio_callback, 141 | None::, 142 | Some(error_callback), 143 | ).unwrap(); 144 | println!("Starting soundio stream.."); 145 | 146 | stream.start().unwrap(); 147 | 148 | self.stream = Option::Some(stream); 149 | } 150 | 151 | fn stop(&mut self) -> () { 152 | println!("Stopping SoundIO source."); 153 | self.stream.take().unwrap().pause(true).unwrap(); 154 | println!("Stopped SoundIO Source!"); 155 | } 156 | 157 | fn is_active(&self) -> bool 158 | { 159 | match self.stream 160 | { 161 | Some(ref stream) => true, 162 | None => return false 163 | } 164 | } 165 | 166 | fn get_devices() -> Result, ()> where Self: Sized 167 | { 168 | let mut devices = HashMap::new(); 169 | 170 | for mut dev in SOUNDIO_CTX.input_devices().unwrap() { 171 | dev.sort_channel_layouts(); 172 | devices.insert(dev.id(), (dev.name(), dev.layouts()[0].channels.len() as i32)); 173 | } 174 | 175 | return Ok(devices); 176 | } 177 | 178 | fn get_and_clear_error(&self) -> Option 179 | { 180 | let error_clone = self.error.read().unwrap().clone(); 181 | if error_clone.len() <= 0 182 | { 183 | return None; 184 | } 185 | *self.error.write().unwrap() = "".to_string(); 186 | 187 | return Some(error_clone); 188 | } 189 | } 190 | 191 | impl<'a> Drop for SoundioSource<'a> { 192 | fn drop(&mut self) { 193 | println!("Dropping SoundioSource!"); 194 | } 195 | } -------------------------------------------------------------------------------- /src/analysis/traits.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | use std; 3 | 4 | use std::sync::Arc; 5 | use std::sync::RwLock; 6 | use std::rc::Rc; 7 | use std::collections::HashMap; 8 | use analysis::analysis::Chain; 9 | 10 | 11 | pub trait Sourcable { 12 | fn start(&mut self, chain: Arc>); 13 | fn stop(&mut self); 14 | fn get_devices() -> Result, ()> where Self: Sized; 15 | fn is_active(&self) -> bool; 16 | fn get_and_clear_error(&self) -> Option; 17 | } 18 | 19 | pub trait Chainable { 20 | fn update(&mut self, buffer: &Vec>); 21 | fn output(&self) -> &Vec; 22 | } 23 | -------------------------------------------------------------------------------- /src/client_test/main.rs: -------------------------------------------------------------------------------- 1 | use std::io::prelude::*; 2 | use std::net::TcpStream; 3 | 4 | extern crate raa; 5 | use raa::server::messages; 6 | use raa::server::messages::Serializable; 7 | 8 | fn request_rms(mut stream: &TcpStream) -> Result 9 | { 10 | let mut rms_msg = messages::MsgStartStreamRMS::new(); 11 | rms_msg.device_id = "{0.0.1.00000000}.{625fb92c-394b-482e-82ed-30b560d85d8f}".to_string(); 12 | rms_msg.channels = vec![0, 1]; 13 | 14 | let mut serialized = rms_msg.serialize(); 15 | stream.write(serialized.as_mut_slice()) 16 | } 17 | 18 | fn main() { 19 | if let Ok(mut stream) = TcpStream::connect("127.0.0.1:50000") { 20 | println!("Connected to the server!"); 21 | let _ = request_rms(&stream); 22 | loop { 23 | let mut data = [0u8; 2048]; 24 | match stream.read(&mut data) 25 | { 26 | Ok(result) => { 27 | if result <= 0 28 | { 29 | continue; 30 | } 31 | 32 | let length: i32 = data[0] as i32 | ((data[1] as i32) << 8) | ((data[2] as i32) << 16) | ((data[3] as i32) << 24); 33 | 34 | let msg_type: i32 = data[4] as i32 | ((data[5] as i32) << 8) | ((data[6] as i32) << 16) | ((data[7] as i32) << 24); 35 | 36 | if msg_type == messages::MsgType::MSG_RMS_PACKET as i32 37 | { 38 | let rms_msg = messages::MsgRMSPacket::deserialized(data[8..].to_vec()); 39 | 40 | println!("RMS: {:?}", rms_msg.value); 41 | } 42 | else if msg_type == messages::MsgType::MSG_DEVICES_LIST as i32 43 | { 44 | let _ = messages::MsgDevicesList::deserialized(data[8..].to_vec()); 45 | } 46 | else if msg_type == messages::MsgType::MSG_ERROR as i32 47 | { 48 | let message = messages::MsgError::deserialized(data[8..].to_vec()).message; 49 | println!("Error terror: {:?}", message); 50 | } 51 | else { 52 | println!("Unknown message type."); 53 | } 54 | //Skip message length and type (WIP) 55 | //let _ = messages::MsgDevicesList::deserialized(data[8..].to_vec()); 56 | 57 | }, 58 | Err(e) => { 59 | println!("Error terror, {}", e); 60 | } 61 | } 62 | } 63 | } else { 64 | println!("Couldn't connect to server..."); 65 | } 66 | } -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate lazy_static; 3 | 4 | pub mod analysis; 5 | pub mod server; 6 | 7 | /*#[cfg(test)] 8 | mod tests { 9 | #[test] 10 | fn it_works() { 11 | } 12 | } 13 | */ -------------------------------------------------------------------------------- /src/server/main.rs: -------------------------------------------------------------------------------- 1 | use std::net::{TcpListener, TcpStream}; 2 | 3 | use std::io::prelude::*; 4 | use std::{thread, time}; 5 | 6 | use std::time::{Duration, Instant}; 7 | 8 | mod messages; 9 | 10 | use messages::Serializable; 11 | use messages::MsgType; 12 | 13 | extern crate raa; 14 | use raa::analysis; 15 | use raa::analysis::traits::Sourcable; 16 | 17 | use std::sync::Arc; 18 | use std::sync::RwLock; 19 | 20 | 21 | fn handle_client(stream: TcpStream) { 22 | // ... 23 | } 24 | 25 | fn send_devices(mut stream: &TcpStream) -> Result 26 | { 27 | let mut devices = analysis::soundio_source::SoundioSource::get_devices(); 28 | let mut device_msg = messages::MsgDevicesList::new(); 29 | device_msg.devices = devices.unwrap(); 30 | 31 | let mut serialized = device_msg.serialize(); 32 | stream.write(serialized.as_mut_slice()) 33 | } 34 | 35 | fn send_test_error(mut stream: &TcpStream) -> Result 36 | { 37 | let mut error_msg = messages::MsgError::new(); 38 | error_msg.message = "horror".to_string(); 39 | 40 | let mut serialized = error_msg.serialize(); 41 | stream.write(serialized.as_mut_slice()) 42 | } 43 | 44 | fn send_error(mut stream: &TcpStream, error: String) -> Result 45 | { 46 | let mut error_msg = messages::MsgError::new(); 47 | error_msg.message = error; 48 | 49 | let mut serialized = error_msg.serialize(); 50 | stream.write(serialized.as_mut_slice()) 51 | } 52 | 53 | fn send_rms_msg(mut stream: &TcpStream, rms: f32) -> Result 54 | { 55 | let mut rms_msg = messages::MsgRMSPacket::new(); 56 | rms_msg.value = rms; 57 | 58 | let mut serialized = rms_msg.serialize(); 59 | stream.write(serialized.as_mut_slice()) 60 | } 61 | 62 | fn main() { 63 | let listener = TcpListener::bind("127.0.0.1:50000").unwrap(); 64 | listener.set_nonblocking(true).expect("Cannot set non-blocking"); 65 | 66 | loop { 67 | match listener.accept() { 68 | Ok((mut stream, addr)) => { 69 | let _ = stream.set_nodelay(true); 70 | 71 | 72 | thread::spawn(move || { 73 | 74 | println!("new client: {:?}", addr); 75 | 76 | let _ = send_devices(&stream); 77 | //let _ = send_test_error(&stream); 78 | 79 | // Ready an analysis chain to be used later on after a proper message has been received. 80 | let arena = analysis::analysis::Arena::new(); 81 | let arena_rc = Arc::new(RwLock::new(arena)); 82 | let mut chain = analysis::analysis::Chain::new(arena_rc.clone()); 83 | let mut chain_ref = Arc::new(RwLock::new(chain)); 84 | 85 | let rms = Arc::new(RwLock::new(analysis::rms::RMS::new())); 86 | let rms_id = arena_rc.write().unwrap().add_chainable(rms); 87 | 88 | let mut source_id = None; 89 | 90 | let mut send_rms = false; 91 | 92 | // Cap to 20 outgoing messages per second 93 | let mut sent_msg_instant = Instant::now(); 94 | 95 | // Buffer for whole message. 96 | // Each message is prefixed by message length. 97 | // As TCP is a streaming protocol, message size may vary. 98 | // As such, only handle (and remove) a message when whole message is read. 99 | let mut msg_buffer: Vec = Vec::new(); 100 | 101 | // Read stuff until error. 102 | loop { 103 | let mut data = [0u8; 2048]; 104 | match stream.read(&mut data) 105 | { 106 | Ok(read_bytes) => { 107 | if read_bytes <= 0 108 | { 109 | continue; 110 | } 111 | 112 | for i in 0..read_bytes 113 | { 114 | msg_buffer.push(data[i]); 115 | } 116 | 117 | if msg_buffer.len() < 4 118 | { 119 | continue; 120 | } 121 | 122 | // Length that the message should have 123 | let mut msg_length: i32 = msg_buffer[0] as i32 | ((msg_buffer[1] as i32) << 8) | ((msg_buffer[2] as i32) << 16) | ((msg_buffer[3] as i32) << 24); 124 | 125 | println!("\nMessage length: {}", msg_length); 126 | println!("Buffer length: {}", msg_buffer.len()); 127 | 128 | // We have a full length message if buffer has msg_length bytes 129 | while msg_buffer.len() >= msg_length as usize 130 | { 131 | // Remove the message's worth of bytes from the buffer. 132 | println!("Buffer before: {}", msg_buffer.len()); 133 | let mut message_bytes: Vec = msg_buffer.drain(0..msg_length as usize).collect(); 134 | println!("Buffer after: {}", msg_buffer.len()); 135 | let msg_type = message_bytes[4] as i32 | ((message_bytes[5] as i32) << 8) | ((message_bytes[6] as i32) << 16) | ((message_bytes[7] as i32) << 24); 136 | println!("Message type: {}", msg_type); 137 | 138 | if msg_type == MsgType::MSG_GET_RMS as i32 139 | { 140 | println!("Stopping RMS chain.."); 141 | chain_ref.write().unwrap().stop(); 142 | 143 | println!("Stopped RMS chain!"); 144 | match source_id 145 | { 146 | Some(id) => { 147 | println!("Removing sourcable.."); 148 | match arena_rc.write() { 149 | Ok(mut rc) => (rc.remove_sourcable(id)), 150 | Err(e) => (println!("Could not write: {:?}", e)) 151 | } 152 | println!("Removed sourcable!"); 153 | } 154 | None => () 155 | }; 156 | 157 | // Ignore length & type when passing message_bytes 158 | println!("1"); 159 | let msg_length = message_bytes.len(); 160 | println!("2"); 161 | let messages_bytes_without_type = message_bytes.drain(8..msg_length).collect(); 162 | println!("Creating RMS msg.."); 163 | let rms_msg = messages::MsgStartStreamRMS::deserialized(messages_bytes_without_type); 164 | println!("Device: {}", rms_msg.device_id); 165 | println!("Channels: {:?}", rms_msg.channels); 166 | 167 | let source = Arc::new(RwLock::new(analysis::soundio_source::SoundioSource::new(rms_msg.device_id, rms_msg.channels))); 168 | source_id = Some(arena_rc.write().unwrap().add_sourcable(source)); 169 | 170 | chain = analysis::analysis::Chain::new(arena_rc.clone()); 171 | chain.set_source(source_id.unwrap()); 172 | chain.add_node(rms_id); 173 | println!("Created new RMS chain!"); 174 | 175 | chain_ref = Arc::new(RwLock::new(chain)); 176 | chain_ref.write().unwrap().start(chain_ref.clone()); 177 | println!("Started RMS chain!\n"); 178 | 179 | send_rms = true; 180 | } 181 | 182 | if msg_buffer.len() >= 4 183 | { 184 | msg_length = msg_buffer[0] as i32 | ((msg_buffer[1] as i32) << 8) | ((msg_buffer[2] as i32) << 16) | ((msg_buffer[3] as i32) << 24); 185 | } 186 | } 187 | }, 188 | Err(e) => { 189 | match e.kind() { 190 | std::io::ErrorKind::WouldBlock => {}, 191 | _ => { 192 | println!("Breaking."); 193 | arena_rc.write().unwrap().remove_sourcable(source_id.unwrap()); 194 | arena_rc.write().unwrap().remove_chainable(rms_id); 195 | break; 196 | }, 197 | } 198 | } 199 | } 200 | 201 | let elapsed_as_mills = sent_msg_instant.elapsed().as_secs() * 1000 202 | + sent_msg_instant.elapsed().subsec_nanos() as u64 / 1000000; 203 | let arena_borrow = arena_rc.read().unwrap(); 204 | match source_id 205 | { 206 | Some(id) => 207 | { 208 | let sourcable = arena_borrow.sourcables[&id].read().unwrap(); 209 | 210 | match sourcable.get_and_clear_error() 211 | { 212 | Some(error) => { 213 | let _ = send_error(&stream, error); 214 | } 215 | None => () 216 | } 217 | }, 218 | None => () 219 | } 220 | 221 | if send_rms == true && elapsed_as_mills > 1000/20 222 | { 223 | sent_msg_instant = Instant::now(); 224 | 225 | if arena_borrow.chainables[&rms_id].read().unwrap().output().len() > 0 226 | { 227 | let error = send_rms_msg(&stream, arena_borrow.chainables[&rms_id].read().unwrap().output()[0]); 228 | match error 229 | { 230 | Ok(_) => (), 231 | Err(e) => { 232 | println!("Connection lost: {:?}", e); 233 | arena_rc.write().unwrap().remove_sourcable(source_id.unwrap()); 234 | arena_rc.write().unwrap().remove_chainable(rms_id); 235 | } 236 | } 237 | } 238 | } 239 | 240 | let ten_millis = time::Duration::from_millis(10); 241 | thread::sleep(ten_millis); 242 | } 243 | println!("Stopped looping for data - client disconnected?"); 244 | chain_ref.write().unwrap().stop(); 245 | }); 246 | }, 247 | Err(e) => { 248 | //println!("Couldn't accept client connection, {:?}", e); 249 | }, 250 | } 251 | let ten_millis = time::Duration::from_millis(10); 252 | thread::sleep(ten_millis); 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /src/server/messages.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::mem::transmute; 3 | use std::str; 4 | 5 | #[derive(Clone)] 6 | pub enum MsgType { 7 | MSG_GET_RMS = 0, 8 | MSG_RMS_PACKET = 1, 9 | MSG_GET_DEVICES = 2, 10 | MSG_SET_FLOAT_PARAM = 3, 11 | MSG_DEVICES_LIST = 4, 12 | MSG_DB_PACKET = 5, 13 | MSG_SET_BOOLEAN_PARAM = 6, 14 | MSG_CONFIGUREDB = 7, 15 | MSG_ERROR = 8, 16 | } 17 | 18 | pub trait Serializable { 19 | fn serialize(&self) -> Vec; 20 | } 21 | 22 | 23 | pub struct MsgGetDevices { 24 | pub msg_type: MsgType, 25 | } 26 | 27 | impl MsgGetDevices { 28 | pub fn new() -> MsgGetDevices { 29 | MsgGetDevices { msg_type: MsgType::MSG_GET_DEVICES } 30 | } 31 | } 32 | 33 | pub struct MsgDevicesList { 34 | pub msg_type: MsgType, 35 | pub devices: HashMap, 36 | } 37 | 38 | impl MsgDevicesList { 39 | pub fn new() -> MsgDevicesList { 40 | MsgDevicesList { 41 | msg_type: MsgType::MSG_DEVICES_LIST, 42 | devices: HashMap::new(), 43 | } 44 | } 45 | 46 | pub fn deserialized(mut data: Vec) -> MsgDevicesList { 47 | let mut devices_list_msg = MsgDevicesList { 48 | msg_type: MsgType::MSG_DEVICES_LIST, 49 | devices: HashMap::new(), 50 | }; 51 | 52 | let device_amount: i32 = data[0] as i32 | ((data[1] as i32) << 8) | 53 | ((data[2] as i32) << 16) | 54 | ((data[3] as i32) << 24); 55 | 56 | println!("Device amount: {}", device_amount); 57 | 58 | data = data[4..].to_vec(); 59 | 60 | for _ in 0..device_amount { 61 | let device_id_length: u16 = data[0] as u16 | ((data[1] as u16) << 8); 62 | data = data[2..].to_vec(); 63 | println!("ID length: {}", device_id_length); 64 | 65 | let data_clone = data.clone(); 66 | let device_id = str::from_utf8(&data_clone[..device_id_length as usize]).unwrap(); 67 | println!("ID: {}", device_id); 68 | 69 | data = data[device_id_length as usize..].to_vec(); 70 | 71 | let device_name_length: u16 = data[0] as u16 | ((data[1] as u16) << 8); 72 | data = data[2..].to_vec(); 73 | println!("Name length: {}", device_name_length); 74 | 75 | let data_clone = data.clone(); 76 | let device_name = str::from_utf8(&data_clone[..device_name_length as usize]).unwrap(); 77 | println!("Name: {}", device_name); 78 | 79 | data = data[device_name_length as usize..].to_vec(); 80 | 81 | let device_channels = data[0] as i32 | ((data[1] as i32) << 8) | 82 | ((data[2] as i32) << 16) | 83 | ((data[3] as i32) << 24); 84 | data = data[4..].to_vec(); 85 | println!("Channels: {}", device_channels); 86 | } 87 | 88 | devices_list_msg 89 | } 90 | } 91 | 92 | impl Serializable for MsgDevicesList { 93 | fn serialize(&self) -> Vec { 94 | let mut bytes = Vec::new(); 95 | 96 | let type_bytes: [u8; 4] = unsafe { transmute((self.msg_type.clone() as i32).to_le()) }; 97 | 98 | let device_count_bytes: [u8; 4] = unsafe { transmute((self.devices.len() as i32).to_le()) }; 99 | 100 | let mut device_bytes = Vec::new(); 101 | 102 | for (id, name_and_channels) in &self.devices { 103 | let id_length: [u8; 2] = 104 | unsafe { transmute((id.as_bytes().len() as u16).to_le() as u16) }; 105 | device_bytes.extend(id_length.iter().cloned()); 106 | device_bytes.extend(id.as_bytes()); 107 | println!("Serializing device, ID: {}", 108 | id); 109 | println!("ID bytes: {:?}", id_length); 110 | 111 | let name_length: [u8; 2] = 112 | unsafe { transmute((name_and_channels.0.as_bytes().len() as u16).to_le() as u16) }; 113 | device_bytes.extend(name_length.iter().cloned()); 114 | device_bytes.extend(name_and_channels.0.as_bytes()); 115 | println!("Name: {} Length: {}", 116 | name_and_channels.0, 117 | name_and_channels.0.as_bytes().len()); 118 | println!("Name bytes: {:?}", name_length); 119 | 120 | let channel_bytes: [u8; 4] = unsafe { transmute(name_and_channels.1.to_le()) }; 121 | device_bytes.extend(channel_bytes.iter().cloned()); 122 | } 123 | 124 | let length_bytes: [u8; 4] = 125 | unsafe { transmute(((4 + 4 + 4 + device_bytes.len()) as i32).to_le()) }; 126 | bytes.extend(length_bytes.iter().cloned()); 127 | bytes.extend(type_bytes.iter().cloned()); 128 | bytes.extend(device_count_bytes.iter().cloned()); 129 | bytes.extend(device_bytes.iter().cloned()); 130 | bytes 131 | } 132 | } 133 | 134 | pub struct MsgStartStreamRMS { 135 | pub msg_type: MsgType, 136 | pub device_id: String, 137 | pub channels: Vec, 138 | } 139 | 140 | impl MsgStartStreamRMS { 141 | pub fn new() -> MsgStartStreamRMS { 142 | MsgStartStreamRMS { 143 | msg_type: MsgType::MSG_GET_RMS, 144 | device_id: "".to_string(), 145 | channels: Vec::new(), 146 | } 147 | } 148 | 149 | pub fn deserialized(mut data: Vec) -> MsgStartStreamRMS { 150 | let mut start_msg = MsgStartStreamRMS { 151 | msg_type: MsgType::MSG_GET_RMS, 152 | device_id: "".to_string(), 153 | channels: Vec::new(), 154 | }; 155 | 156 | // In old protocol, multiple devices could be given. 157 | // This isn't currently supported, but may be in the future? 158 | // We're assuming that there's only single device for now. 159 | 160 | // Read amount of devices 161 | let _ = data[0] as i32 | ((data[1] as i32) << 8) | ((data[2] as i32) << 16) | 162 | ((data[3] as i32) << 24); 163 | data = data[4..].to_vec(); 164 | 165 | // Read device ID 166 | let device_id_length: u16 = data[0] as u16 | ((data[1] as u16) << 8); 167 | data = data[2..].to_vec(); 168 | let data_clone = data.clone(); 169 | start_msg.device_id = str::from_utf8(&data_clone[..device_id_length as usize]).unwrap().to_string(); 170 | data = data[device_id_length as usize..].to_vec(); 171 | 172 | // Amount of channels - if there were multiple devices, we'd have multiple channel counts too. 173 | let channel_count = data[0] as i32 | ((data[1] as i32) << 8) | ((data[2] as i32) << 16) | 174 | ((data[3] as i32) << 24); 175 | data = data[4..].to_vec(); 176 | 177 | println!("Channel count: {}", channel_count); 178 | 179 | // Read channels 180 | for _ in 0..channel_count { 181 | let channel_id: i32 = data[0] as i32 | ((data[1] as i32) << 8) | 182 | ((data[2] as i32) << 16) | 183 | ((data[3] as i32) << 24); 184 | data = data[4..].to_vec(); 185 | 186 | start_msg.channels.push(channel_id); 187 | } 188 | 189 | start_msg 190 | } 191 | } 192 | 193 | impl Serializable for MsgStartStreamRMS { 194 | fn serialize(&self) -> Vec { 195 | let mut bytes = Vec::new(); 196 | 197 | let type_bytes: [u8; 4] = unsafe { transmute((self.msg_type.clone() as i32).to_le()) }; 198 | let id_length: [u8; 2] = 199 | unsafe { transmute((self.device_id.as_bytes().len() as u16).to_le() as u16) }; 200 | let mut device_bytes = Vec::new(); 201 | device_bytes.extend(id_length.iter().cloned()); 202 | device_bytes.extend(self.device_id.as_bytes()); 203 | 204 | // Device amount - make it possible to define multiple devices. For now, just 1 device supported. 205 | 206 | let mut channels_bytes = Vec::new(); 207 | for i in 0..self.channels.len() { 208 | let channel_bytes: [u8; 4] = unsafe { transmute(self.channels[i].to_le()) }; 209 | channels_bytes.extend(channel_bytes.iter().cloned()); 210 | } 211 | 212 | let length_bytes: [u8; 4] = 213 | unsafe { transmute((4 + 4 + 4 + device_bytes.len() as i32 + 4 + channels_bytes.len() as i32).to_le()) }; 214 | bytes.extend(length_bytes.iter().cloned()); 215 | bytes.extend(type_bytes.iter().cloned()); 216 | let device_count: [u8; 4] = unsafe { transmute((1 as i32).to_le()) }; 217 | bytes.extend(device_count.iter().cloned()); 218 | bytes.extend(device_bytes.iter().cloned()); 219 | let channel_count: [u8; 4] = unsafe { transmute((self.channels.len() as i32).to_le()) }; 220 | bytes.extend(channel_count.iter().cloned()); 221 | bytes.extend(channels_bytes.iter().cloned()); 222 | 223 | bytes 224 | } 225 | } 226 | 227 | pub struct MsgRMSPacket { 228 | pub msg_type: MsgType, 229 | pub value: f32 230 | } 231 | 232 | impl MsgRMSPacket { 233 | pub fn new() -> MsgRMSPacket { 234 | MsgRMSPacket { 235 | msg_type: MsgType::MSG_RMS_PACKET, 236 | value: 0f32, 237 | } 238 | } 239 | 240 | pub fn deserialized(mut data: Vec) -> MsgRMSPacket { 241 | let mut start_msg = MsgRMSPacket { 242 | msg_type: MsgType::MSG_RMS_PACKET, 243 | value: 0f32, 244 | }; 245 | 246 | let mut data_array = [0u8; 4]; 247 | data_array[0] = data[0]; 248 | data_array[1] = data[1]; 249 | data_array[2] = data[2]; 250 | data_array[3] = data[3]; 251 | start_msg.value = unsafe { transmute::<[u8; 4], f32>(data_array) }; 252 | 253 | start_msg 254 | } 255 | } 256 | 257 | impl Serializable for MsgRMSPacket { 258 | fn serialize(&self) -> Vec { 259 | let mut bytes = Vec::new(); 260 | 261 | let type_bytes: [u8; 4] = unsafe { transmute((self.msg_type.clone() as i32).to_le()) }; 262 | let value_bytes: [u8; 4] = unsafe { transmute(self.value as f32) }; 263 | let length_bytes: [u8; 4] = unsafe { transmute((4 + 4 + 4 as i32).to_le()) }; 264 | 265 | bytes.extend(length_bytes.iter().cloned()); 266 | bytes.extend(type_bytes.iter().cloned()); 267 | bytes.extend(value_bytes.iter().cloned()); 268 | 269 | bytes 270 | } 271 | } 272 | 273 | pub struct MsgError { 274 | pub msg_type: MsgType, 275 | pub message: String, 276 | } 277 | 278 | impl MsgError { 279 | pub fn new() -> MsgError { 280 | MsgError { 281 | msg_type: MsgType::MSG_ERROR, 282 | message: "".to_string(), 283 | } 284 | } 285 | 286 | pub fn deserialized(mut data: Vec) -> MsgError { 287 | let mut start_msg = MsgError { 288 | msg_type: MsgType::MSG_ERROR, 289 | message: "".to_string(), 290 | }; 291 | 292 | let message_length: u16 = data[0] as u16 | ((data[1] as u16) << 8); 293 | data = data[2..].to_vec(); 294 | 295 | let data_clone = data.clone(); 296 | let message = str::from_utf8(&data_clone[..message_length as usize]).unwrap(); 297 | 298 | start_msg.message = message.to_string(); 299 | 300 | start_msg 301 | } 302 | } 303 | 304 | impl Serializable for MsgError { 305 | fn serialize(&self) -> Vec { 306 | let mut bytes = Vec::new(); 307 | 308 | let type_bytes: [u8; 4] = unsafe { transmute((self.msg_type.clone() as i32).to_le()) }; 309 | let message_length: [u8; 2] = unsafe { transmute ((self.message.as_bytes().len() as u16).to_le() as u16) }; 310 | // Length: 4 from the length information (u32) itself, 2 from the length information of the error message, + error message length 311 | let length_bytes: [u8; 4] = unsafe { transmute((4 + 4 + 2 + self.message.as_bytes().len() as i32).to_le()) }; 312 | 313 | bytes.extend(length_bytes.iter().cloned()); 314 | bytes.extend(type_bytes.iter().cloned()); 315 | bytes.extend(message_length.iter().cloned()); 316 | bytes.extend(self.message.as_bytes()); 317 | 318 | bytes 319 | } 320 | } -------------------------------------------------------------------------------- /src/server/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod messages; -------------------------------------------------------------------------------- /src/test/main.rs: -------------------------------------------------------------------------------- 1 | extern crate raa; 2 | use raa::analysis; 3 | use std::cell::RefCell; 4 | use std::rc::Rc; 5 | 6 | use std::sync::Arc; 7 | use std::sync::RwLock; 8 | 9 | use std::{thread, time}; 10 | 11 | fn main() { 12 | let mut arena = analysis::pa_interface::AArena::new(); 13 | 14 | let source = Arc::new(RwLock::new(analysis::pa_interface::SoundioSource::new(0, vec![0]))); 15 | let source_id = arena.add_sourcable(source); 16 | 17 | let rms = Arc::new(RwLock::new(analysis::pa_interface::RMS::new())); 18 | let rms_id = arena.add_chainable(rms); 19 | 20 | let arena_rc = Arc::new(RwLock::new(arena)); 21 | 22 | let mut chain = analysis::pa_interface::AChain::new(arena_rc.clone()); 23 | chain.set_source(source_id); 24 | chain.add_node(rms_id); 25 | 26 | let chain_rc = Arc::new(RwLock::new(chain)); 27 | 28 | chain_rc.write().unwrap().start(chain_rc.clone()); 29 | 30 | let millis = time::Duration::from_millis(20); 31 | 32 | loop { 33 | let arena_borrow = arena_rc.read().unwrap(); 34 | if arena_borrow.chainables[&rms_id].read().unwrap().output().len() > 0 35 | { 36 | println!("RMS: {}", arena_borrow.chainables[&rms_id].read().unwrap().output()[0]); 37 | } 38 | thread::sleep(millis); 39 | } 40 | } --------------------------------------------------------------------------------