Class: MPV::Handle

Inherits:
Base
  • Object
show all
Defined in:
lib/mpvlib/handle.rb

Overview

typedef enum mpv_sub_api void *mpv_get_sub_api(mpv_handle *ctx, mpv_sub_api sub_api);

Constant Summary collapse

MPVLogMessageLevels =
{
  'none'  => Logger::UNKNOWN,
  'fatal' => Logger::FATAL,
  'error' => Logger::ERROR,
  'warn'  => Logger::WARN,
  'info'  => Logger::INFO,
  'v'     => Logger::DEBUG,
  'debug' => Logger::DEBUG,
  'trace' => Logger::DEBUG,
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Base

#define_finalizer, finalize

Constructor Details

#initialize(playlist_file: nil, audio_device: nil, mpv_log_level: nil, equalizer: nil, delegate:, **params) ⇒ Handle

Returns a new instance of Handle.

Raises:

  • (StandardError)


70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/mpvlib/handle.rb', line 70

def initialize(
  playlist_file: nil,
  audio_device: nil,
  mpv_log_level: nil,
  equalizer: nil,
  delegate:,
  **params
)
  @playlist_file = Path.new(playlist_file || '/tmp/playlist.txt')
  @audio_device = audio_device
  @mpv_log_level = mpv_log_level || 'error'
  @equalizer = equalizer
  @delegate = delegate
  @property_observers = {}
  @event_observers = {}
  @reply_id = 1
  @mpv_handle = MPV.mpv_create
  MPV::Error.raise_on_failure("initialize") {
    MPV.mpv_initialize(@mpv_handle)
  }
  define_finalizer(:mpv_terminate_destroy, @mpv_handle)
  fd = MPV.mpv_get_wakeup_pipe(@mpv_handle)
  raise StandardError, "Couldn't get wakeup pipe from MPV" if fd < 0
  @wakeup_pipe = IO.new(fd)
  register_event('log-message') { |e| handle_log_message(e) }
  request_log_messages(@mpv_log_level)
  set_option('audio-device', @audio_device) if @audio_device
  command('af', 'add', "equalizer=#{@equalizer.join(':')}") if @equalizer
  set_option('audio-display', 'no')
  set_option('vo', 'null')
  set_property('volume', '100')
  observe_property('playlist') { |e| @delegate.playlist_changed(e) }
  observe_property('pause') { |e| @delegate.pause_changed(e) }
  register_event('playback-restart') { |e| @delegate.playback_restart(e) }
end

Instance Attribute Details

#audio_deviceObject

Returns the value of attribute audio_device.



64
65
66
# File 'lib/mpvlib/handle.rb', line 64

def audio_device
  @audio_device
end

#delegateObject

Returns the value of attribute delegate.



67
68
69
# File 'lib/mpvlib/handle.rb', line 67

def delegate
  @delegate
end

#equalizerObject

Returns the value of attribute equalizer.



66
67
68
# File 'lib/mpvlib/handle.rb', line 66

def equalizer
  @equalizer
end

#mpv_log_levelObject

Returns the value of attribute mpv_log_level.



65
66
67
# File 'lib/mpvlib/handle.rb', line 65

def mpv_log_level
  @mpv_log_level
end

#playlist_fileObject

Returns the value of attribute playlist_file.



63
64
65
# File 'lib/mpvlib/handle.rb', line 63

def playlist_file
  @playlist_file
end

#wakeup_pipeObject (readonly)

Returns the value of attribute wakeup_pipe.



68
69
70
# File 'lib/mpvlib/handle.rb', line 68

def wakeup_pipe
  @wakeup_pipe
end

Instance Method Details

#client_nameObject



106
107
108
# File 'lib/mpvlib/handle.rb', line 106

def client_name
  MPV.mpv_client_name(@mpv_handle)
end

#command(*args) ⇒ Object



119
120
121
122
123
# File 'lib/mpvlib/handle.rb', line 119

def command(*args)
  MPV::Error.raise_on_failure("command: args = %p" % args) {
    MPV.mpv_command(@mpv_handle, FFI::MemoryPointer.from_array_of_strings(args.map(&:to_s)))
  }
end

#command_async(*args, &block) ⇒ Object



125
126
127
128
129
130
131
132
# File 'lib/mpvlib/handle.rb', line 125

def command_async(*args, &block)
  @reply_id += 1
  MPV::Error.raise_on_failure("command_async: args = %p" % args) {
    MPV.mpv_command_async(@mpv_handle, @reply_id, FFI::MemoryPointer.from_array_of_strings(args.map(&:to_s)))
  }
  @property_observers[@reply_id] = block
  @reply_id
end

#event_loop(timeout: nil) ⇒ Object



165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/mpvlib/handle.rb', line 165

def event_loop(timeout: nil)
  loop do
    event = wait_event(timeout: timeout)
    break if event.kind_of?(MPV::Event::None)
    raise event.error if event.error
    if event.reply_id && event.reply_id != 0 && (observer = @property_observers[event.reply_id])
      observer.call(event)
    end
    if (observers = @event_observers[event.event_id])
      observers.each { |o| o.call(event) }
    end
  end
end

#get_property(name) ⇒ Object



141
142
143
144
# File 'lib/mpvlib/handle.rb', line 141

def get_property(name)
  #FIXME: allow non-string values
  MPV.mpv_get_property_string(@mpv_handle, name)
end

#get_time_usObject



110
111
112
# File 'lib/mpvlib/handle.rb', line 110

def get_time_us
  MPV.mpv_get_time_us(@mpv_handle)
end

#handle_log_message(log_message) ⇒ Object



277
278
279
280
281
282
283
# File 'lib/mpvlib/handle.rb', line 277

def handle_log_message(log_message)
  severity = MPVLogMessageLevels[log_message.level] || Logger::UNKNOWN
  @delegate.add_log_message(
    severity,
    '%15s: %s' % [log_message.prefix, log_message.text.chomp],
    'MPV')
end

#loadlist(path) ⇒ Object



211
212
213
# File 'lib/mpvlib/handle.rb', line 211

def loadlist(path)
  command('loadlist', path.to_s)
end

#observe_property(name, &block) ⇒ Object



146
147
148
149
150
151
152
153
# File 'lib/mpvlib/handle.rb', line 146

def observe_property(name, &block)
  @reply_id += 1
  MPV::Error.raise_on_failure("set_property: name = %p" % name) {
    MPV.mpv_observe_property(@mpv_handle, @reply_id, name, :MPV_FORMAT_STRING)
  }
  @property_observers[@reply_id] = block
  @reply_id
end

#pauseObject



223
224
225
226
227
228
229
230
# File 'lib/mpvlib/handle.rb', line 223

def pause
  case get_property('pause')
  when 'no', nil
    false
  when 'yes'
    true
  end
end

#pause=(state) ⇒ Object



232
233
234
# File 'lib/mpvlib/handle.rb', line 232

def pause=(state)
  set_property('pause', state ? 'yes' : 'no')
end

#play(playlist = nil) ⇒ Object



256
257
258
259
260
261
262
263
264
# File 'lib/mpvlib/handle.rb', line 256

def play(playlist=nil)
  if playlist
    @playlist_file.dirname.mkpath
    @playlist_file.open('w') do |io|
      playlist.each { |p| io.puts(p) }
    end
  end
  loadlist(@playlist_file)
end

#playlistObject



252
253
254
# File 'lib/mpvlib/handle.rb', line 252

def playlist
  JSON.parse(get_property('playlist')).map { |h| HashStruct.new(h) }
end

#playlist_countObject



199
200
201
# File 'lib/mpvlib/handle.rb', line 199

def playlist_count
  (v = get_property('playlist/count')) && v.to_i
end

#playlist_filename(position) ⇒ Object



244
245
246
247
248
249
250
# File 'lib/mpvlib/handle.rb', line 244

def playlist_filename(position)
  if (filename = get_property("playlist/#{position}/filename")) && !filename.empty?
    Path.new(filename)
  else
    nil
  end
end

#playlist_nextObject



219
220
221
# File 'lib/mpvlib/handle.rb', line 219

def playlist_next
  command('playlist-next')
end

#playlist_positionObject



191
192
193
# File 'lib/mpvlib/handle.rb', line 191

def playlist_position
  (v = get_property('playlist-pos')) && v.to_i
end

#playlist_position=(position) ⇒ Object



195
196
197
# File 'lib/mpvlib/handle.rb', line 195

def playlist_position=(position)
  set_property('playlist-pos', position)
end

#playlist_previousObject



215
216
217
# File 'lib/mpvlib/handle.rb', line 215

def playlist_previous
  command('playlist-prev')
end

#register_event(name, &block) ⇒ Object



155
156
157
158
159
# File 'lib/mpvlib/handle.rb', line 155

def register_event(name, &block)
  event_id = MPVEventNames[name] or raise "No such event: #{name.inspect}"
  @event_observers[event_id] ||= []
  @event_observers[event_id] << block
end

#request_log_messages(level, &block) ⇒ Object



184
185
186
187
188
189
# File 'lib/mpvlib/handle.rb', line 184

def request_log_messages(level, &block)
  MPV::Error.raise_on_failure("request_log_messages: level = %p" % level) {
    MPV.mpv_request_log_messages(@mpv_handle, level)
  }
  register_event('log-message', &block) if block_given?
end

#run_event_loopObject



179
180
181
182
# File 'lib/mpvlib/handle.rb', line 179

def run_event_loop
  @wakeup_pipe.read_nonblock(1024)
  event_loop(timeout: 0)
end

#seek_by(seconds) ⇒ Object



236
237
238
# File 'lib/mpvlib/handle.rb', line 236

def seek_by(seconds)
  command('seek', seconds)
end

#seek_to_percent(percent) ⇒ Object



240
241
242
# File 'lib/mpvlib/handle.rb', line 240

def seek_to_percent(percent)
  command('seek', percent, 'absolute-percent')
end

#set_option(name, value) ⇒ Object



114
115
116
117
# File 'lib/mpvlib/handle.rb', line 114

def set_option(name, value)
  #FIXME: allow non-string values
  MPV.mpv_set_option_string(@mpv_handle, name, value.to_s)
end

#set_property(name, data) ⇒ Object



134
135
136
137
138
139
# File 'lib/mpvlib/handle.rb', line 134

def set_property(name, data)
  #FIXME: allow non-string values
  MPV::Error.raise_on_failure("set_property: name = %p, data = %p" % [name, data]) {
    MPV.mpv_set_property_string(@mpv_handle, name, data.to_s)
  }
end

#time_positionObject



203
204
205
# File 'lib/mpvlib/handle.rb', line 203

def time_position
  (v = get_property('time-pos')) && v.to_f
end

#time_position=(position) ⇒ Object



207
208
209
# File 'lib/mpvlib/handle.rb', line 207

def time_position=(position)
  set_property('time-pos', position)
end

#wait_event(timeout: nil) ⇒ Object



161
162
163
# File 'lib/mpvlib/handle.rb', line 161

def wait_event(timeout: nil)
  Event.new_from_mpv_event(MPV.mpv_wait_event(@mpv_handle, timeout || -1))
end