aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJokler <jokler@protonmail.com>2020-02-21 22:47:26 +0100
committerGitHub <noreply@github.com>2020-02-21 22:47:26 +0100
commit00b60b8f210b93a5d6cbdde2bc98feff2f2ec1ca (patch)
treefc2102295e2b3f0fd5db6f4d2ed811a6a0e87ffd
parent8e708b65365aeb0591aee39d2ffb7c59239ffc3f (diff)
parentd9bfc97b599af4e4e96ae403df8287a533223e32 (diff)
downloadpokebot-00b60b8f210b93a5d6cbdde2bc98feff2f2ec1ca.tar.gz
pokebot-00b60b8f210b93a5d6cbdde2bc98feff2f2ec1ca.zip
Merge pull request #34 from Mavulp/branches/fkaa/Seeking
Add seeking to audio player
-rw-r--r--Cargo.lock9
-rw-r--r--Cargo.toml1
-rw-r--r--src/audio_player.rs44
-rw-r--r--src/bot/music.rs35
-rw-r--r--src/command.rs5
5 files changed, 91 insertions, 3 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 8d57a14..fe0ea26 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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",
diff --git a/Cargo.toml b/Cargo.toml
index 34726ff..7f7aeb5 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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