Tracks: Add TypeMap to Handles.

Adds a shared TypeMap per TrackHandle. This should greatly simplify the user experience for attaching additional per-track state which the driver does not care for.
This commit is contained in:
Kyle Simpson
2021-01-02 23:43:28 +00:00
parent 873458d288
commit d42e09f72b
4 changed files with 47 additions and 9 deletions

View File

@@ -91,6 +91,10 @@ optional = true
version = "0.2" version = "0.2"
default-features = false default-features = false
[dependencies.typemap_rev]
optional = true
version = "0.1"
[dependencies.url] [dependencies.url]
optional = true optional = true
version = "2" version = "2"
@@ -140,6 +144,7 @@ driver = [
"tokio/rt-core", "tokio/rt-core",
"tokio/sync", "tokio/sync",
"tokio/time", "tokio/time",
"typemap_rev",
"url", "url",
"uuid", "uuid",
"xsalsa20poly1305", "xsalsa20poly1305",

View File

@@ -66,6 +66,8 @@ pub use audiopus::{self as opus, Bitrate};
pub use discortp as packet; pub use discortp as packet;
#[cfg(feature = "driver")] #[cfg(feature = "driver")]
pub use serenity_voice_model as model; pub use serenity_voice_model as model;
#[cfg(feature = "driver")]
pub use typemap_rev as typemap;
#[cfg(test)] #[cfg(test)]
use utils as test_utils; use utils as test_utils;

View File

@@ -3,29 +3,45 @@ use crate::{
events::{Event, EventData, EventHandler}, events::{Event, EventData, EventHandler},
input::Metadata, input::Metadata,
}; };
use std::{sync::Arc, time::Duration}; use std::{fmt, sync::Arc, time::Duration};
use tokio::sync::{mpsc::UnboundedSender, oneshot}; use tokio::sync::{mpsc::UnboundedSender, oneshot, RwLock};
use typemap_rev::TypeMap;
use uuid::Uuid; use uuid::Uuid;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
/// Handle for safe control of a [`Track`] track from other threads, outside /// Handle for safe control of a [`Track`] from other threads, outside
/// of the audio mixing and voice handling context. /// of the audio mixing and voice handling context.
/// ///
/// Almost all method calls here are fallible; in most cases, this will be because /// These are cheap to clone, using `Arc<...>` internally.
///
/// Many method calls here are fallible; in most cases, this will be because
/// the underlying [`Track`] object has been discarded. Those which aren't refer /// the underlying [`Track`] object has been discarded. Those which aren't refer
/// to immutable properties of the underlying stream. /// to immutable properties of the underlying stream, or shared data not used
/// by the driver.
/// ///
/// [`Track`]: Track /// [`Track`]: Track
pub struct TrackHandle { pub struct TrackHandle {
inner: Arc<InnerHandle>, inner: Arc<InnerHandle>,
} }
#[derive(Clone, Debug)]
struct InnerHandle { struct InnerHandle {
command_channel: UnboundedSender<TrackCommand>, command_channel: UnboundedSender<TrackCommand>,
seekable: bool, seekable: bool,
metadata: Box<Metadata>,
uuid: Uuid, uuid: Uuid,
metadata: Box<Metadata>,
typemap: RwLock<TypeMap>,
}
impl fmt::Debug for InnerHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("InnerHandle")
.field("command_channel", &self.command_channel)
.field("seekable", &self.seekable)
.field("uuid", &self.uuid)
.field("metadata", &self.metadata)
.field("typemap", &"<LOCK>")
.finish()
}
} }
impl TrackHandle { impl TrackHandle {
@@ -42,8 +58,9 @@ impl TrackHandle {
let inner = Arc::new(InnerHandle { let inner = Arc::new(InnerHandle {
command_channel, command_channel,
seekable, seekable,
metadata,
uuid, uuid,
metadata,
typemap: RwLock::new(TypeMap::new()),
}); });
Self { inner } Self { inner }
@@ -209,6 +226,17 @@ impl TrackHandle {
&self.inner.metadata &self.inner.metadata
} }
/// Allows access to this track's attached TypeMap.
///
/// TypeMaps allow additional, user-defined data shared by all handles
/// to be attached to any track.
///
/// Driver code will never attempt to lock access to this map,
/// preventing deadlock/stalling.
pub fn typemap(&self) -> &RwLock<TypeMap> {
&self.inner.typemap
}
#[inline] #[inline]
/// Send a raw command to the [`Track`] object. /// Send a raw command to the [`Track`] object.
/// ///

View File

@@ -382,9 +382,12 @@ pub fn create_player(source: Input) -> (Track, TrackHandle) {
create_player_with_uuid(source, Uuid::new_v4()) create_player_with_uuid(source, Uuid::new_v4())
} }
/// Refer to the documentation for [`create_player`] however, allows for a custom uuid to be inserted into the Track and Handle /// Creates a [`Track`] and [`TrackHandle`] as in [`create_player`], allowing
/// a custom UUID to be set.
/// ///
/// [`create_player`]: create_player /// [`create_player`]: create_player
/// [`Track`]: Track
/// [`TrackHandle`]: TrackHandle
pub fn create_player_with_uuid(source: Input, uuid: Uuid) -> (Track, TrackHandle) { pub fn create_player_with_uuid(source: Input, uuid: Uuid) -> (Track, TrackHandle) {
let (tx, rx) = mpsc::unbounded_channel(); let (tx, rx) = mpsc::unbounded_channel();
let can_seek = source.is_seekable(); let can_seek = source.is_seekable();