From 7797dbf89afd42118f2c1d427ce0d13a91c2d603 Mon Sep 17 00:00:00 2001 From: "DavidCrompton1192@gmail.com" Date: Sun, 12 Mar 2023 13:10:05 -0400 Subject: [PATCH] Move Ding to DriverConnect --- src/vc/mod.rs | 201 +++++++++++++++++++++++++++----------------------- 1 file changed, 109 insertions(+), 92 deletions(-) diff --git a/src/vc/mod.rs b/src/vc/mod.rs index e053044..1478a4d 100644 --- a/src/vc/mod.rs +++ b/src/vc/mod.rs @@ -4,16 +4,18 @@ use serenity::{async_trait, model::prelude::{ChannelId, Guild}, prelude::{Context, Mutex}}; use songbird::{EventHandler, Event, EventContext, - model::payload::{Speaking, ClientDisconnect}, ffmpeg, create_player, Call, CoreEvent}; + model::payload::{Speaking, ClientDisconnect}, ffmpeg, create_player, Call, CoreEvent, events::context_data::ConnectData}; -struct Receiver; +struct Receiver { + call : Arc>, +} impl Receiver { - pub fn new() -> Self { - // You can manage state here, such as a buffer of audio packet bytes so - // you can later store them in intervals. - Self { - + pub fn new(call: Arc>) -> Self { + // You can manage state here, such as a buffer of audio packet bytes so + // you can later store them in intervals. + Self { + call } } } @@ -22,76 +24,91 @@ impl Receiver { impl EventHandler for Receiver { #[allow(unused_variables)] async fn act(&self, ctx: &EventContext<'_>) -> Option { - use EventContext as Ctx; - match ctx { - Ctx::SpeakingStateUpdate( - Speaking {speaking, ssrc, user_id, ..} - ) => { - // Discord voice calls use RTP, where every sender uses a randomly allocated - // *Synchronisation Source* (SSRC) to allow receivers to tell which audio - // stream a received packet belongs to. As this number is not derived from - // the sender's user_id, only Discord Voice Gateway messages like this one - // inform us about which random SSRC a user has been allocated. Future voice - // packets will contain *only* the SSRC. - // - // You can implement logic here so that you can differentiate users' - // SSRCs and map the SSRC to the User ID and maintain this state. - // Using this map, you can map the `ssrc` in `voice_packet` - // to the user ID and handle their audio packets separately. - println!( - "Speaking state update: user {:?} has SSRC {:?}, using {:?}", - user_id, - ssrc, - speaking, - ); - }, - Ctx::SpeakingUpdate(data) => { - // You can implement logic here which reacts to a user starting - // or stopping speaking, and to map their SSRC to User ID. - println!( - "Source {} has {} speaking.", - data.ssrc, - if data.speaking {"started"} else {"stopped"}, - ); - }, - Ctx::VoicePacket(data) => { - // An event which fires for every received audio packet, - // containing the decoded data. - if let Some(audio) = data.audio { - println!("Audio packet's first 5 samples: {:?}", audio.get(..5.min(audio.len()))); - println!( - "Audio packet sequence {:05} has {:04} bytes (decompressed from {}), SSRC {}", - data.packet.sequence.0, - audio.len() * std::mem::size_of::(), - data.packet.payload.len(), - data.packet.ssrc, - ); - } else { - println!("RTP packet, but no audio. Driver may not be configured to decode."); - } - }, - Ctx::RtcpPacket(data) => { - // An event which fires for every received rtcp packet, - // containing the call statistics and reporting information. - println!("RTCP packet received: {:?}", data.packet); - }, - Ctx::ClientDisconnect( - ClientDisconnect {user_id, ..} - ) => { - // You can implement your own logic here to handle a user who has left the - // voice channel e.g., finalise processing of statistics etc. - // You will typically need to map the User ID to their SSRC; observed when - // first speaking. + use EventContext as Ctx; + match ctx { + Ctx::SpeakingStateUpdate( + Speaking {speaking, ssrc, user_id, ..} + ) => { + // Discord voice calls use RTP, where every sender uses a randomly allocated + // *Synchronisation Source* (SSRC) to allow receivers to tell which audio + // stream a received packet belongs to. As this number is not derived from + // the sender's user_id, only Discord Voice Gateway messages like this one + // inform us about which random SSRC a user has been allocated. Future voice + // packets will contain *only* the SSRC. + // + // You can implement logic here so that you can differentiate users' + // SSRCs and map the SSRC to the User ID and maintain this state. + // Using this map, you can map the `ssrc` in `voice_packet` + // to the user ID and handle their audio packets separately. + println!( + "Speaking state update: user {:?} has SSRC {:?}, using {:?}", + user_id, + ssrc, + speaking, + ); + }, + Ctx::SpeakingUpdate(data) => { + // You can implement logic here which reacts to a user starting + // or stopping speaking, and to map their SSRC to User ID. + println!( + "Source {} has {} speaking.", + data.ssrc, + if data.speaking {"started"} else {"stopped"}, + ); + }, + Ctx::VoicePacket(data) => { + // An event which fires for every received audio packet, + // containing the decoded data. + if let Some(audio) = data.audio { + println!("Audio packet's first 5 samples: {:?}", audio.get(..5.min(audio.len()))); + println!( + "Audio packet sequence {:05} has {:04} bytes (decompressed from {}), SSRC {}", + data.packet.sequence.0, + audio.len() * std::mem::size_of::(), + data.packet.payload.len(), + data.packet.ssrc, + ); + } else { + println!("RTP packet, but no audio. Driver may not be configured to decode."); + } + }, + Ctx::RtcpPacket(data) => { + // An event which fires for every received rtcp packet, + // containing the call statistics and reporting information. + println!("RTCP packet received: {:?}", data.packet); + }, + Ctx::ClientDisconnect( + ClientDisconnect {user_id, ..} + ) => { + // You can implement your own logic here to handle a user who has left the + // voice channel e.g., finalise processing of statistics etc. + // You will typically need to map the User ID to their SSRC; observed when + // first speaking. - println!("Client disconnected: user {:?}", user_id); - }, - _ => { - // We won't be registering this struct for any more event classes. - unimplemented!() - } - } + println!("Client disconnected: user {:?}", user_id); + }, + Ctx::DriverConnect( + ConnectData { channel_id, ..} + ) => { + match channel_id { + Some(chan) => { + let ding_src = + std::env::var("DING_SOUND").expect("DING not found in DING_SOUND"); + let ding = ffmpeg(ding_src).await.expect("no ding."); + let (audio, handle) = create_player(ding); + let mut call = self.call.lock().await; + call.play(audio); + }, + None => {} + } + }, + _ => { + // We won't be registering this struct for any more event classes. + unimplemented!() + } + } - None + None } } @@ -99,46 +116,46 @@ pub async fn join(ctx: Context, guild: Guild, cid: ChannelId) -> Option { + Ok(_) => { + let call_handle = call.clone(); { let mut call = call.lock().await; call.add_global_event( CoreEvent::SpeakingUpdate.into(), - Receiver::new(), + Receiver::new(call_handle.clone()), ); call.add_global_event( CoreEvent::VoicePacket.into(), - Receiver::new(), + Receiver::new(call_handle.clone()), ); call.add_global_event( CoreEvent::RtcpPacket.into(), - Receiver::new(), + Receiver::new(call_handle.clone()), ); call.add_global_event( CoreEvent::ClientDisconnect.into(), - Receiver::new(), + Receiver::new(call_handle.clone()), ); - + call.add_global_event( CoreEvent::ClientDisconnect.into(), - Receiver::new(), + Receiver::new(call_handle.clone()), + ); + + call.add_global_event( + CoreEvent::DriverConnect.into(), + Receiver::new(call_handle.clone()), ); - - let ding_src = - std::env::var("DING_SOUND").expect("DING not found in DING_SOUND"); - let ding = ffmpeg(ding_src).await.expect("no ding."); - let (audio, handle) = create_player(ding); - call.play(audio); } return Some(call); - } - Err(_err) => { - println!("Error joining channel"); - } + } + Err(_err) => { + println!("Error joining channel"); + } } None }