Events: Break out and non-exhaust context body structs (#54)

This PR makes many of the types under `EventContext` separate `#[non_exhaustive]` structs. This makes it more feasible to add further information to connection and packet events as required in future. On this note, driver (re)connection events now include the SSRC supplied by Discord and the domain name which was connected to.

In addition, this fixes global timed events to return a list of all live tracks, and extensively details/documents events at a high level.

This was tested using `cargo make ready`.
This commit is contained in:
Kyle Simpson
2021-04-07 12:52:05 +01:00
parent 1bfee1b989
commit 27f26ade99
14 changed files with 321 additions and 129 deletions

130
src/events/context/mod.rs Normal file
View File

@@ -0,0 +1,130 @@
pub mod data;
pub(crate) mod internal_data;
use super::*;
use crate::{
model::payload::{ClientConnect, ClientDisconnect, Speaking},
tracks::{TrackHandle, TrackState},
};
pub use data as context_data;
use data::*;
use internal_data::*;
/// Information about which tracks or data fired an event.
///
/// [`Track`] events may be local or global, and have no tracks
/// if fired on the global context via [`Driver::add_global_event`].
///
/// [`Track`]: crate::tracks::Track
/// [`Driver::add_global_event`]: crate::driver::Driver::add_global_event
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum EventContext<'a> {
/// Track event context, passed to events created via [`TrackHandle::add_event`],
/// [`EventStore::add_event`], or relevant global events.
///
/// [`EventStore::add_event`]: EventStore::add_event
/// [`TrackHandle::add_event`]: TrackHandle::add_event
Track(&'a [(&'a TrackState, &'a TrackHandle)]),
/// Speaking state update, typically describing how another voice
/// user is transmitting audio data. Clients must send at least one such
/// packet to allow SSRC/UserID matching.
SpeakingStateUpdate(Speaking),
/// Speaking state transition, describing whether a given source has started/stopped
/// transmitting. This fires in response to a silent burst, or the first packet
/// breaking such a burst.
SpeakingUpdate(SpeakingUpdateData),
/// Opus audio packet, received from another stream.
VoicePacket(VoiceData<'a>),
/// Telemetry/statistics packet, received from another stream.
RtcpPacket(RtcpData<'a>),
/// Fired whenever a client connects to a call for the first time, allowing SSRC/UserID
/// matching.
ClientConnect(ClientConnect),
/// Fired whenever a client disconnects.
ClientDisconnect(ClientDisconnect),
/// Fires when this driver successfully connects to a voice channel.
DriverConnect(ConnectData<'a>),
/// Fires when this driver successfully reconnects after a network error.
DriverReconnect(ConnectData<'a>),
/// Fires when this driver fails to connect to a voice channel.
DriverConnectFailed,
/// Fires when this driver fails to reconnect to a voice channel after a network error.
///
/// Users will need to manually reconnect on receipt of this error.
DriverReconnectFailed,
#[deprecated(
since = "0.2.0",
note = "Please use the DriverConnect/Reconnect events instead."
)]
/// Fires whenever the driver is assigned a new [RTP SSRC] by the voice server.
///
/// This typically fires alongside a [DriverConnect], or a full [DriverReconnect].
/// **This event is *deprecated* in favour of these alternatives**.
///
/// [RTP SSRC]: https://tools.ietf.org/html/rfc3550#section-3
/// [DriverConnect]: Self::DriverConnect
/// [DriverReconnect]: Self::DriverReconnect
// TODO: remove in 0.3.x
SsrcKnown(u32),
}
#[derive(Clone, Debug)]
pub enum CoreContext {
SpeakingStateUpdate(Speaking),
SpeakingUpdate(InternalSpeakingUpdate),
VoicePacket(InternalVoicePacket),
RtcpPacket(InternalRtcpPacket),
ClientConnect(ClientConnect),
ClientDisconnect(ClientDisconnect),
DriverConnect(InternalConnect),
DriverReconnect(InternalConnect),
DriverConnectFailed,
DriverReconnectFailed,
SsrcKnown(u32),
}
impl<'a> CoreContext {
pub(crate) fn to_user_context(&'a self) -> EventContext<'a> {
use CoreContext::*;
match self {
SpeakingStateUpdate(evt) => EventContext::SpeakingStateUpdate(*evt),
SpeakingUpdate(evt) => EventContext::SpeakingUpdate(SpeakingUpdateData::from(evt)),
VoicePacket(evt) => EventContext::VoicePacket(VoiceData::from(evt)),
RtcpPacket(evt) => EventContext::RtcpPacket(RtcpData::from(evt)),
ClientConnect(evt) => EventContext::ClientConnect(*evt),
ClientDisconnect(evt) => EventContext::ClientDisconnect(*evt),
DriverConnect(evt) => EventContext::DriverConnect(ConnectData::from(evt)),
DriverReconnect(evt) => EventContext::DriverReconnect(ConnectData::from(evt)),
DriverConnectFailed => EventContext::DriverConnectFailed,
DriverReconnectFailed => EventContext::DriverReconnectFailed,
#[allow(deprecated)]
SsrcKnown(s) => EventContext::SsrcKnown(*s),
}
}
}
impl EventContext<'_> {
/// Retreive the event class for an event (i.e., when matching)
/// an event against the registered listeners.
pub fn to_core_event(&self) -> Option<CoreEvent> {
use EventContext::*;
match self {
SpeakingStateUpdate { .. } => Some(CoreEvent::SpeakingStateUpdate),
SpeakingUpdate { .. } => Some(CoreEvent::SpeakingUpdate),
VoicePacket { .. } => Some(CoreEvent::VoicePacket),
RtcpPacket { .. } => Some(CoreEvent::RtcpPacket),
ClientConnect { .. } => Some(CoreEvent::ClientConnect),
ClientDisconnect { .. } => Some(CoreEvent::ClientDisconnect),
DriverConnect(_) => Some(CoreEvent::DriverConnect),
DriverReconnect(_) => Some(CoreEvent::DriverReconnect),
DriverConnectFailed => Some(CoreEvent::DriverConnectFailed),
DriverReconnectFailed => Some(CoreEvent::DriverReconnectFailed),
#[allow(deprecated)]
SsrcKnown(_) => Some(CoreEvent::SsrcKnown),
_ => None,
}
}
}