Noticeable delay between playing (streaming) different, in-memory inputs. #223
-
I am streaming my data to the discord bot, pre-encoded in Opus and with the correct DCA1 headers and metadata. This data can change in real time, and as such is sent to songbird in ~300 ms packets (each packets has multiple frames, all with correct size headers attached to them). In 0.3.2 I had the streaming working seamlessly after some help at #192. However, now in 0.4.0, there seems to be additional delay between the playing of each of these packets. To rule out any possibility of this delay being caused by my implementation, I essentially queued up 10-20 of these packets and played them back, and it does have a noticeable delay between playing each of the 300ms packets. Could this be due to using DCA1 as the use of DCA0 is now not supported? In 0.3.2, you could specify the Container and Codec yourself, so I never included any DCA1 specific information and had it "force" passthrough (?) on the data. The delay is not from any of the in-between steps either. I get a byte array by stream, so I can Is this known? And is there any way to remove this delay, something specific to streaming or similar? // This function is called each time a packet is received.
pub async fn play_music(set: AudioSet) {
use songbird::input::{
Input,
codecs::{CODEC_REGISTRY, PROBE},
};
// SONG: OnceCell<Arc<Songbird>>
let sb = SONG.get().expect("Songbird not found!").clone();
if let Some(h) = sb.get(set.guild_id) {
let mut handler = h.lock().await;
let audio: Input = set.audio_data.into();
let audio: Input = audio.make_playable_async(&CODEC_REGISTRY, &PROBE).await
.expect("Can't make audio playable!");
let track_handle = handler.play_input(audio);
while track_handle.get_info().await.unwrap().playing == songbird::tracks::PlayMode::Play {}
}
} |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 7 replies
-
This shouldn't be down to DCA0 vs DCA1 -- parsing a small block of json is probably not expensive to pay once, as an audible gap here would exceed ~25--50ms, I'm guessing. You'd need an insanely large metadata block to blow past that in terms of cost. I have to ask what you mean by packet: are you playing these as individual DCA files? I.e. n x {DCA header + 15 x 20ms frame}? If so then your tracks are almost certainly being handed off to an aux thread to be made ready -- this is cheap work, but will insert at least one tick between sending the track off and awaiting the response. Part of this is that songbird now treats all track initialisation lazily by default. You should be able to upgrade your Inputs before you play them to prevent this: https://docs.rs/songbird/latest/songbird/input/enum.Input.html#method.make_playable_async. The ideal fix would be to write a custom Read implementation which emits the headers once. You would just dump frames into via an mpsc, and an empty channel read would emit a silent frame (I don't know if we export this definition, but it's in our constants.rs). Note that writing this correctly is a bit tricky! So I'd recommend you try the former first. :) |
Beta Was this translation helpful? Give feedback.
You're perhaps looking too far ahead -- you should be looking for where the packet data is built/encrypted/... in the mixer task, and then placed into
self.packets
. The important part is in the mixer task:songbird/src/driver/tasks/mixer/mod.rs
Lines 743 to 868 in 087e5f2