Skip to content

Commit

Permalink
Merge pull request #63 from dheijl/flac_support
Browse files Browse the repository at this point in the history
Flac support
  • Loading branch information
dheijl committed Jul 12, 2022
2 parents cac5af0 + c6c38bf commit 10d3a45
Show file tree
Hide file tree
Showing 10 changed files with 385 additions and 91 deletions.
43 changes: 31 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ bitflags = "1.3.2"
cpal = "0.13.5"
crossbeam-channel = "0.5.5"
dirs = "4.0.0"
fltk = { version = "1.3.10", features = ["use-ninja"] }
flac-bound = { version = "0.2.0", features = ["libflac-sys"] }
fltk = { version = "1.3.11", features = ["use-ninja"] }
#fltk-flow = "0.1.4"
htmlescape = "0.3.1"
if-addrs = "0.7.0"
Expand All @@ -36,7 +37,7 @@ strfmt = "0.1.6"
stringreader = "0.1.1"
tiny_http = "0.11.0"
toml = "0.5.9"
ureq = { version = "2.4.0", features = ["charset"] }
ureq = { version = "2.5.0", features = ["charset"] }
url = "2.2.2"
xml-rs = "0.8.4"
[target.'cfg(windows)'.dependencies]
Expand All @@ -49,3 +50,4 @@ libc = "0.2.126"
#fltk = { git = "https://github.com/fltk-rs/fltk-rs" }
#tiny_http = { git = "https://github.com/tiny-http/tiny-http" }
#cpal = { git = "https://github.com/RustAudio/cpal" }
flac-bound = { git = "https://github.com/dheijl/flac-bound" }
22 changes: 18 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,11 @@ use fltk::{
use lazy_static::lazy_static;
use log::{debug, error, info, warn, LevelFilter};
use parking_lot::RwLock;
use serde::{Deserialize, Serialize};
use simplelog::{ColorChoice, CombinedLogger, Config, TermLogger, WriteLogger};
use std::cell::Cell;
use std::collections::HashMap;
use std::fmt;
use std::fs::File;
use std::net::IpAddr;
use std::path::Path;
Expand All @@ -81,15 +83,26 @@ pub const APP_VERSION: &str = env!("CARGO_PKG_VERSION");
pub const SERVER_PORT: u16 = 5901;

/// streaming state
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum StreamingState {
Started,
Ended,
}

impl PartialEq for StreamingState {
fn eq(&self, other: &Self) -> bool {
self == other
#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
pub enum StreamingFormat {
Lpcm,
Wav,
Flac,
}

impl fmt::Display for StreamingFormat {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
StreamingFormat::Lpcm => write!(f, "LPCM"),
StreamingFormat::Wav => write!(f, "WAV"),
StreamingFormat::Flac => write!(f, "FLAC"),
}
}
}

Expand Down Expand Up @@ -320,6 +333,7 @@ fn main() {
&dummy_log,
config.use_wave_format,
config.bits_per_sample.unwrap(),
config.streaming_format.as_ref().unwrap(),
);
}
} else if button.is_set() {
Expand Down
34 changes: 17 additions & 17 deletions src/openhome/rendercontrol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
/// Only tested with Volumio streamers (https://volumio.org/)
///
///
use crate::CONFIG;
use crate::{StreamingFormat, CONFIG};
use log::{debug, error, info};
use std::collections::HashMap;
use std::net::{IpAddr, SocketAddr, UdpSocket};
Expand Down Expand Up @@ -46,7 +46,6 @@ static AV_SET_TRANSPORT_URI_TEMPLATE: &str = "\
static L16_PROT_INFO: &str = "http-get:*:audio/L16;rate={sample_rate};channels=2:DLNA.ORG_PN=LPCM";
static L24_PROT_INFO: &str = "http-get:*:audio/L24;rate={sample_rate};channels=2:DLNA.ORG_PN=LPCM";
static WAV_PROT_INFO: &str = "http-get:*:audio/wav:DLNA.ORG_PN=WAV;DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=03700000000000000000000000000000";
#[allow(dead_code)]
static FLAC_PROT_INFO: &str = "http-get:*:audio/flac:DLNA.ORG_PN=FLAC;DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01700000000000000000000000000000";

/// didl metadata template
Expand Down Expand Up @@ -230,6 +229,7 @@ impl Renderer {
log: &dyn Fn(String),
use_wav_format: bool,
bits_per_sample: u16,
format: &StreamingFormat,
) -> Result<(), &str> {
// build the hashmap with the formatting vars for the OH and AV play templates
let mut fmt_vars = HashMap::new();
Expand All @@ -241,21 +241,21 @@ impl Renderer {
fmt_vars.insert("sample_rate".to_string(), wd.sample_rate.0.to_string());
fmt_vars.insert("duration".to_string(), "00:00:00".to_string());
let mut didl_prot: String;
if use_wav_format {
if *format == StreamingFormat::Flac {
didl_prot = htmlescape::encode_minimal(FLAC_PROT_INFO);
} else if use_wav_format {
didl_prot = htmlescape::encode_minimal(WAV_PROT_INFO);
} else if bits_per_sample == 16 {
didl_prot = htmlescape::encode_minimal(L16_PROT_INFO);
} else {
if bits_per_sample == 16 {
didl_prot = htmlescape::encode_minimal(L16_PROT_INFO);
} else {
didl_prot = htmlescape::encode_minimal(L24_PROT_INFO);
}
match strfmt(&didl_prot, &fmt_vars) {
Ok(s) => didl_prot = s,
Err(e) => {
didl_prot = format!("oh_play: error {e} formatting didl_prot");
log(didl_prot.clone());
return Err(BAD_TEMPL);
}
didl_prot = htmlescape::encode_minimal(L24_PROT_INFO);
}
match strfmt(&didl_prot, &fmt_vars) {
Ok(s) => didl_prot = s,
Err(e) => {
didl_prot = format!("oh_play: error {e} formatting didl_prot");
log(didl_prot.clone());
return Err(BAD_TEMPL);
}
}
fmt_vars.insert("didl_prot_info".to_string(), didl_prot);
Expand Down Expand Up @@ -456,7 +456,7 @@ pub fn discover(
let local_addr = CONFIG.read().last_network.parse().unwrap();
let bind_addr = SocketAddr::new(local_addr, 0);
let socket = UdpSocket::bind(&bind_addr).unwrap();
let _ = socket.set_broadcast(true).unwrap();
socket.set_broadcast(true).unwrap();

// broadcast the M-SEARCH message (MX is 3 secs) and collect responses
let mut oh_devices: Vec<(String, SocketAddr)> = Vec::new();
Expand All @@ -477,7 +477,7 @@ pub fn discover(
break;
}
let max_wait_time = 3100 - duration;
let _ = socket
socket
.set_read_timeout(Some(Duration::from_millis(max_wait_time)))
.unwrap();
let mut buf: [u8; 2048] = [0; 2048];
Expand Down
40 changes: 29 additions & 11 deletions src/server/streaming_server.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::{ui_log, ChannelStream, StreamerFeedBack, StreamingState, WavData, CLIENTS, CONFIG};
use crate::{
ui_log, ChannelStream, StreamerFeedBack, StreamingFormat, StreamingState, WavData, CLIENTS,
CONFIG,
};
use crossbeam_channel::{unbounded, Receiver, Sender};
use fltk::app;
use log::debug;
Expand Down Expand Up @@ -88,12 +91,17 @@ pub fn run_server(
}
// prpare streaming headers
let conf = CONFIG.read().clone();
let ct_text = if conf.use_wave_format {
let format = conf.streaming_format.unwrap();
let ct_text = if format == StreamingFormat::Flac {
"audio/flac".to_string()
} else if conf.use_wave_format {
"audio/vnd.wave;codec=1".to_string()
} else if conf.bits_per_sample == Some(16) {
format!("audio/L16;rate={};channels=2", wd.sample_rate.0)
} else {
format!("audio/L24;rate={};channels=2", wd.sample_rate.0)
} else { // LPCM
if conf.bits_per_sample == Some(16) {
format!("audio/L16;rate={};channels=2", wd.sample_rate.0)
} else {
format!("audio/L24;rate={};channels=2", wd.sample_rate.0)
}
};
let ct_hdr = Header::from_bytes(&b"Content-Type"[..], ct_text.as_bytes()).unwrap();
let tm_hdr =
Expand Down Expand Up @@ -121,7 +129,11 @@ pub fn run_server(
conf.use_wave_format,
wd.sample_rate.0,
conf.bits_per_sample.unwrap(),
conf.streaming_format.unwrap(),
);
if channel_stream.streaming_format == StreamingFormat::Flac {
channel_stream.start_flac_encoder();
}
channel_stream.create_silence(wd.sample_rate.0);
let nclients = {
let mut clients = CLIENTS.write();
Expand All @@ -138,12 +150,16 @@ pub fn run_server(
})
.unwrap();
std::thread::yield_now();
let streaming_format = if conf.use_wave_format {
let streaming_format = if format == StreamingFormat::Flac {
"audio/FLAC"
} else if format == StreamingFormat::Wav {
"audio/wave;codec=1 (WAV)"
} else if conf.bits_per_sample == Some(16) {
"audio/L16 (LPCM)"
} else {
"audio/L24 (LPCM)"
} else { // LPCM
if conf.bits_per_sample == Some(16) {
"audio/L16 (LPCM)"
} else {
"audio/L24 (LPCM)"
}
};
ui_log(format!(
"Streaming {streaming_format}, input sample format {:?}, channels=2, rate={}, disable chunked={} to {}",
Expand All @@ -169,6 +185,8 @@ pub fn run_server(
}
let nclients = {
let mut clients = CLIENTS.write();
let chs = clients.get(&remote_addr).unwrap();
chs.stop_flac_encoder();
clients.remove(&remote_addr);
clients.len()
};
Expand Down
Loading

0 comments on commit 10d3a45

Please sign in to comment.