add first audio support
This commit is contained in:
13
src/args.rs
Normal file
13
src/args.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
use clap::Parser;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(author, version, about, long_about = None)]
|
||||
pub struct Cli {
|
||||
/// file for light sequences
|
||||
#[clap(short, long)]
|
||||
pub spectacle_file: String,
|
||||
|
||||
/// musique file that will be played
|
||||
#[clap(short, long)]
|
||||
pub musique_file: String,
|
||||
}
|
||||
18
src/audio.rs
Normal file
18
src/audio.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
use rodio::{Decoder, OutputStream, Sink};
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
use std::path::Path;
|
||||
|
||||
pub fn play_sound(path: &Path) {
|
||||
println!("starting musique");
|
||||
let (_stream, stream_handle) = OutputStream::try_default().unwrap();
|
||||
let sink = Sink::try_new(&stream_handle).unwrap();
|
||||
|
||||
let file = BufReader::new(File::open(path).unwrap());
|
||||
let source = Some(Decoder::new(file).unwrap()).unwrap();
|
||||
sink.append(source);
|
||||
|
||||
// The sound plays in a separate thread. This call will block the current thread until the sink
|
||||
// has finished playing all its queued sounds.
|
||||
sink.sleep_until_end();
|
||||
}
|
||||
@@ -1,23 +1,19 @@
|
||||
use std::collections::HashSet;
|
||||
use std::fs;
|
||||
use crate::runner::DeviceSequence;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::HashSet;
|
||||
use std::fs;
|
||||
|
||||
|
||||
pub(crate) type Config<const N:usize> = Vec<Device<N>>;
|
||||
pub(crate) type Config<const N: usize> = Vec<Device<N>>;
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct Device<const N: usize> {
|
||||
pub mac_addresses : Option<HashSet<String>>,
|
||||
name : Option<String>,
|
||||
pub sequence : DeviceSequence<N>,
|
||||
pub mac_addresses: Option<HashSet<String>>,
|
||||
name: Option<String>,
|
||||
pub sequence: DeviceSequence<N>,
|
||||
}
|
||||
|
||||
|
||||
pub fn load_from_file<const N: usize>(file: &std::path::Path) -> Config<N> {
|
||||
|
||||
|
||||
let file = fs::read_to_string(file).unwrap();
|
||||
let config: Config<N> = serde_yaml::from_str(&*file).unwrap();
|
||||
config
|
||||
}
|
||||
pub fn load_from_file<const N: usize>(file: &std::path::Path) -> Config<N> {
|
||||
let file = fs::read_to_string(file).unwrap();
|
||||
let config: Config<N> = serde_yaml::from_str(&*file).unwrap();
|
||||
config
|
||||
}
|
||||
|
||||
31
src/main.rs
31
src/main.rs
@@ -1,19 +1,22 @@
|
||||
mod args;
|
||||
mod audio;
|
||||
mod bluetooth;
|
||||
mod config;
|
||||
mod patterns;
|
||||
mod runner;
|
||||
mod spectacle;
|
||||
mod config;
|
||||
|
||||
use std::borrow::BorrowMut;
|
||||
use crate::args::Cli;
|
||||
use crate::audio::play_sound;
|
||||
use crate::config::{load_from_file, Config};
|
||||
use crate::runner::Spectacle;
|
||||
use bluer::gatt::remote::Characteristic;
|
||||
use clap::Parser;
|
||||
use patterns::Strip;
|
||||
use std::path::Path;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
use tokio::sync::mpsc;
|
||||
use tokio::sync::watch::Receiver;
|
||||
use crate::config::{Config, load_from_file};
|
||||
|
||||
const SERVICE_UUID: bluer::Uuid = bluer::Uuid::from_u128(0xadaf0900c33242a893bd25e905756cb8);
|
||||
const PIXEL_DATA_UUID: bluer::Uuid = bluer::Uuid::from_u128(0xadaf0903c33242a893bd25e905756cb8);
|
||||
@@ -22,13 +25,17 @@ const BASE_STRIP_DATA: [u8; 3] = [0x00, 0x00, 0x01];
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn main() -> bluer::Result<()> {
|
||||
let file = Path::new("spectacle.yml");
|
||||
let command_line = Cli::parse();
|
||||
|
||||
let file = Path::new(&command_line.spectacle_file);
|
||||
let config: Config<25> = load_from_file(file);
|
||||
let mut spectacle = Spectacle::from(config);
|
||||
let mut spectacle = Arc::new(Mutex::new(spectacle));
|
||||
let spectacle = Spectacle::from(config);
|
||||
let spectacle = Arc::new(Mutex::new(spectacle));
|
||||
|
||||
let musique_file = command_line.musique_file;
|
||||
let musique = tokio::task::spawn_blocking(move || play_sound(Path::new(&musique_file)));
|
||||
|
||||
let adapter = bluetooth::create_session().await?;
|
||||
|
||||
let (tx_scan, mut rx_scan) = mpsc::channel(3);
|
||||
|
||||
tokio::spawn(bluetooth::bluetooth_scan(
|
||||
@@ -43,7 +50,7 @@ async fn main() -> bluer::Result<()> {
|
||||
bluetooth::connect(&device, 3).await?;
|
||||
let char = bluetooth::get_char(&device, SERVICE_UUID, PIXEL_DATA_UUID).await?;
|
||||
if let Some(char) = char {
|
||||
let rx : Option<Receiver<Strip<STRIP_SIZE>>>;
|
||||
let rx: Option<Receiver<Strip<STRIP_SIZE>>>;
|
||||
{
|
||||
let spectacle_channels = spectacle_channels.lock().unwrap();
|
||||
rx = spectacle_channels.get_channel(&device.address());
|
||||
@@ -67,7 +74,6 @@ async fn main() -> bluer::Result<()> {
|
||||
});
|
||||
|
||||
println!("starting");
|
||||
// runner_loop(config, &tx).await;
|
||||
let futures;
|
||||
{
|
||||
let mut spectacle = spectacle.lock().unwrap();
|
||||
@@ -78,10 +84,9 @@ async fn main() -> bluer::Result<()> {
|
||||
joinhandles.push(tokio::spawn(future));
|
||||
}
|
||||
for joinhandle in joinhandles {
|
||||
joinhandle.await;
|
||||
joinhandle.await.unwrap();
|
||||
}
|
||||
tokio::time::sleep(Duration::from_secs(5)).await;
|
||||
println!("error sending value");
|
||||
musique.await.unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
use crate::config::Config;
|
||||
use crate::patterns::Patterns;
|
||||
use crate::Strip;
|
||||
use bluer::Address;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::future::Future;
|
||||
use std::str::FromStr;
|
||||
use crate::patterns::Patterns;
|
||||
use crate::Strip;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use bluer::Address;
|
||||
use tokio::sync::watch::{Receiver, Sender};
|
||||
use tokio::task::JoinHandle;
|
||||
use crate::config::Config;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
|
||||
pub struct Context<const N: usize> {
|
||||
@@ -18,7 +17,6 @@ pub struct Context<const N: usize> {
|
||||
|
||||
pub(crate) type DeviceSequence<const N: usize> = Vec<Context<N>>;
|
||||
|
||||
|
||||
pub async fn runner_loop<const N: usize>(runner: DeviceSequence<N>, tx: Sender<Strip<N>>) {
|
||||
for mut context in runner {
|
||||
let mut strip = context.pattern.next().unwrap();
|
||||
@@ -43,7 +41,6 @@ pub struct Spectacle<const N: usize> {
|
||||
default_receiver: Option<Receiver<Strip<N>>>,
|
||||
}
|
||||
|
||||
|
||||
impl<const N: usize> Spectacle<N> {
|
||||
pub fn add(&mut self, mac_address: Address, runner: &DeviceSequence<N>) {
|
||||
if let Some((_, rx)) = self.runners.get(&runner as &DeviceSequence<N>) {
|
||||
@@ -55,7 +52,6 @@ impl<const N: usize> Spectacle<N> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn add_default(&mut self, runner: DeviceSequence<N>) {
|
||||
let (tx, rx) = tokio::sync::watch::channel(Strip::<N>::default());
|
||||
// self.tasks.push(runner.runner_loop(tx));
|
||||
@@ -67,20 +63,23 @@ impl<const N: usize> Spectacle<N> {
|
||||
let channel = self.channels.get(mac_address);
|
||||
match channel {
|
||||
None => {
|
||||
let d = &self.default_receiver;
|
||||
let d = &self.default_receiver;
|
||||
match d {
|
||||
None => { None}
|
||||
Some(runner) => {
|
||||
println!("default rx");
|
||||
Some(runner.clone())}
|
||||
} }
|
||||
None => None,
|
||||
Some(runner) => {
|
||||
println!("default rx");
|
||||
Some(runner.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(channel) => {
|
||||
println!("rx found ");
|
||||
Some(channel.clone()) }
|
||||
Some(channel.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(&mut self) -> Vec<impl Future<Output=()>> {
|
||||
pub fn run(&mut self) -> Vec<impl Future<Output = ()>> {
|
||||
let mut joinhandles = vec![];
|
||||
|
||||
if let Some(_) = &self.default_runner {
|
||||
@@ -105,10 +104,13 @@ impl<const N: usize> From<Config<N>> for Spectacle<N> {
|
||||
for mac_address in mac_addresses {
|
||||
let mac_address = Address::from_str(&*mac_address);
|
||||
match mac_address {
|
||||
Ok(address) => { spectacle.add(address, &device.sequence);}
|
||||
Err(_) => { println!("error reading mac address");}
|
||||
Ok(address) => {
|
||||
spectacle.add(address, &device.sequence);
|
||||
}
|
||||
Err(_) => {
|
||||
println!("error reading mac address");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
spectacle.add_default(device.sequence);
|
||||
|
||||
Reference in New Issue
Block a user