//! Events relating to tracks, timing, and other callers. //! //! ## Listening for events //! Driver events in Songbird are composed of two parts: //! * An [`Event`] to listen out for. These may be discrete events, //! or generated by timers. //! * An [`EventHandler`] to be called on receipt of an event. As event //! handlers may be shared between several events, the handler is called //! with an [`EventContext`] describing which event was fired. //! //! Event handlers are registered using functions such as [`Driver::add_global_event`], //! or [`TrackHandle::add_event`], or. Internally, these pairs are stored //! as [`EventData`]. //! //! ## `EventHandler` lifecycle //! An event handler is essentially just an async function which may return //! another type of event to listen out for (an `Option`). For instance, //! [`Some(Event::Cancel)`] will remove that event listener, while `None` won't //! change it at all. //! //! The exception is one-off events like [`Event::Delayed`], which remove themselves //! after one call *unless* an [`Event`] override is returned. //! //! ## Global and local listeners //! *Global* event listeners are those which are placed onto the [`Driver`], //! while *local* event listeners are those which are placed on a //! [`Track`]/[`Handle`]. //! //! Track or timed events, when local, return a reference to the parent track. //! When registered globally, they fire on a per-tick basis, returning references to //! all relevant tracks in that 20ms window. Global/local timed events use a global //! timer or a [track's playback time], respectively. //! //! [`CoreEvent`]s may only be registered globally. //! //! [`Event`]: Event //! [`EventHandler`]: EventHandler //! [`EventContext`]: EventContext //! [`Driver::add_global_event`]: crate::driver::Driver::add_global_event //! [`Driver`]: crate::driver::Driver::add_global_event //! [`TrackHandle::add_event`]: crate::tracks::TrackHandle::add_event //! [`Track`]: crate::tracks::Track::events //! [`Handle`]: crate::tracks::TrackHandle::add_event //! [`EventData`]: EventData //! [`Some(Event::Cancel)`]: Event::Cancel //! [`Event::Delayed`]: Event::Delayed //! [track's playback time]: crate::tracks::TrackState::play_time //! [`CoreEvent`]: CoreEvent mod context; mod core; mod data; mod store; mod track; mod untimed; pub use self::{ context::{context_data, EventContext}, core::*, data::*, store::*, track::*, untimed::*, }; pub(crate) use context::{internal_data, CoreContext}; use async_trait::async_trait; use std::time::Duration; /// Trait to handle an event which can be fired per-track, or globally. /// /// These may be feasibly reused between several event sources. #[async_trait] pub trait EventHandler: Send + Sync { /// Respond to one received event. async fn act(&self, ctx: &EventContext<'_>) -> Option; } /// Classes of event which may occur, triggering a handler /// at the local (track-specific) or global level. /// /// Local time-based events rely upon the current playback /// time of a track, and so will not fire if a track becomes paused /// or stops. In case this is required, global events are a better /// fit. /// /// Event handlers themselves are described in [`EventData::new`]. /// /// [`EventData::new`]: EventData::new #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[non_exhaustive] pub enum Event { /// Periodic events rely upon two parameters: a *period* /// and an optional *phase*. /// /// If the *phase* is `None`, then the event will first fire /// in one *period*. Periodic events repeat automatically /// so long as the `action` in [`EventData`] returns `None`. /// /// [`EventData`]: EventData Periodic(Duration, Option), /// Delayed events rely upon a *delay* parameter, and /// fire one *delay* after the audio context processes them. /// /// Delayed events are automatically removed once fired, /// so long as the `action` in [`EventData`] returns `None`. /// /// [`EventData`]: EventData Delayed(Duration), /// Track events correspond to certain actions or changes /// of state, such as a track finishing, looping, or being /// manually stopped. /// /// Track events persist while the `action` in [`EventData`] /// returns `None`. /// /// [`EventData`]: EventData Track(TrackEvent), /// Core events /// /// Track events persist while the `action` in [`EventData`] /// returns `None`. Core events **must** be applied globally, /// as attaching them to a track is a no-op. /// /// [`EventData`]: EventData Core(CoreEvent), /// Cancels the event, if it was intended to persist. Cancel, } impl Event { pub(crate) fn is_global_only(&self) -> bool { matches!(self, Self::Core(_)) } } impl From for Event { fn from(evt: TrackEvent) -> Self { Event::Track(evt) } } impl From for Event { fn from(evt: CoreEvent) -> Self { Event::Core(evt) } }