Class: Plllayer::SinglePlayers::MPlayer

Inherits:
Plllayer::SinglePlayer show all
Defined in:
lib/plllayer/single_players/mplayer.rb

Overview

This is the SinglePlayer implementation for mplayer. It requires mplayer to be in your $PATH. It uses open4 to start up and communicate with the mplayer process, and mplayer’s slave protocol to issue commands to mplayer.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeMPlayer

Create a new MPlayer. The mplayer process is only started when the #play method is called to start playing a song. The process quits when the song ends. Even though a new process is started for each song, the MPlayer object keeps track of the volume, speed, and mute properties and sets these properties when a new song is played.



14
15
16
17
18
19
20
# File 'lib/plllayer/single_players/mplayer.rb', line 14

def initialize
  @paused = false
  @muted = false
  @volume = 50
  @speed = 1.0
  @track_path = nil
end

Instance Attribute Details

#track_pathObject (readonly)

Returns the value of attribute track_path.



7
8
9
# File 'lib/plllayer/single_players/mplayer.rb', line 7

def track_path
  @track_path
end

Instance Method Details

#log_start!Object



161
162
163
# File 'lib/plllayer/single_players/mplayer.rb', line 161

def log_start!
  @log = true
end

#log_stop!Object



165
166
167
# File 'lib/plllayer/single_players/mplayer.rb', line 165

def log_stop!
  @log = false
end

#muteObject



128
129
130
131
132
# File 'lib/plllayer/single_players/mplayer.rb', line 128

def mute
  @muted = true
  answer = _command "mute 1", expect_answer: true
  !!answer
end

#muted?Boolean

Returns:

  • (Boolean)


124
125
126
# File 'lib/plllayer/single_players/mplayer.rb', line 124

def muted?
  @muted
end

#pauseObject



81
82
83
84
85
86
87
88
# File 'lib/plllayer/single_players/mplayer.rb', line 81

def pause
  if not @paused
    @paused = true
    _command "pause"
  else
    false
  end
end

#paused?Boolean

Returns:

  • (Boolean)


77
78
79
# File 'lib/plllayer/single_players/mplayer.rb', line 77

def paused?
  @paused
end

#play(track_path, &on_end) ⇒ Object

Raises:



26
27
28
29
30
31
32
33
34
35
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
# File 'lib/plllayer/single_players/mplayer.rb', line 26

def play(track_path, &on_end)
  # Make sure we're only playing one song at any one time.
  _quit

  # Make sure the audio file exists.
  raise FileNotFoundError, "file '#{track_path}' doesn't exist" unless File.exists? track_path

  # Run the mplayer process in slave mode, passing it the location of
  # the track's audio file.
  cmd = ["mplayer", "-slave", "-quiet", track_path]
  @pid, @stdin, @stdout, @stderr = Open4.popen4(*cmd)

  # This should skip past mplayer's initial lines of output so we can
  # start reading its replies to our commands.
  begin
    line = @stdout.gets
    raise InvalidAudioFileError, "file '#{track_path}' isn't a valid audio file" if line.nil?
  end until line.chomp == "Starting playback..."

  @paused = false
  @track_path = track_path

  # Persist the previous speed, volume, and mute properties into this
  # process.
  self.speed = @speed
  muted = @muted
  self.volume = @volume
  @muted = muted
  mute if @muted

  # Start a thread that waits for the mplayer process to end, then calls
  # the end of song callback. If the #quit method is called, this thread
  # will be killed if it's still waiting for the process to end.
  @quit_hook_active = false
  @quit_hook = Thread.new do
    Process.wait(@pid)
    @quit_hook_active = true
    @paused = false
    @track_path = nil
    on_end.call
  end

  at_exit { stop }

  true
end

#playing?Boolean

Returns:

  • (Boolean)


22
23
24
# File 'lib/plllayer/single_players/mplayer.rb', line 22

def playing?
  not @track_path.nil?
end

#positionObject



151
152
153
154
# File 'lib/plllayer/single_players/mplayer.rb', line 151

def position
  answer = _command "get_time_pos", expect_answer: /^ANS_TIME_POSITION=([0-9.]+)$/
  answer ? (answer.to_f * 1000).to_i : false
end

#resumeObject



90
91
92
93
94
95
96
97
# File 'lib/plllayer/single_players/mplayer.rb', line 90

def resume
  if @paused
    @paused = false
    _command "pause"
  else
    false
  end
end

#seek(where, type = :absolute) ⇒ Object



99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/plllayer/single_players/mplayer.rb', line 99

def seek(where, type = :absolute)
  # mplayer talks seconds, not milliseconds.
  seconds = where.to_f / 1_000
  case type
  when :absolute
    _command "seek #{seconds} 2", expect_answer: true
  when :relative
    _command "seek #{seconds} 0", expect_answer: true
  when :percent
    _command "seek #{where} 1", expect_answer: true
  else
    raise NotImplementedError
  end
end

#speedObject



114
115
116
# File 'lib/plllayer/single_players/mplayer.rb', line 114

def speed
  @speed
end

#speed=(new_speed) ⇒ Object



118
119
120
121
122
# File 'lib/plllayer/single_players/mplayer.rb', line 118

def speed=(new_speed)
  @speed = new_speed.to_f
  answer = _command "speed_set #{@speed}", expect_answer: true
  !!answer
end

#stopObject



73
74
75
# File 'lib/plllayer/single_players/mplayer.rb', line 73

def stop
  _quit
end

#track_lengthObject



156
157
158
159
# File 'lib/plllayer/single_players/mplayer.rb', line 156

def track_length
  answer = _command "get_time_length", expect_answer: /^ANS_LENGTH=([0-9.]+)$/
  answer ? (answer.to_f * 1000).to_i : false
end

#unmuteObject



134
135
136
137
138
# File 'lib/plllayer/single_players/mplayer.rb', line 134

def unmute
  @muted = false
  answer = _command "mute 0", expect_answer: true
  !!answer
end

#volumeObject



140
141
142
# File 'lib/plllayer/single_players/mplayer.rb', line 140

def volume
  @volume
end

#volume=(new_volume) ⇒ Object



144
145
146
147
148
149
# File 'lib/plllayer/single_players/mplayer.rb', line 144

def volume=(new_volume)
  @muted = false
  @volume = new_volume.to_f
  answer = _command "volume #{@volume} 1", expect_answer: true
  !!answer
end