diff options
| author | Jokler <jokler@protonmail.com> | 2020-02-21 22:47:26 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-02-21 22:47:26 +0100 |
| commit | 00b60b8f210b93a5d6cbdde2bc98feff2f2ec1ca (patch) | |
| tree | fc2102295e2b3f0fd5db6f4d2ed811a6a0e87ffd | |
| parent | 8e708b65365aeb0591aee39d2ffb7c59239ffc3f (diff) | |
| parent | d9bfc97b599af4e4e96ae403df8287a533223e32 (diff) | |
| download | pokebot-00b60b8f210b93a5d6cbdde2bc98feff2f2ec1ca.tar.gz pokebot-00b60b8f210b93a5d6cbdde2bc98feff2f2ec1ca.zip | |
Merge pull request #34 from Mavulp/branches/fkaa/Seeking
Add seeking to audio player
| -rw-r--r-- | Cargo.lock | 9 | ||||
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | src/audio_player.rs | 44 | ||||
| -rw-r--r-- | src/bot/music.rs | 35 | ||||
| -rw-r--r-- | src/command.rs | 5 |
5 files changed, 91 insertions, 3 deletions
@@ -1142,6 +1142,12 @@ dependencies = [ ] [[package]] +name = "humantime" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9b6c53306532d3c8e8087b44e6580e10db51a023cf9b433cea2ac38066b92da" + +[[package]] name = "hyper" version = "0.12.35" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1334,7 +1340,7 @@ dependencies = [ "chrono", "flate2", "fnv", - "humantime", + "humantime 1.3.0", "libc", "log", "log-mdc", @@ -1784,6 +1790,7 @@ dependencies = [ "gstreamer", "gstreamer-app", "gstreamer-audio", + "humantime 2.0.0", "log", "log4rs", "rand 0.7.3", @@ -14,6 +14,7 @@ log = "0.4.8" log4rs = "0.9" toml = "0.5.5" structopt = "0.2" +humantime = "2.0" tokio = "0.1" tokio-process = "0.2.4" 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<humantime::FormattedDuration, AudioPlayerError> { + let base = match seek { + Seek::Positive(_) | Seek::Negative(_) => { + let pos = self + .pipeline + .query_position::<gst::ClockTime>() + .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<glib::error::BoolError> 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<Seek, ()> { + 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 |
