serenity-rs / songbird

An async Rust library for the Discord voice API
ISC License
384 stars 110 forks source link

Option to await until a `TrackHandle` is finished playing #148

Open Sir-Photch opened 2 years ago

Sir-Photch commented 2 years ago

I suggest adding some way for TrackHandle returned by Driver.play_source() to be awaited, for the future to be finished when the played input is finished.

I have this implemented the following way:

let (call, result) = manager.join( .... ).await;
let player = call.lock().await.play_source(....);
if let Some(duration) = player.metadata().duration {
    tokio::time::sleep(duration).await;
}

Maybe this is something that would be of use for the API?

FelixMcFelix commented 2 years ago

The correct way to do something like this is to use the existing event system: have a look at the queue implementation to get a feel for how tracks can handle an event on end.

I think a utility function that makes use of this might be useful though, if a little tough to get right ergonomically. I.e., you want to register events before you play a track to ensure no Ends can be missed (though this should only be possible on 0--20ms sources), but naturally you have to play it after registering the event!

Sir-Photch commented 2 years ago

I see. I am not sure though, if this applies to my usecase.

I think a utility function that makes use of this might be useful though, if a little tough to get right ergonomically.

Well, what if .play_source() returns a tuple consisting of the player as well as some handle that can be joined? Then, the events could be registered internally, before the actual process of playing the input starts.

FelixMcFelix commented 2 years ago

Well, what if .play_source() returns a tuple...

The problem with doing this is that every single user now pays for an extra event registration, channel allocation, etc. – it isn't zero-cost, regardless of whether they use the feature or not. So this is unlikely to happen.

You could also attach a global event handler to the End event, and simply store a one-shot channel for each needed UUID. All you need to do is await a response on the channel to get the same semantics.