class Airplay::Player
Public: The class that handles all the video playback
Constants
- PlaybackInfo
Attributes
Public Class Methods
# File lib/airplay/player.rb, line 25 def initialize(device) @device = device end
Public Instance Methods
Public: Cleans up the player
Returns nothing
# File lib/airplay/player.rb, line 200 def cleanup timers.cancel persistent.close end
Public: checks current playback information
Returns a PlaybackInfo
object with the playback information
# File lib/airplay/player.rb, line 142 def info response = connection.get("/playback-info").response plist = CFPropertyList::List.new(data: response.body) hash = CFPropertyList.native_types(plist.value) PlaybackInfo.new(hash) end
# File lib/airplay/player.rb, line 181 def loading?; state == :loading end
Public: Plays the next video in the playlist
Returns the video that was selected or nil if none
# File lib/airplay/player.rb, line 111 def next video = playlist.next play(video) if video video end
Public: Pauses a playing video
Returns nothing
# File lib/airplay/player.rb, line 161 def pause connection.async.post("/rate?value=0") end
# File lib/airplay/player.rb, line 183 def paused?; state == :paused end
Public: Plays a given url or file.
Creates a new persistent connection to ensure that the socket will be kept alive
file_or_url - The url or file to be reproduced options - Optional starting time
Returns nothing
# File lib/airplay/player.rb, line 69 def play(media_to_play = "playlist", options = {}) start_the_machine check_for_playback_status media = case true when media_to_play.is_a?(Media) then media_to_play when media_to_play == "playlist" && playlist.any? playlist.next else Media.new(media_to_play) end content = { "Content-Location" => media, "Start-Position" => options.fetch(:time, 0.0) } data = content.map { |k, v| "#{k}: #{v}" }.join("\r\n") response = persistent.async.post("/play", data + "\r\n", { "Content-Type" => "text/parameters" }) timers.reset end
# File lib/airplay/player.rb, line 184 def played?; state == :played end
# File lib/airplay/player.rb, line 182 def playing?; state == :playing end
Public: Gets the current playlist
Returns the first Playlist
if none defined or creates a new one
# File lib/airplay/player.rb, line 41 def playlist @_playlist ||= if playlists.any? key, value = playlists.first value else Playlist.new("Default") end end
Public: Gets all the playlists
Returns the Playlists
# File lib/airplay/player.rb, line 33 def playlists @_playlists ||= Hash.new { |h,k| h[k] = Playlist.new(k) } end
Public: Plays the previous video in the playlist
Returns the video that was selected or nil if none
# File lib/airplay/player.rb, line 121 def previous video = playlist.previous play(video) if video video end
Public: Handles the progress of the playback, the given &block get’s
executed every second while the video is played.
&block - Block to be executed in every playable second.
Returns nothing
# File lib/airplay/player.rb, line 101 def progress(callback) timers << every(1) do callback.call(info) if playing? end end
Public: Resumes a paused video
Returns nothing
# File lib/airplay/player.rb, line 153 def resume connection.async.post("/rate?value=1") end
Public: Shows the current playback time if a video is being played.
Returns a hash with the :duration and current :position
# File lib/airplay/player.rb, line 131 def scrub return unless playing? response = connection.get("/scrub").response parts = response.body.split("\n") Hash[parts.collect { |v| v.split(": ") }] end
Public: Seeks to the specified position (seconds) in the video
Returns nothing
# File lib/airplay/player.rb, line 177 def seek(position) connection.async.post("/scrub?position=#{position}") end
Public: Stops the video
Returns nothing
# File lib/airplay/player.rb, line 169 def stop connection.post("/stop") end
# File lib/airplay/player.rb, line 185 def stopped?; state == :stopped end
Public: Sets a given playlist
name - The name of the playlist to be used
Returns nothing
# File lib/airplay/player.rb, line 56 def use(name) @_playlist = playlists[name] end
Public: Locks the execution until the video gets fully played
Returns nothing
# File lib/airplay/player.rb, line 191 def wait sleep 1 while wait_for_playback? cleanup end
Private Instance Methods
Private: Starts checking for playback status ever 1 second
Adds one timer to the pool
Returns nothing
# File lib/airplay/player.rb, line 245 def check_for_playback_status timers << every(1) do case true when info.stopped? && playing? then @machine.trigger(:stopped) when info.played? && playing? then @machine.trigger(:played) when info.playing? && !playing? then @machine.trigger(:playing) when info.paused? && playing? then @machine.trigger(:paused) end end end
Private: The connection
Returns the current connection to the device
# File lib/airplay/player.rb, line 228 def connection @_connection ||= Airplay::Connection.new(@device) end
Private: The persistent connection
Returns the persistent connection to the device
# File lib/airplay/player.rb, line 236 def persistent @_persistent ||= Airplay::Connection.new(@device, keep_alive: true) end
Private: Get ready the state machine
Returns nothing
# File lib/airplay/player.rb, line 260 def start_the_machine @machine = MicroMachine.new(:loading) @machine.on(:stopped) { cleanup } @machine.on(:played) do cleanup self.next if playlist.next? end @machine.when(:loading, :stopped => :loading) @machine.when(:playing, { :paused => :playing, :loading => :playing, :stopped => :playing }) @machine.when(:paused, :loading => :paused, :playing => :paused) @machine.when(:stopped, :playing => :stopped, :paused => :stopped) @machine.when(:played, :playing => :played, :paused => :played) end
Private: The timers
Returns a Timers
object
# File lib/airplay/player.rb, line 220 def timers @_timers ||= Timers.new end
Private: Returns if we have to wait for playback
Returns a boolean if we need to wait
# File lib/airplay/player.rb, line 211 def wait_for_playback? return true if playlist.next? loading? || playing? || paused? end