add a command to jump to an arbitrary time
authorKostya Shishkov <kostya.shishkov@gmail.com>
Fri, 16 Oct 2020 08:11:36 +0000 (10:11 +0200)
committerKostya Shishkov <kostya.shishkov@gmail.com>
Fri, 16 Oct 2020 08:11:36 +0000 (10:11 +0200)
sndplay/src/command.rs
sndplay/src/main.rs

index 802908b2de0e0ec818c8eed2e8bed4c9dfd662cd..3f5ecdeb3cdebbb48161c268da4eb2b1df4740a2 100644 (file)
@@ -1,7 +1,8 @@
 use libc::{termios, tcgetattr, tcsetattr};
 use std::sync::mpsc;
-use std::io::Read;
+use std::io::{Read, BufRead};
 use std::thread;
+use nihav_core::frame::NATimePoint;
 
 #[derive(Clone,Copy,Debug,PartialEq)]
 pub enum Command {
@@ -12,8 +13,11 @@ pub enum Command {
     Pause,
     Back(u8),
     Forward(u8),
+    Seek(u64),
     Repeat,
     Next,
+    PauseDisplay,
+    ResumeDisplay,
     Quit,
 }
 
@@ -29,6 +33,14 @@ impl CmdLineState {
         unsafe { tcsetattr(0, 0, &new_state); }
         Self { orig_state }
     }
+    pub fn new_normal() -> Self {
+        let mut orig_state: termios = unsafe { std::mem::uninitialized() };
+        unsafe { tcgetattr(0, &mut orig_state); }
+        let mut new_state = orig_state;
+        new_state.c_lflag |= libc::ECHO | libc::ICANON;
+        unsafe { tcsetattr(0, 0, &new_state); }
+        Self { orig_state }
+    }
     pub fn restore(&self) {
         unsafe { tcsetattr(0, 0, &self.orig_state); }
     }
@@ -60,6 +72,26 @@ pub fn start_reader() -> (thread::JoinHandle<()>, mpsc::Receiver<Command>) {
                         b'-' => { sender.send(Command::VolumeDown).unwrap(); },
                         b'd' | b'D' => { sender.send(Command::Debug).unwrap(); },
                         b'm' | b'M' => { sender.send(Command::Mute).unwrap(); },
+                        b'j' | b'J' => {
+                            sender.send(Command::PauseDisplay).unwrap();
+                            let cstate = CmdLineState::new_normal();
+                            // wait so that the main thread stops displaying
+                            thread::sleep(std::time::Duration::from_millis(500));
+                            print!("\nJump to: ");
+                            let mut str = String::new();
+                            let ret = file.read_line(&mut str);
+                            cstate.restore();
+                            sender.send(Command::ResumeDisplay).unwrap();
+
+                            if ret.is_ok() && str.len() > 1 {
+                                str.pop(); // newline
+                                if let Ok(NATimePoint::Milliseconds(time)) = str.parse::<NATimePoint>() {
+                                    sender.send(Command::Seek(time)).unwrap();
+                                } else {
+                                    println!("wrong time");
+                                }
+                            }
+                        },
                         _ => {},
                     };
                 },
@@ -98,4 +130,4 @@ pub fn start_reader() -> (thread::JoinHandle<()>, mpsc::Receiver<Command>) {
             }
         }
     }), cmd_receiver)
-}
\ No newline at end of file
+}
index 66def2b05250b0fe3f3fe5a32aa330e12c3fafec..377c2d1b11bb7b134f3a1b9e1bd5ad287a61d175 100644 (file)
@@ -335,15 +335,18 @@ impl Player {
         if !self.paused {
             device.resume();
         }
+        let mut no_display = false;
         'main: loop {
             let cur_time = decoder.samplepos.saturating_sub(u64::from(device.size() / 2 / u32::from(dst_info.channels)));
             let full_ms = cur_time * 1000 / u64::from(arate);
             let timestr = format_time(full_ms);
             let disp_vol = if self.mute { 0 } else { self.volume };
-            if !self.debug {
-                print!("> {} / {}   {}%       \r", timestr, duration_str, disp_vol);
-            } else {
-                print!("> {} / {}   |{}| {}%       \r", timestr, duration_str, device.size(), disp_vol);
+            if !no_display {
+                if !self.debug {
+                    print!("> {} / {}   {}%       \r", timestr, duration_str, disp_vol);
+                } else {
+                    print!("> {} / {}   |{}| {}%       \r", timestr, duration_str, device.size(), disp_vol);
+                }
             }
             std::io::stdout().flush().unwrap();
             if device.size() < underfill_limit && !self.paused && refill_limit < (1 << 20) {
@@ -403,6 +406,20 @@ impl Player {
                             device.resume();
                         }
                     },
+                    Command::Seek(seek_time) => {
+                        device.pause();
+                        device.clear();
+                        let _ret = decoder.seek(seek_time);
+                        while !eof && device.size() < refill_limit {
+                            eof = decoder.refill(&device);
+                        }
+                        if eof {
+                            break 'main;
+                        }
+                        if !self.paused {
+                            device.resume();
+                        }
+                    },
                     Command::Quit => {
                         device.pause();
                         self.ended = true;
@@ -449,8 +466,12 @@ impl Player {
                     Command::Debug => {
                         self.debug = !self.debug;
                     },
+                    Command::PauseDisplay  => { no_display = true; },
+                    Command::ResumeDisplay => { no_display = false; },
                 };
-                print!("\r{:60}\r", ' ');
+                if !no_display {
+                    print!("\r{:60}\r", ' ');
+                }
             }
             thread::sleep(Duration::from_millis(200));
         }