Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // main.rs
- use tokio_tungstenite::{connect_async, tungstenite::protocol::Message};
- use futures::{SinkExt, StreamExt};
- use url::Url;
- use serde_json::json;
- use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
- use audiopus::coder::Decoder as OpusDecoder;
- use std::{sync::{Arc, Mutex}, collections::VecDeque};
- #[tokio::main]
- async fn main() -> Result<(), Box<dyn std::error::Error>> {
- println!("Connecting to Lavalink WS...");
- let url = Url::parse("ws://localhost:2333")?;
- let (ws_stream, _) = connect_async(url).await?;
- let (mut write, mut read) = ws_stream.split();
- // Fake Discord Voice State Update
- let voice_update = json!({
- "op": "voiceUpdate",
- "guildId": "1",
- "sessionId": "dummy",
- "event": {
- "token": "dummy",
- "guild_id": "1",
- "endpoint": "dummy"
- }
- });
- write.send(Message::Text(voice_update.to_string())).await?;
- // Load and play track
- let track_id = fetch_track().await?;
- let play = json!({
- "op": "play",
- "guildId": "1",
- "track": track_id
- });
- write.send(Message::Text(play.to_string())).await?;
- println!("Playback started.");
- // Setup Opus decoder
- let mut opus = OpusDecoder::new(48000, audiopus::Channels::Stereo)?;
- let pcm_buffer = Arc::new(Mutex::new(VecDeque::new()));
- let pcm_clone = pcm_buffer.clone();
- // Setup CPAL audio output
- let host = cpal::default_host();
- let device = host.default_output_device().ok_or("No output device")?;
- let config = device.default_output_config()?;
- let stream = device.build_output_stream(
- &config.config(),
- move |data: &mut [f32], _| {
- let mut buf = pcm_clone.lock().unwrap();
- for sample in data.iter_mut() {
- *sample = buf.pop_front().unwrap_or(0.0);
- }
- },
- |err| eprintln!("Stream error: {err}"),
- None,
- )?;
- stream.play()?;
- // Read and decode opus packets
- while let Some(msg) = read.next().await {
- if let Ok(Message::Binary(data)) = msg {
- let mut output = [0f32; 1920 * 2];
- let samples = opus.decode_float(&data, &mut output, false)?;
- pcm_buffer.lock().unwrap().extend(&output[..samples * 2]);
- } else if let Ok(Message::Text(txt)) = msg {
- println!("WS Message: {txt}");
- }
- }
- Ok(())
- }
- async fn fetch_track() -> Result<String, Box<dyn std::error::Error>> {
- let client = reqwest::Client::new();
- let res = client
- .get("http://localhost:2333/v4/loadtracks")
- .header("Authorization", "youshallnotpass")
- .query(&[("identifier", "ytsearch:Never Gonna Give You Up")])
- .send()
- .await?;
- let json: serde_json::Value = res.json().await?;
- let track = json["data"][0]["encoded"].as_str().unwrap().to_string();
- Ok(track)
- }
Advertisement
Add Comment
Please, Sign In to add comment