Browse Source

merge ColmOnline changes

fossedihelm 7 years ago
parent
commit
94e4cd853a
3 changed files with 102 additions and 40 deletions
  1. 33 9
      README.md
  2. 32 21
      src/audio_backend/pulseaudio.rs
  3. 37 10
      src/spirc.rs

+ 33 - 9
README.md

@@ -1,16 +1,22 @@
+[![Build Status](https://travis-ci.org/ComlOnline/librespot.svg?branch=master)](https://travis-ci.org/ComlOnline/librespot)
+
 # librespot
 *librespot* is an open source client library for Spotify. It enables
 applications to use Spotify's service, without using the official but
 closed-source libspotify. Additionally, it will provide extra features
 which are not available in the official library.
 
-Note: librespot only works with Spotify Premium.
+Note: librespot needs to be logged in and only works with Spotify Premium
+
+# THIS FORK
+As the origin is no longer maintained I wanted to have a place for a version of librespot with other peoples forks and features merged.
+
 
-# Unmaintained
-Unfortunately I am unable to maintain librespot anymore. It should still work,
-but issues and Pull requests will be ignored. Feel free to fork it and continue
-development there. If a fork gains traction I will happily point to it from the
-README.
+# THANKS
+I've done noting more than make this pretty so big thanks to:  
+[plietar](https://github.com/plietar/) for making the thing in the first place.  
+[kingosticks](https://github.com/kingosticks/) For the Suffling and Repeat.  
+[ipha](https://github.com/ipha/) For the start stop audio sink.  
 
 ## Building
 Rust 1.17.0 or later is required to build librespot.
@@ -46,9 +52,27 @@ Once you've built *librespot*, run it using :
 target/release/librespot --username USERNAME --cache CACHEDIR --name DEVICENAME [--initial-volume 20]
 ```
 
-## Discovery mode
-*librespot* can be run in discovery mode, in which case no password is required at startup.
-For that, simply omit the `--username` argument.
+### All options
+
+| Type     | Short | Long                | Description                                     | Hint        |
+|----------|-------|---------------------|-------------------------------------------------|-------------|
+| Option   | c     | cache               | Path to a directory where files will be cached. | CACHE       |
+| Flag     |       | disable-audio-cache | Disable caching of the audio data.              |             |
+| Required | n     | name                | Device name                                     | NAME        |
+| Option   |       | device-type         | Displayed device type                           | DEVICE_TYPE |
+| Option   | b     | bitrate             | Bitrate (96, 160 or 320). Defaults to 160       | BITRATE     |
+| Option   |       | onstart             | Run PROGRAM when playback is about to begin.    |             |
+| Option   |       | onstop              | Run PROGRAM when playback has ended.            | PROGRAM     |
+| Flag     | v     | verbose             | Enable verbose output                           | PROGRAM     |
+| Option   | u     | username            | Username to sign in with                        | USERNAME    |
+| Option   | p     | password            | Password                                        | PASSWORD    |
+| Flag     |       | disable-discovery   | Disable discovery mode                          |             |
+| Option   |       | backend             | Audio backend to use. Use '?' to list options   | BACKEND     |
+| Option   |       | device              | Audio device to use. Use '?' to list options    | DEVICE      |
+| Option   |       | mixer               | Mixer to use                                    | MIXER       |
+
+Taken from here:
+https://github.com/ComlOnline/librespot/blob/master/src/main.rs#L88
 
 ## Audio Backends
 *librespot* supports various audio backends. Multiple backends can be enabled at compile time by enabling the

+ 32 - 21
src/audio_backend/pulseaudio.rs

@@ -5,7 +5,12 @@ use std::ptr::{null, null_mut};
 use std::mem::{transmute};
 use std::ffi::CString;
 
-pub struct PulseAudioSink(*mut pa_simple);
+pub struct PulseAudioSink {
+    s    : *mut pa_simple,
+    ss   : pa_sample_spec,
+    name : CString,
+    desc : CString
+}
 
 impl Open for PulseAudioSink {
    fn open(device: Option<String>) -> PulseAudioSink {
@@ -24,30 +29,40 @@ impl Open for PulseAudioSink {
         let name = CString::new("librespot").unwrap();
         let description = CString::new("A spoty client library").unwrap();
 
-        let s = unsafe {
-            pa_simple_new(null(),               // Use the default server.
-                          name.as_ptr(),        // Our application's name.
-                          PA_STREAM_PLAYBACK,
-                          null(),               // Use the default device.
-                          description.as_ptr(), // Description of our stream.
-                          &ss,                  // Our sample format.
-                          null(),               // Use default channel map
-                          null(),               // Use default buffering attributes.
-                          null_mut(),           // Ignore error code.
-            )
-        };
-        assert!(s != null_mut());
-        
-        PulseAudioSink(s)
+        PulseAudioSink {
+            s: null_mut(),
+            ss: ss,
+            name: name,
+            desc: description
+        }
     }
 }
 
 impl Sink for PulseAudioSink {
     fn start(&mut self) -> io::Result<()> {
+        if self.s == null_mut() {
+            self.s = unsafe {
+                pa_simple_new(null(),               // Use the default server.
+                              self.name.as_ptr(),   // Our application's name.
+                              PA_STREAM_PLAYBACK,
+                              null(),               // Use the default device.
+                              self.desc.as_ptr(),   // desc of our stream.
+                              &self.ss,             // Our sample format.
+                              null(),               // Use default channel map
+                              null(),               // Use default buffering attributes.
+                              null_mut(),           // Ignore error code.
+                )
+            };
+            assert!(self.s != null_mut());
+        }
         Ok(())
     }
 
     fn stop(&mut self) -> io::Result<()> {
+        unsafe {
+            pa_simple_free(self.s);
+        }
+        self.s = null_mut();
         Ok(())
     }
 
@@ -55,13 +70,9 @@ impl Sink for PulseAudioSink {
         unsafe {
             let ptr = transmute(data.as_ptr());
             let bytes = data.len() as usize * 2;
-            pa_simple_write(self.0, ptr, bytes, null_mut());
+            pa_simple_write(self.s, ptr, bytes, null_mut());
         };
         
         Ok(())
     }
 }
-
-
-
-

+ 37 - 10
src/spirc.rs

@@ -17,6 +17,9 @@ use protocol::spirc::{PlayStatus, State, MessageType, Frame, DeviceState};
 use mixer::Mixer;
 use player::Player;
 
+use rand;
+use rand::Rng;
+
 pub struct SpircTask {
     player: Player,
     mixer: Box<Mixer>,
@@ -396,6 +399,31 @@ impl SpircTask {
                 self.notify(None);
             }
 
+            MessageType::kMessageTypeRepeat => {
+                self.state.set_repeat(frame.get_state().get_repeat());
+                self.notify(None);
+            }
+
+            MessageType::kMessageTypeShuffle => {
+                self.state.set_shuffle(frame.get_state().get_shuffle());
+                if self.state.get_shuffle()
+                {
+                    let current_index = self.state.get_playing_track_index();
+                    {
+                        let tracks = self.state.mut_track();
+                        tracks.swap(0, current_index as usize);
+                        if let Some((_, rest)) = tracks.split_first_mut() {
+                            rand::thread_rng().shuffle(rest);
+                        }
+                    }
+                    self.state.set_playing_track_index(0);
+                } else {
+                    let context = self.state.get_context_uri();
+                    debug!("{:?}", context);
+                }
+                self.notify(None);
+            }
+
             MessageType::kMessageTypeSeek => {
                 let position = frame.get_position();
 
@@ -467,13 +495,19 @@ impl SpircTask {
 
     fn handle_next(&mut self) {
         let current_index = self.state.get_playing_track_index();
-        let new_index = (current_index + 1) % (self.state.get_track().len() as u32);
+        let num_tracks = self.state.get_track().len() as u32;
+        let new_index = (current_index + 1) % num_tracks;
+
+        let mut was_last_track = (current_index + 1) >= num_tracks;
+        if self.state.get_repeat() {
+            was_last_track = false;
+        }
 
         self.state.set_playing_track_index(new_index);
         self.state.set_position_ms(0);
         self.state.set_position_measured_at(now_ms() as u64);
 
-        self.load_track(true);
+        self.load_track(!was_last_track);
     }
 
     fn handle_prev(&mut self) {
@@ -520,14 +554,7 @@ impl SpircTask {
     }
 
     fn handle_end_of_track(&mut self) {
-        let current_index = self.state.get_playing_track_index();
-        let new_index = (current_index + 1) % (self.state.get_track().len() as u32);
-
-        self.state.set_playing_track_index(new_index);
-        self.state.set_position_ms(0);
-        self.state.set_position_measured_at(now_ms() as u64);
-
-        self.load_track(true);
+        self.handle_next();   
         self.notify(None);
     }