From d9bfc97b599af4e4e96ae403df8287a533223e32 Mon Sep 17 00:00:00 2001 From: Felix Kaaman Date: Fri, 21 Feb 2020 23:24:55 +0200 Subject: Add seeking to audio player Adds a new "!seek" command which takes in a string that will be parsed by humantime in addition to a '+' or '-' character that can be prefixed to determine if it is a relative seek. Without any prefix characters the seek will be absolute. --- src/audio_player.rs | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/bot/music.rs | 35 ++++++++++++++++++++++++++++++++++- src/command.rs | 5 ++++- 3 files changed, 82 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/audio_player.rs b/src/audio_player.rs index 97ecfbf..9ed645d 100644 --- a/src/audio_player.rs +++ b/src/audio_player.rs @@ -1,4 +1,5 @@ use std::sync::Once; +use std::time::Duration; use gst::prelude::*; use gst::GhostPad; @@ -14,6 +15,13 @@ use tokio02::sync::mpsc::UnboundedSender; static GST_INIT: Once = Once::new(); +#[derive(Copy, Clone, Debug)] +pub enum Seek { + Positive(Duration), + Negative(Duration), + Absolute(Duration), +} + #[derive(PartialEq, Eq, Debug, Clone, Copy)] pub enum PollResult { Continue, @@ -219,6 +227,41 @@ impl AudioPlayer { Ok(()) } + pub fn seek(&self, seek: Seek) -> Result { + let base = match seek { + Seek::Positive(_) | Seek::Negative(_) => { + let pos = self + .pipeline + .query_position::() + .ok_or(AudioPlayerError::SeekError)?; + Duration::from_nanos(pos.nanoseconds().ok_or(AudioPlayerError::SeekError)?) + } + _ => Duration::new(0, 0), + }; + + let absolute = match seek { + Seek::Positive(duration) => base + duration, + Seek::Negative(duration) => { + if duration > base { + Duration::new(0, 0) + } else { + base - duration + } + } + Seek::Absolute(duration) => duration, + }; + + let time = humantime::format_duration(absolute); + info!("Seeking to {}", time); + + self.pipeline.seek_simple( + gst::SeekFlags::FLUSH, + gst::ClockTime::from_nseconds(absolute.as_nanos() as _), + )?; + + Ok(time) + } + pub fn stop_current(&self) -> Result<(), AudioPlayerError> { info!("Stopping pipeline, sending EOS"); @@ -334,6 +377,7 @@ impl AudioPlayer { pub enum AudioPlayerError { GStreamerError(glib::error::BoolError), StateChangeFailed, + SeekError, } impl From for AudioPlayerError { diff --git a/src/bot/music.rs b/src/bot/music.rs index 4de4d4b..75e61de 100644 --- a/src/bot/music.rs +++ b/src/bot/music.rs @@ -3,12 +3,13 @@ use std::io::BufRead; use std::sync::{Arc, Mutex}; use std::thread; +use humantime; use log::{debug, info}; use structopt::StructOpt; use tokio02::sync::mpsc::UnboundedSender; use tsclientlib::{data, ChannelId, ClientId, ConnectOptions, Identity, Invoker, MessageTarget}; -use crate::audio_player::{AudioPlayer, AudioPlayerError, PollResult}; +use crate::audio_player::{AudioPlayer, AudioPlayerError, PollResult, Seek}; use crate::command::Command; use crate::playlist::Playlist; use crate::teamspeak::TeamSpeakConnection; @@ -21,6 +22,27 @@ pub struct Message { pub text: String, } +fn parse_seek(mut amount: &str) -> Result { + let sign = match amount.chars().next() { + Some('+') => 1, + Some('-') => -1, + _ => 0, + }; + let is_relative = sign != 0; + + if is_relative { + amount = &amount[1..]; + } + + let duration = humantime::parse_duration(amount).map_err(|_| ())?; + + match sign { + 1 => Ok(Seek::Positive(duration)), + -1 => Ok(Seek::Negative(duration)), + _ => Ok(Seek::Absolute(duration)), + } +} + #[derive(Debug, PartialEq, Eq)] pub enum State { Playing, @@ -268,6 +290,17 @@ impl MusicBot { Command::Stop => { self.player.reset()?; } + Command::Seek { amount } => { + if let Ok(seek) = parse_seek(&amount) { + if let Ok(time) = self.player.seek(seek) { + self.send_message(&format!("New position: {}", time)); + } else { + self.send_message("Failed to seek"); + } + } else { + info!("Failed to parse seeking command"); + } + } Command::Next => { let playlist = self.playlist.lock().expect("Mutex was not poisoned"); if !playlist.is_empty() { diff --git a/src/command.rs b/src/command.rs index 3a39290..db22028 100644 --- a/src/command.rs +++ b/src/command.rs @@ -9,7 +9,8 @@ use structopt::StructOpt; DisableHelpFlags, DisableVersion, ColorNever, - NoBinaryName]",) + NoBinaryName, + AllowLeadingHyphen]",) )] pub enum Command { /// Adds url to playlist @@ -18,6 +19,8 @@ pub enum Command { Play, /// Pauses audio playback Pause, + /// Seeks by a specified amount + Seek { amount: String }, /// Stops audio playback Stop, /// Switches to the next queue entry -- cgit v1.2.3-70-g09d2