Class: Hallon::Player
- Extended by:
- Observable::Player
- Defined in:
- lib/hallon/player.rb
Overview
A wrapper around Session for playing, stopping and otherwise controlling the playback features of libspotify.
Instance Attribute Summary collapse
-
#pointer ⇒ Spotify::Session
readonly
Session pointer.
-
#status ⇒ Symbol
One of :playing, :paused, :stopped.
Class Method Summary collapse
-
.bitrates ⇒ Array<Symbol>
A list of available playback bitrates.
Instance Method Summary collapse
-
#bitrate=(bitrate) ⇒ Object
Set preferred playback bitrate.
-
#get_audio_buffer_stats ⇒ Object
protected
Called by libspotify to request information about our audio buffer.
-
#initialize(driver) { ... } ⇒ Player
constructor
Constructs a Player, given an audio driver.
-
#load(track) ⇒ Player
Loads a Track for playing.
-
#music_delivery(format, frames) ⇒ Object
protected
Called by libspotify on music delivery; format is a hash of (sample) rate, channels and (sample) type.
-
#pause ⇒ Object
Pause playback of a Track.
-
#play(track = nil) ⇒ Player
Start playing the currently loaded, or given, Track.
-
#play!(track = nil) ⇒ Player
Like #play, but blocks until the track has finished playing.
-
#prefetch(track) ⇒ Player
Prepares a Track for playing, without #loading it.
-
#seek(seconds) ⇒ Player
Seek to the desired position of the currently loaded Track.
-
#start_playback ⇒ Object
protected
Called by libspotify when the driver should start audio playback.
-
#stop ⇒ Object
Stop playing current track and unload it.
-
#stop_playback ⇒ Object
protected
Called by libspotify when the driver should pause audio playback.
- #to_s ⇒ String
- #volume_normalization=(normalize_volume) ⇒ Object
-
#volume_normalization? ⇒ Boolean
True if libspotify is set to normalize audio volume.
Methods included from Observable::Player
end_of_track_callback, extended, initialize_callbacks, play_token_lost_callback, streaming_error_callback
Methods inherited from Base
#==, from, from_link, #is_linkable?, #session, to_link, #to_pointer
Constructor Details
#initialize(driver) { ... } ⇒ Player
for instructions on how to write your own audio driver, see Hallons’ README
Constructs a Player, given an audio driver.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/hallon/player.rb', line 36 def initialize(driver, &block) @session = Hallon::Session.instance @pointer = @session.pointer # sample rate is often (if not always) 44.1KHz, so # we keep an audio queue that can store 3s of audio @queue = AudioQueue.new(44100) @driver = driver.new @driver.format = { rate: 44100, channels: 2, type: :int16 } # used for feeder thread to know if it should stream # data to the driver or not (see #status=) @status_c = @queue.new_cond # set initial status (we assume stopped) self.status = :stopped # this thread feeds the audio driver with data, but # if we are not playing it’ll wait until we are @thread = Thread.start(@driver, @queue, @status_c) do |output, queue, cond| output.stream do |num_frames| queue.synchronize do frames = queue.pop(output.format, *num_frames) if frames.nil? # if we received no frames, it means the audio format changed output.format = queue.format end # frames is either nil, or an array of audio frames frames end end end @session.on(:start_playback, &method(:start_playback)) @session.on(:stop_playback, &method(:stop_playback)) @session.on(:music_delivery, &method(:music_delivery)) @session.on(:get_audio_buffer_stats, &method(:get_audio_buffer_stats)) @session.on(:end_of_track) { |*args| trigger(:end_of_track, *args) } @session.on(:streaming_error) { |*args| trigger(:streaming_error, *args) } @session.on(:play_token_lost) { |*args| trigger(:play_token_lost, *args) } instance_eval(&block) if block_given? end |
Instance Attribute Details
#pointer ⇒ Spotify::Session (readonly)
Returns session pointer.
14 15 16 |
# File 'lib/hallon/player.rb', line 14 def pointer @pointer end |
#status ⇒ Symbol
Returns one of :playing, :paused, :stopped.
17 18 19 |
# File 'lib/hallon/player.rb', line 17 def status @status end |
Class Method Details
.bitrates ⇒ Array<Symbol>
Returns a list of available playback bitrates.
20 21 22 23 24 25 |
# File 'lib/hallon/player.rb', line 20 def self.bitrates Spotify.enum_type(:bitrate).symbols.sort_by do |sym| # sort by bitrate quality sym.to_s.to_i end end |
Instance Method Details
#bitrate=(bitrate) ⇒ Object
the double possible errors is a result of the same thing as for Session#offline_bitrate=, see its documentation for further information.
Set preferred playback bitrate.
210 211 212 |
# File 'lib/hallon/player.rb', line 210 def bitrate=(bitrate) Spotify.try(:session_preferred_bitrate, pointer, bitrate) end |
#get_audio_buffer_stats ⇒ Object (protected)
Called by libspotify to request information about our audio buffer. Required if we want libspotify to tell us when we should start and stop playback.
111 112 113 114 |
# File 'lib/hallon/player.rb', line 111 def get_audio_buffer_stats drops = @driver.drops if @driver.respond_to?(:drops) [@queue.size, drops.to_i] end |
#load(track) ⇒ Player
Loads a Track for playing.
219 220 221 222 223 |
# File 'lib/hallon/player.rb', line 219 def load(track) track = Track.new(track) unless track.is_a?(Track) error = Spotify.session_player_load(pointer, track.pointer) tap { Error.maybe_raise(error) } end |
#music_delivery(format, frames) ⇒ Object (protected)
Called by libspotify on music delivery; format is a hash of (sample) rate, channels and (sample) type.
101 102 103 104 105 106 |
# File 'lib/hallon/player.rb', line 101 def music_delivery(format, frames) @queue.synchronize do @queue.clear if frames.none? @queue.push(format, frames) end end |
#pause ⇒ Object
Pause playback of a Track.
176 177 178 179 |
# File 'lib/hallon/player.rb', line 176 def pause self.status = :paused Spotify.session_player_play(pointer, false) end |
#play(track = nil) ⇒ Player
If no track is given, will try to play currently #loaded track.
Start playing the currently loaded, or given, Track.
168 169 170 171 |
# File 'lib/hallon/player.rb', line 168 def play(track = nil) load(track) unless track.nil? tap { Spotify.session_player_play(pointer, true) } end |
#play!(track = nil) ⇒ Player
Like #play, but blocks until the track has finished playing.
193 194 195 196 197 198 199 200 |
# File 'lib/hallon/player.rb', line 193 def play!(track = nil) end_of_track = false old_callback = on(:end_of_track) { end_of_track = true } play(track) wait_for(:end_of_track) { end_of_track } ensure on(:end_of_track, &old_callback) end |
#prefetch(track) ⇒ Player
You can only prefetch if caching is on.
Prepares a Track for playing, without #loading it.
230 231 232 233 |
# File 'lib/hallon/player.rb', line 230 def prefetch(track) error = Spotify.session_player_prefetch(pointer, track.pointer) tap { Error.maybe_raise(error) } end |
#seek(seconds) ⇒ Player
Seek to the desired position of the currently loaded Track.
239 240 241 |
# File 'lib/hallon/player.rb', line 239 def seek(seconds) tap { Spotify.session_player_seek(pointer, seconds * 1000) } end |
#start_playback ⇒ Object (protected)
Called by libspotify when the driver should start audio playback.
Will be called after calling our buffers are full enough to support continous playback.
88 89 90 |
# File 'lib/hallon/player.rb', line 88 def start_playback self.status = :playing end |
#stop ⇒ Object
Stop playing current track and unload it.
184 185 186 187 |
# File 'lib/hallon/player.rb', line 184 def stop self.status = :stopped Spotify.session_player_unload(pointer) end |
#stop_playback ⇒ Object (protected)
Called by libspotify when the driver should pause audio playback.
Might happen if we’re playing audio faster than we can stream it.
95 96 97 |
# File 'lib/hallon/player.rb', line 95 def stop_playback self.status = :paused end |
#to_s ⇒ String
default output also shows all our instance variables, that is kind of unnecessary and might take some time to display, for example if the audio queue is full
154 155 156 157 158 |
# File 'lib/hallon/player.rb', line 154 def to_s name = self.class.name address = pointer.address.to_s(16) "<#{name} session=0x#{address} driver=#{@driver.class} status=#{status}>" end |
#volume_normalization=(normalize_volume) ⇒ Object
249 250 251 |
# File 'lib/hallon/player.rb', line 249 def volume_normalization=(normalize_volume) Spotify.session_set_volume_normalization(pointer, !! normalize_volume) end |
#volume_normalization? ⇒ Boolean
Returns true if libspotify is set to normalize audio volume.
244 245 246 |
# File 'lib/hallon/player.rb', line 244 def volume_normalization? Spotify.session_get_volume_normalization(pointer) end |