0.1.7: switch logs err/out, bump symphonia, buffer wisely

Signed-off-by: Ivan Bushchik <ivabus@ivabus.dev>
This commit is contained in:
Ivan Bushchik 2024-02-28 17:50:24 +03:00
parent 31c0db5d99
commit 6daba088b8
No known key found for this signature in database
GPG key ID: 2F16FBF3262E090C
4 changed files with 211 additions and 90 deletions

151
Cargo.lock generated
View file

@ -387,6 +387,12 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "extended"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af9673d8203fcb076b19dfd17e38b3d4ae9f44959416ea532ce72415a6020365"
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.12" version = "0.2.12"
@ -568,7 +574,7 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]] [[package]]
name = "lonelyradio" name = "lonelyradio"
version = "0.1.6" version = "0.1.7"
dependencies = [ dependencies = [
"chrono", "chrono",
"clap", "clap",
@ -679,6 +685,15 @@ dependencies = [
"minimal-lexical", "minimal-lexical",
] ]
[[package]]
name = "num-complex"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214"
dependencies = [
"num-traits",
]
[[package]] [[package]]
name = "num-derive" name = "num-derive"
version = "0.3.3" version = "0.3.3"
@ -690,6 +705,15 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "num-integer"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
dependencies = [
"num-traits",
]
[[package]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.2.17" version = "0.2.17"
@ -815,6 +839,15 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "primal-check"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9df7f93fd637f083201473dab4fee2db4c429d32e55e3299980ab3957ab916a0"
dependencies = [
"num-integer",
]
[[package]] [[package]]
name = "proc-macro-crate" name = "proc-macro-crate"
version = "1.3.1" version = "1.3.1"
@ -938,6 +971,21 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustfft"
version = "6.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43806561bc506d0c5d160643ad742e3161049ac01027b5e6d7524091fd401d86"
dependencies = [
"num-complex",
"num-integer",
"num-traits",
"primal-check",
"strength_reduce",
"transpose",
"version_check",
]
[[package]] [[package]]
name = "same-file" name = "same-file"
version = "1.0.6" version = "1.0.6"
@ -984,6 +1032,12 @@ dependencies = [
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
[[package]]
name = "strength_reduce"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.10.0" version = "0.10.0"
@ -992,9 +1046,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "symphonia" name = "symphonia"
version = "0.5.3" version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62e48dba70095f265fdb269b99619b95d04c89e619538138383e63310b14d941" checksum = "815c942ae7ee74737bb00f965fa5b5a2ac2ce7b6c01c0cc169bbeaf7abd5f5a9"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"symphonia-bundle-flac", "symphonia-bundle-flac",
@ -1005,18 +1059,19 @@ dependencies = [
"symphonia-codec-pcm", "symphonia-codec-pcm",
"symphonia-codec-vorbis", "symphonia-codec-vorbis",
"symphonia-core", "symphonia-core",
"symphonia-format-caf",
"symphonia-format-isomp4", "symphonia-format-isomp4",
"symphonia-format-mkv", "symphonia-format-mkv",
"symphonia-format-ogg", "symphonia-format-ogg",
"symphonia-format-wav", "symphonia-format-riff",
"symphonia-metadata", "symphonia-metadata",
] ]
[[package]] [[package]]
name = "symphonia-bundle-flac" name = "symphonia-bundle-flac"
version = "0.5.3" version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f23b0482a7cb18fcdf9981ab0b78df800ef0080187d294650023c462439058d" checksum = "72e34f34298a7308d4397a6c7fbf5b84c5d491231ce3dd379707ba673ab3bd97"
dependencies = [ dependencies = [
"log", "log",
"symphonia-core", "symphonia-core",
@ -1026,11 +1081,10 @@ dependencies = [
[[package]] [[package]]
name = "symphonia-bundle-mp3" name = "symphonia-bundle-mp3"
version = "0.5.3" version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f31d7fece546f1e6973011a9eceae948133bbd18fd3d52f6073b1e38ae6368a" checksum = "c01c2aae70f0f1fb096b6f0ff112a930b1fb3626178fba3ae68b09dce71706d4"
dependencies = [ dependencies = [
"bitflags 1.3.2",
"lazy_static", "lazy_static",
"log", "log",
"symphonia-core", "symphonia-core",
@ -1039,9 +1093,9 @@ dependencies = [
[[package]] [[package]]
name = "symphonia-codec-aac" name = "symphonia-codec-aac"
version = "0.5.3" version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68bdd75b25ce4b84b12a4bd20bfea2460c2dbd7fc1d227ef5533504d3168109d" checksum = "cdbf25b545ad0d3ee3e891ea643ad115aff4ca92f6aec472086b957a58522f70"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"log", "log",
@ -1050,9 +1104,9 @@ dependencies = [
[[package]] [[package]]
name = "symphonia-codec-adpcm" name = "symphonia-codec-adpcm"
version = "0.5.3" version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "870e7dc1865d818c7b6318879d060553a73a3b2a3b8443dff90910f10ac41150" checksum = "c94e1feac3327cd616e973d5be69ad36b3945f16b06f19c6773fc3ac0b426a0f"
dependencies = [ dependencies = [
"log", "log",
"symphonia-core", "symphonia-core",
@ -1060,9 +1114,9 @@ dependencies = [
[[package]] [[package]]
name = "symphonia-codec-alac" name = "symphonia-codec-alac"
version = "0.5.3" version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a27e8763d1c9eff666faf903e73a99d4de2f7a93fca4e3c214c1d68432903b9" checksum = "2d8a6666649a08412906476a8b0efd9b9733e241180189e9f92b09c08d0e38f3"
dependencies = [ dependencies = [
"log", "log",
"symphonia-core", "symphonia-core",
@ -1070,9 +1124,9 @@ dependencies = [
[[package]] [[package]]
name = "symphonia-codec-pcm" name = "symphonia-codec-pcm"
version = "0.5.3" version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47f1fbd220a06a641c8ce2ddad10f5ef6ee5cc0c54d9044d25d43b0d3119deaa" checksum = "f395a67057c2ebc5e84d7bb1be71cce1a7ba99f64e0f0f0e303a03f79116f89b"
dependencies = [ dependencies = [
"log", "log",
"symphonia-core", "symphonia-core",
@ -1080,9 +1134,9 @@ dependencies = [
[[package]] [[package]]
name = "symphonia-codec-vorbis" name = "symphonia-codec-vorbis"
version = "0.5.3" version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3953397e3506aa01350c4205817e4f95b58d476877a42f0458d07b665749e203" checksum = "5a98765fb46a0a6732b007f7e2870c2129b6f78d87db7987e6533c8f164a9f30"
dependencies = [ dependencies = [
"log", "log",
"symphonia-core", "symphonia-core",
@ -1091,22 +1145,34 @@ dependencies = [
[[package]] [[package]]
name = "symphonia-core" name = "symphonia-core"
version = "0.5.3" version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7c73eb88fee79705268cc7b742c7bc93a7b76e092ab751d0833866970754142" checksum = "798306779e3dc7d5231bd5691f5a813496dc79d3f56bf82e25789f2094e022c3"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"bitflags 1.3.2", "bitflags 1.3.2",
"bytemuck", "bytemuck",
"lazy_static", "lazy_static",
"log", "log",
"rustfft",
]
[[package]]
name = "symphonia-format-caf"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e43c99c696a388295a29fe71b133079f5d8b18041cf734c5459c35ad9097af50"
dependencies = [
"log",
"symphonia-core",
"symphonia-metadata",
] ]
[[package]] [[package]]
name = "symphonia-format-isomp4" name = "symphonia-format-isomp4"
version = "0.5.3" version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffdf14bae5cf352032416bc64151e5d6242d29d33cbf3238513b44d4427a1efb" checksum = "abfdf178d697e50ce1e5d9b982ba1b94c47218e03ec35022d9f0e071a16dc844"
dependencies = [ dependencies = [
"encoding_rs", "encoding_rs",
"log", "log",
@ -1117,9 +1183,9 @@ dependencies = [
[[package]] [[package]]
name = "symphonia-format-mkv" name = "symphonia-format-mkv"
version = "0.5.3" version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5c61dfc851ad25d4043d8c231d8617e8f7cd02a6cc0edad21ade21848d58895" checksum = "1bb43471a100f7882dc9937395bd5ebee8329298e766250b15b3875652fe3d6f"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"log", "log",
@ -1130,9 +1196,9 @@ dependencies = [
[[package]] [[package]]
name = "symphonia-format-ogg" name = "symphonia-format-ogg"
version = "0.5.3" version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bf1a00ccd11452d44048a0368828040f778ae650418dbd9d8765b7ee2574c8d" checksum = "ada3505789516bcf00fc1157c67729eded428b455c27ca370e41f4d785bfa931"
dependencies = [ dependencies = [
"log", "log",
"symphonia-core", "symphonia-core",
@ -1141,11 +1207,12 @@ dependencies = [
] ]
[[package]] [[package]]
name = "symphonia-format-wav" name = "symphonia-format-riff"
version = "0.5.3" version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da76614728fa27c003bdcdfbac51396bd8fcbf94c95fe8e62f1d2bac58ef03a4" checksum = "05f7be232f962f937f4b7115cbe62c330929345434c834359425e043bfd15f50"
dependencies = [ dependencies = [
"extended",
"log", "log",
"symphonia-core", "symphonia-core",
"symphonia-metadata", "symphonia-metadata",
@ -1153,9 +1220,9 @@ dependencies = [
[[package]] [[package]]
name = "symphonia-metadata" name = "symphonia-metadata"
version = "0.5.3" version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89c3e1937e31d0e068bbe829f66b2f2bfaa28d056365279e0ef897172c3320c0" checksum = "bc622b9841a10089c5b18e99eb904f4341615d5aa55bbf4eedde1be721a4023c"
dependencies = [ dependencies = [
"encoding_rs", "encoding_rs",
"lazy_static", "lazy_static",
@ -1165,9 +1232,9 @@ dependencies = [
[[package]] [[package]]
name = "symphonia-utils-xiph" name = "symphonia-utils-xiph"
version = "0.5.3" version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a450ca645b80d69aff8b35576cbfdc7f20940b29998202aab910045714c951f8" checksum = "484472580fa49991afda5f6550ece662237b00c6f562c7d9638d1b086ed010fe"
dependencies = [ dependencies = [
"symphonia-core", "symphonia-core",
"symphonia-metadata", "symphonia-metadata",
@ -1260,6 +1327,16 @@ dependencies = [
"winnow", "winnow",
] ]
[[package]]
name = "transpose"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6522d49d03727ffb138ae4cbc1283d3774f0d10aa7f9bf52e6784c45daf9b23"
dependencies = [
"num-integer",
"strength_reduce",
]
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.12" version = "1.0.12"
@ -1272,6 +1349,12 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]] [[package]]
name = "walkdir" name = "walkdir"
version = "2.4.0" version = "2.4.0"

View file

@ -4,7 +4,7 @@ members = ["monoclient"]
[package] [package]
name = "lonelyradio" name = "lonelyradio"
description = "TCP radio for singles" description = "TCP radio for singles"
version = "0.1.6" version = "0.1.7"
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"
authors = ["Ivan Bushchik <ivabus@ivabus.dev>"] authors = ["Ivan Bushchik <ivabus@ivabus.dev>"]
@ -22,11 +22,10 @@ tokio = { version = "1.35.1", features = [
"macros", "macros",
] } ] }
walkdir = "2.4.0" walkdir = "2.4.0"
symphonia = { version = "0.5.3", features = [ symphonia = { version = "0.5.4", features = [
"all-codecs", "all-codecs",
"all-formats", "all-formats",
"pcm", "opt-simd",
"symphonia-codec-pcm",
] } ] }
samplerate = "0.2.4" samplerate = "0.2.4"
chrono = "0.4" chrono = "0.4"

View file

@ -4,9 +4,12 @@ use rodio::buffer::SamplesBuffer;
use rodio::{OutputStream, Sink}; use rodio::{OutputStream, Sink};
use std::io::Read; use std::io::Read;
use std::net::TcpStream; use std::net::TcpStream;
use std::time::Instant;
// How many samples to cache before playing (half a second) // How many samples to cache before playing in samples (both channels) SHOULD BE EVEN
const BUFFER_SIZE: usize = 44100; const BUFFER_SIZE: usize = 2400;
// How many buffers to cache
const CACHE_SIZE: usize = 100;
enum Channel { enum Channel {
Right, Right,
@ -18,16 +21,29 @@ enum Channel {
struct Args { struct Args {
/// Remote address /// Remote address
address: String, address: String,
#[arg(short, long, default_value = "s")]
/// L, R or S for Left, Right or Stereo /// L, R or S for Left, Right or Stereo
channel: String, channel: String,
#[arg(short)] #[arg(short)]
/// Play only on specified channel, with it if channel = Right => L=0 and R=R, without L=R and R=R. No effect on Stereo /// Play only on specified channel, with it if channel = Right => L=0 and R=R, without L=R and R=R. No effect on Stereo
single: bool, single: bool,
/// More verbose
#[arg(short)]
verbose: bool,
} }
fn main() { fn main() {
let start = Instant::now();
let args = Args::parse(); let args = Args::parse();
let mut stream = TcpStream::connect(args.address).unwrap(); let mut stream = TcpStream::connect(args.address).unwrap();
if args.verbose {
eprintln!(
"Connected to {} from {}",
stream.peer_addr().unwrap(),
stream.local_addr().unwrap()
)
}
let channel = match args.channel.to_ascii_lowercase().as_str() { let channel = match args.channel.to_ascii_lowercase().as_str() {
"l" => Channel::Left, "l" => Channel::Left,
@ -38,12 +54,14 @@ fn main() {
let (_stream, stream_handle) = OutputStream::try_default().unwrap(); let (_stream, stream_handle) = OutputStream::try_default().unwrap();
let sink = Sink::try_new(&stream_handle).unwrap(); let sink = Sink::try_new(&stream_handle).unwrap();
let mut buffer = [0u8; 4]; let mut buffer = [0u8; 4];
let mut samples = vec![]; let mut samples = [0f32; BUFFER_SIZE];
let mut index = 0usize;
let mut first = true;
while stream.read_exact(&mut buffer).is_ok() { while stream.read_exact(&mut buffer).is_ok() {
let sample_l = byteorder::LittleEndian::read_i16(&buffer[..2]) as f32 / 32768.0; let sample_l = byteorder::LittleEndian::read_i16(&buffer[..2]) as f32 / 32768.0;
let sample_r = byteorder::LittleEndian::read_i16(&buffer[2..]) as f32 / 32768.0; let sample_r = byteorder::LittleEndian::read_i16(&buffer[2..]) as f32 / 32768.0;
// Left channel // Left channel
samples.push(match channel { samples[index] = match channel {
Channel::Left | Channel::Stereo => sample_l, Channel::Left | Channel::Stereo => sample_l,
Channel::Right => { Channel::Right => {
if args.single { if args.single {
@ -52,9 +70,10 @@ fn main() {
sample_r sample_r
} }
} }
}); };
index += 1;
// Right channel // Right channel
samples.push(match channel { samples[index] = match channel {
Channel::Right | Channel::Stereo => sample_r, Channel::Right | Channel::Stereo => sample_r,
Channel::Left => { Channel::Left => {
if args.single { if args.single {
@ -63,20 +82,35 @@ fn main() {
sample_l sample_l
} }
} }
}); };
if samples.len() >= BUFFER_SIZE { index += 1;
// What is next three lines? if index == BUFFER_SIZE {
// Sink's thread is detached from main thread, so we need to somehow synchronize with it let mut first_wait_iteration = true;
// Sink's thread is detached from main thread, so we need to synchronize with it
// Why we should synchronize with it? // Why we should synchronize with it?
// Let's say, that if we don't synchronize with it, we would have // Let's say, that if we don't synchronize with it, we would have
// a lot (no upper limit, actualy) of buffered sound, waiting for playing in sink // a lot (no upper limit, actualy) of buffered sound, waiting for playing in sink
while sink.len() >= 3 while sink.len() >= CACHE_SIZE {
// buffered >= 1.5 sec if args.verbose && first_wait_iteration {
{ eprint!(".");
std::thread::sleep(std::time::Duration::from_secs_f32(0.25)) first_wait_iteration = false;
} }
sink.append(SamplesBuffer::new(2, 44100, samples)); // Sleeping exactly one buffer
samples = vec![]; std::thread::sleep(std::time::Duration::from_secs_f32(
(if sink.len() >= 2 {
sink.len() - 2
} else {
1
} as f32) * BUFFER_SIZE as f32
/ 44100.0 / 2.0,
))
}
if first && args.verbose {
eprintln!("Started playing in {} ms", (Instant::now() - start).as_millis());
first = false;
}
sink.append(SamplesBuffer::new(2, 44100, samples.as_slice()));
index = 0;
} }
} }
} }

View file

@ -1,4 +1,5 @@
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc;
use chrono::Local; use chrono::Local;
use clap::Parser; use clap::Parser;
@ -6,9 +7,7 @@ use rand::prelude::*;
use samplerate::ConverterType; use samplerate::ConverterType;
use symphonia::core::audio::SampleBuffer; use symphonia::core::audio::SampleBuffer;
use symphonia::core::codecs::CODEC_TYPE_NULL; use symphonia::core::codecs::CODEC_TYPE_NULL;
use symphonia::core::formats::FormatOptions;
use symphonia::core::io::MediaSourceStream; use symphonia::core::io::MediaSourceStream;
use symphonia::core::meta::MetadataOptions;
use symphonia::core::probe::Hint; use symphonia::core::probe::Hint;
use tokio::io::AsyncWriteExt; use tokio::io::AsyncWriteExt;
use tokio::net::{TcpListener, TcpStream}; use tokio::net::{TcpListener, TcpStream};
@ -30,42 +29,43 @@ struct Args {
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
let listener = TcpListener::bind(Args::parse().address).await.unwrap(); let listener = TcpListener::bind(Args::parse().address).await.unwrap();
let tracklist = Arc::new(
walkdir::WalkDir::new(Args::parse().dir)
.into_iter()
.filter_entry(is_not_hidden)
.filter_map(|v| v.ok())
.map(|x| x.into_path())
.filter(track_valid)
.into_iter()
.collect::<Vec<PathBuf>>(),
);
loop { loop {
let (socket, _) = listener.accept().await.unwrap(); let (socket, _) = listener.accept().await.unwrap();
tokio::spawn(stream(socket)); tokio::spawn(stream(socket, tracklist.clone()));
} }
} }
fn is_not_hidden(entry: &DirEntry) -> bool { fn is_not_hidden(entry: &DirEntry) -> bool {
entry.file_name().to_str().map(|s| entry.depth() == 0 || !s.starts_with('.')).unwrap_or(false) entry.file_name().to_str().map(|s| entry.depth() == 0 || !s.starts_with('.')).unwrap_or(false)
} }
// Recursively finding music file fn track_valid(track: &PathBuf) -> bool {
fn pick_track(tracklist: &Vec<PathBuf>) -> &PathBuf { if !track.metadata().unwrap().is_file() {
let mut track = tracklist.choose(&mut thread_rng()).unwrap(); return false;
while !track.metadata().unwrap().is_file() {
track = pick_track(tracklist)
} }
// Skipping "images" (covers) // Skipping "images" (covers)
while "jpgjpegpngwebp" if "jpgjpegpngwebp".contains(&track.extension().unwrap().to_str().unwrap().to_ascii_lowercase())
.contains(&track.extension().unwrap().to_str().unwrap().to_ascii_lowercase())
{ {
track = pick_track(tracklist) return false;
} }
track true
} }
async fn stream(mut s: TcpStream) { async fn stream(mut s: TcpStream, tracklist: Arc<Vec<PathBuf>>) {
let args = Args::parse(); let args = Args::parse();
let tracklist = walkdir::WalkDir::new(Args::parse().dir)
.into_iter()
.filter_entry(is_not_hidden)
.filter_map(|v| v.ok())
.map(|x| x.into_path())
.collect::<Vec<PathBuf>>();
'track: loop { 'track: loop {
let track = pick_track(&tracklist); let track = tracklist.choose(&mut thread_rng()).unwrap();
println!( eprintln!(
"[{}] {} to {}:{}{}", "[{}] {} to {}:{}{}",
Local::now().to_rfc3339(), Local::now().to_rfc3339(),
track.to_str().unwrap(), track.to_str().unwrap(),
@ -79,7 +79,7 @@ async fn stream(mut s: TcpStream) {
); );
if args.public_log { if args.public_log {
eprintln!( println!(
"[{}] {} to {}{}", "[{}] {} to {}{}",
Local::now().to_rfc3339(), Local::now().to_rfc3339(),
track.to_str().unwrap(), track.to_str().unwrap(),
@ -95,13 +95,14 @@ async fn stream(mut s: TcpStream) {
let file = Box::new(std::fs::File::open(track).unwrap()); let file = Box::new(std::fs::File::open(track).unwrap());
let mut hint = Hint::new(); let mut hint = Hint::new();
hint.with_extension(track.extension().unwrap().to_str().unwrap()); hint.with_extension(track.extension().unwrap().to_str().unwrap());
let mss = MediaSourceStream::new(file, Default::default());
let meta_opts: MetadataOptions = Default::default();
let fmt_opts: FormatOptions = Default::default();
let probed = symphonia::default::get_probe() let probed = symphonia::default::get_probe()
.format(&hint, mss, &fmt_opts, &meta_opts) .format(
&hint,
MediaSourceStream::new(file, Default::default()),
&Default::default(),
&Default::default(),
)
.expect("unsupported format"); .expect("unsupported format");
let mut format = probed.format; let mut format = probed.format;
@ -138,14 +139,18 @@ async fn stream(mut s: TcpStream) {
let mut byte_buf = let mut byte_buf =
SampleBuffer::<f32>::new(decoded.capacity() as u64, *decoded.spec()); SampleBuffer::<f32>::new(decoded.capacity() as u64, *decoded.spec());
byte_buf.copy_interleaved_ref(decoded); byte_buf.copy_interleaved_ref(decoded);
let samples = samplerate::convert( let samples = if rate != 44100 {
samplerate::convert(
rate, rate,
44100, 44100,
2, 2,
ConverterType::Linear, ConverterType::Linear,
byte_buf.samples(), byte_buf.samples(),
) )
.unwrap(); .unwrap()
} else {
byte_buf.samples().to_vec()
};
for sample in samples { for sample in samples {
let result = s let result = s
.write( .write(