mirror of
https://github.com/jhbruhn/jellyfin-radio.git
synced 2025-03-14 19:45:50 +00:00
Fix sync problem for wait_for_queue function, custom fork of awedio for now
This commit is contained in:
parent
0053c7a8cc
commit
57076b33ec
6 changed files with 53 additions and 48 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -83,8 +83,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "awedio"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1e49f94356350dde8c54c5cbde90bdfa5642ab25f9c51c60a9ebdfdf3dbef87"
|
||||
source = "git+https://github.com/jhbruhn/awedio.git?branch=symphonia-recover-errors#188442284efea9147e0a37e42edc6ae8ddee10af"
|
||||
dependencies = [
|
||||
"log",
|
||||
"symphonia",
|
||||
|
|
|
@ -8,7 +8,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
reqwest = { version = "0.11", features = ["json", "stream", "native-tls-vendored"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
awedio = { version = "0.3", features = ["symphonia-all", "async"], default-features = false }
|
||||
awedio = { git = "https://github.com/jhbruhn/awedio.git", branch = "symphonia-recover-errors", features = ["symphonia-all", "async"], default-features = false }
|
||||
anyhow = "1.0"
|
||||
mp3lame-encoder = { git = "https://github.com/jhbruhn/mp3lame-encoder.git", branch = "arm" }
|
||||
tokio-stream = { version = "0.1", features = ["sync", "fs"] }
|
||||
|
|
|
@ -150,10 +150,12 @@ impl JellyfinClient {
|
|||
.map(|s| s.replace("\"", ""));
|
||||
let body = response.bytes().await?;
|
||||
|
||||
let decoder = Box::new(awedio::sounds::decoders::SymphoniaDecoder::new(
|
||||
let decoder = awedio::sounds::decoders::SymphoniaDecoder::new(
|
||||
Box::new(symphonia::core::io::ReadOnlySource::new(body.reader())),
|
||||
extension.as_deref(),
|
||||
)?);
|
||||
)?;
|
||||
|
||||
let decoder = Box::new(decoder);
|
||||
|
||||
Ok(decoder)
|
||||
}
|
||||
|
|
|
@ -123,7 +123,6 @@ async fn main() -> anyhow::Result<()> {
|
|||
let mut announce_downmix_player_controller = player_controller.clone();
|
||||
tokio::task::spawn(async move {
|
||||
loop {
|
||||
tokio::task::yield_now().await;
|
||||
player_controller.wait_for_queue().await;
|
||||
|
||||
tracing::info!("Queuing song");
|
||||
|
@ -168,8 +167,6 @@ async fn main() -> anyhow::Result<()> {
|
|||
|
||||
let time_file_map = get_time_file_map(&time_file_path).await;
|
||||
loop {
|
||||
tokio::task::yield_now().await;
|
||||
|
||||
let fade_duration = Duration::from_secs(2);
|
||||
let fade_steps = 100;
|
||||
let fade_minimum_level = 0.1;
|
||||
|
@ -224,7 +221,9 @@ async fn main() -> anyhow::Result<()> {
|
|||
|
||||
tracing::info!("Playing interstitial {:?}", next_path);
|
||||
|
||||
if let Ok(sound) = awedio::sounds::open_file(next_path.as_path()) {
|
||||
if let Ok(sound) =
|
||||
tokio::task::block_in_place(|| awedio::sounds::open_file(next_path.as_path()))
|
||||
{
|
||||
let (sound, completion_notifier) = sound.with_async_completion_notifier();
|
||||
for v in (fade_steps_min..=fade_steps_max).rev() {
|
||||
let volume = v as f32 / fade_steps as f32;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use awedio::NextSample;
|
||||
use awedio::Sound;
|
||||
use std::sync::mpsc;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Notify;
|
||||
|
||||
/// Heavily Based on awedios SoundList and Controllable implementations
|
||||
|
||||
|
@ -16,19 +18,18 @@ type Command<S> = Box<dyn FnOnce(&mut S) + Send>;
|
|||
pub struct PlayerControllable {
|
||||
inner: Player,
|
||||
command_receiver: mpsc::Receiver<Command<Player>>,
|
||||
queue_next_song_sender: tokio::sync::watch::Sender<bool>,
|
||||
queue_next_song_notify: Arc<Notify>,
|
||||
finished: bool,
|
||||
}
|
||||
|
||||
pub struct PlayerController {
|
||||
command_sender: mpsc::Sender<Command<Player>>,
|
||||
queue_next_song_receiver: tokio::sync::watch::Receiver<bool>,
|
||||
queue_next_song_notify: Arc<Notify>,
|
||||
}
|
||||
|
||||
impl Player {
|
||||
/// Create a new empty Player.
|
||||
pub fn new(song_prefetch: u32) -> (PlayerControllable, PlayerController) {
|
||||
let (queue_next_song_sender, queue_next_song_receiver) = tokio::sync::watch::channel(false);
|
||||
let inner = Player {
|
||||
sounds: Vec::new(),
|
||||
was_empty: false,
|
||||
|
@ -36,16 +37,18 @@ impl Player {
|
|||
volume_adjustment: 1.0,
|
||||
};
|
||||
|
||||
let queue_next_song_notify = Arc::new(tokio::sync::Notify::new());
|
||||
let (command_sender, command_receiver) = mpsc::channel::<Command<Player>>();
|
||||
let controllable = PlayerControllable {
|
||||
inner,
|
||||
queue_next_song_sender,
|
||||
queue_next_song_notify: queue_next_song_notify.clone(),
|
||||
command_receiver,
|
||||
finished: false,
|
||||
};
|
||||
|
||||
let controller = PlayerController {
|
||||
command_sender,
|
||||
queue_next_song_receiver,
|
||||
queue_next_song_notify,
|
||||
};
|
||||
|
||||
(controllable, controller)
|
||||
|
@ -64,7 +67,7 @@ impl Player {
|
|||
}
|
||||
|
||||
fn should_prefetch(&self) -> bool {
|
||||
self.sounds.len() < self.song_prefetch as usize
|
||||
self.sounds.len() <= self.song_prefetch as usize
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,6 +131,14 @@ impl Sound for Player {
|
|||
}
|
||||
}
|
||||
|
||||
impl PlayerControllable {
|
||||
fn notify_next_song_queue_if_needed(&mut self) {
|
||||
if self.inner.should_prefetch() {
|
||||
self.queue_next_song_notify.notify_waiters();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sound for PlayerControllable {
|
||||
fn channel_count(&self) -> u16 {
|
||||
self.inner.channel_count()
|
||||
|
@ -140,9 +151,12 @@ impl Sound for PlayerControllable {
|
|||
fn next_sample(&mut self) -> Result<awedio::NextSample, awedio::Error> {
|
||||
let next = self.inner.next_sample()?;
|
||||
match next {
|
||||
awedio::NextSample::Sample(_)
|
||||
| awedio::NextSample::MetadataChanged
|
||||
| awedio::NextSample::Paused => Ok(next),
|
||||
awedio::NextSample::Sample(_) | awedio::NextSample::Paused => Ok(next),
|
||||
awedio::NextSample::MetadataChanged => {
|
||||
// Maybe a new track has started
|
||||
self.notify_next_song_queue_if_needed();
|
||||
Ok(next)
|
||||
}
|
||||
// Since this is controllable we might add another sound later.
|
||||
// Ideally we would do this only if the inner sound can have sounds
|
||||
// added to it but I don't think we can branch on S: AddSound here.
|
||||
|
@ -169,15 +183,7 @@ impl Sound for PlayerControllable {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
let _ = self.queue_next_song_sender.send_if_modified(|v| {
|
||||
if *v != self.inner.should_prefetch() {
|
||||
*v = self.inner.should_prefetch();
|
||||
return true;
|
||||
}
|
||||
false
|
||||
});
|
||||
|
||||
self.notify_next_song_queue_if_needed();
|
||||
self.inner.on_start_of_batch();
|
||||
}
|
||||
}
|
||||
|
@ -195,7 +201,7 @@ impl Clone for PlayerController {
|
|||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
command_sender: self.command_sender.clone(),
|
||||
queue_next_song_receiver: self.queue_next_song_receiver.clone(),
|
||||
queue_next_song_notify: self.queue_next_song_notify.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -210,6 +216,6 @@ impl PlayerController {
|
|||
}
|
||||
|
||||
pub async fn wait_for_queue(&mut self) {
|
||||
let _ = self.queue_next_song_receiver.wait_for(|v| *v == true).await;
|
||||
self.queue_next_song_notify.notified().await;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ use hyper::{Response, StatusCode};
|
|||
const SAMPLE_RATE: u64 = 48000;
|
||||
const CHANNEL_COUNT: u64 = 2;
|
||||
|
||||
const BUFFER_SIZE: usize = 2000; // Should be an integer result of 48000 / 2 / x
|
||||
const BUFFER_SIZE: usize = (SAMPLE_RATE / CHANNEL_COUNT / 10) as usize; // Should be an integer result of 48000 / 2 / x
|
||||
|
||||
type Chunk = [i16; BUFFER_SIZE];
|
||||
|
||||
|
@ -31,17 +31,16 @@ impl StreamerBackend {
|
|||
panic!("expected MetadataChanged event")
|
||||
};
|
||||
|
||||
let (mut s, stream_receiver) = async_broadcast::broadcast(3);
|
||||
let (mut s, stream_receiver) = async_broadcast::broadcast(10);
|
||||
s.set_overflow(true);
|
||||
|
||||
tokio::spawn(async move {
|
||||
let mut stream = tokio_stream::wrappers::IntervalStream::new(tokio::time::interval(
|
||||
Duration::from_millis(1000 * BUFFER_SIZE as u64 / CHANNEL_COUNT / SAMPLE_RATE),
|
||||
Duration::from_millis((1000 * BUFFER_SIZE as u64) / CHANNEL_COUNT / SAMPLE_RATE),
|
||||
))
|
||||
.map(move |_| {
|
||||
let mut buffer = [0_i16; BUFFER_SIZE];
|
||||
renderer.on_start_of_batch();
|
||||
tokio::task::block_in_place(|| {
|
||||
let mut buffer: [i16; 2400] = [0_i16; BUFFER_SIZE];
|
||||
buffer.fill_with(|| {
|
||||
let sample = renderer
|
||||
.next_sample()
|
||||
|
@ -56,7 +55,7 @@ impl StreamerBackend {
|
|||
};
|
||||
sample
|
||||
});
|
||||
});
|
||||
|
||||
Box::new(buffer)
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue