aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/10_voice_receive/Cargo.toml14
-rw-r--r--examples/10_voice_receive/src/main.rs158
2 files changed, 172 insertions, 0 deletions
diff --git a/examples/10_voice_receive/Cargo.toml b/examples/10_voice_receive/Cargo.toml
new file mode 100644
index 0000000..fd1a520
--- /dev/null
+++ b/examples/10_voice_receive/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "10_voice_receive"
+version = "0.1.0"
+authors = ["my name <[email protected]>"]
+
+[dependencies]
+byteorder = "^1.2"
+env_logger = "~0.4"
+log = "~0.4"
+typemap = "~0.3"
+
+[dependencies.serenity]
+features = ["client", "standard_framework", "voice"]
+path = "../../"
diff --git a/examples/10_voice_receive/src/main.rs b/examples/10_voice_receive/src/main.rs
new file mode 100644
index 0000000..09449d6
--- /dev/null
+++ b/examples/10_voice_receive/src/main.rs
@@ -0,0 +1,158 @@
+//! Requires the "client", "standard_framework", and "voice" features be enabled
+//! in your Cargo.toml, like so:
+//!
+//! ```toml
+//! [dependencies.serenity]
+//! git = "https://github.com/zeyla/serenity.git"
+//! features = ["client", "standard_framework", "voice"]
+//! ```
+
+#[macro_use] extern crate serenity;
+
+extern crate typemap;
+
+use serenity::client::bridge::voice::ClientVoiceManager;
+use serenity::client::{CACHE, Client, Context, EventHandler};
+use serenity::framework::StandardFramework;
+use serenity::model::channel::Message;
+use serenity::model::gateway::Ready;
+use serenity::model::id::ChannelId;
+use serenity::model::misc::Mentionable;
+use serenity::prelude::Mutex;
+use serenity::voice::AudioReceiver;
+use serenity::Result as SerenityResult;
+use std::sync::Arc;
+use std::env;
+use typemap::Key;
+
+struct VoiceManager;
+
+impl Key for VoiceManager {
+ type Value = Arc<Mutex<ClientVoiceManager>>;
+}
+
+struct Handler;
+
+impl EventHandler for Handler {
+ fn ready(&self, _: Context, ready: Ready) {
+ println!("{} is connected!", ready.user.name);
+ }
+}
+
+struct Receiver;
+
+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 { }
+ }
+}
+
+impl AudioReceiver for Receiver {
+ fn speaking_update(&mut self, _ssrc: u32, _user_id: u64, _speaking: bool) {
+ // You can implement logic here so that you can differentiate users'
+ // SSRCs and map the SSRC to the User ID and maintain a state in
+ // `Receiver`. Using this map, you can map the `ssrc` in `voice_packet`
+ // to the user ID and handle their audio packets separately.
+ }
+
+ fn voice_packet(&mut self, ssrc: u32, sequence: u16, _timestamp: u32, _stereo: bool, data: &[i16]) {
+ println!("Audio packet's first 5 bytes: {:?}", data.get(..5));
+ println!(
+ "Audio packet sequence {:05} has {:04} bytes, SSRC {}",
+ sequence,
+ data.len(),
+ ssrc,
+ );
+ }
+}
+
+fn main() {
+ // Configure the client with your Discord bot token in the environment.
+ let token = env::var("DISCORD_TOKEN")
+ .expect("Expected a token in the environment");
+ let mut client = Client::new(&token, Handler).expect("Err creating client");
+
+ // Obtain a lock to the data owned by the client, and insert the client's
+ // voice manager into it. This allows the voice manager to be accessible by
+ // event handlers and framework commands.
+ {
+ let mut data = client.data.lock();
+ data.insert::<VoiceManager>(Arc::clone(&client.voice_manager));
+ }
+
+ client.with_framework(StandardFramework::new()
+ .configure(|c| c
+ .prefix("~")
+ .on_mention(true))
+ .cmd("join", join)
+ .cmd("leave", leave)
+ .cmd("ping", ping));
+
+ let _ = client.start().map_err(|why| println!("Client ended: {:?}", why));
+}
+
+command!(join(ctx, msg, args) {
+ let connect_to = match args.single::<u64>() {
+ Ok(id) => ChannelId(id),
+ Err(_) => {
+ check_msg(msg.reply("Requires a valid voice channel ID be given"));
+
+ return Ok(());
+ },
+ };
+
+ let guild_id = match CACHE.read().guild_channel(msg.channel_id) {
+ Some(channel) => channel.read().guild_id,
+ None => {
+ check_msg(msg.channel_id.say("Groups and DMs not supported"));
+
+ return Ok(());
+ },
+ };
+
+ let mut manager_lock = ctx.data.lock().get::<VoiceManager>().cloned().unwrap();
+ let mut manager = manager_lock.lock();
+
+ if let Some(handler) = manager.join(guild_id, connect_to) {
+ handler.listen(Some(Box::new(Receiver::new())));
+ check_msg(msg.channel_id.say(&format!("Joined {}", connect_to.mention())));
+ } else {
+ check_msg(msg.channel_id.say("Error joining the channel"));
+ }
+});
+
+command!(leave(ctx, msg) {
+ let guild_id = match CACHE.read().guild_channel(msg.channel_id) {
+ Some(channel) => channel.read().guild_id,
+ None => {
+ check_msg(msg.channel_id.say("Groups and DMs not supported"));
+
+ return Ok(());
+ },
+ };
+
+ let mut manager_lock = ctx.data.lock().get::<VoiceManager>().cloned().unwrap();
+ let mut manager = manager_lock.lock();
+ let has_handler = manager.get(guild_id).is_some();
+
+ if has_handler {
+ manager.remove(guild_id);
+
+ check_msg(msg.channel_id.say("Left voice channel"));
+ } else {
+ check_msg(msg.reply("Not in a voice channel"));
+ }
+});
+
+command!(ping(_context, msg) {
+ check_msg(msg.channel_id.say("Pong!"));
+});
+
+/// Checks that a message successfully sent; if not, then logs why to stdout.
+fn check_msg(result: SerenityResult<Message>) {
+ if let Err(why) = result {
+ println!("Error sending message: {:?}", why);
+ }
+}