-
Notifications
You must be signed in to change notification settings - Fork 12
/
player.go
431 lines (376 loc) · 15.2 KB
/
player.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
package omxplayer
import (
"os"
"os/exec"
"syscall"
"time"
dbus "github.com/guelfey/go.dbus"
log "github.com/sirupsen/logrus"
)
const (
ifaceProps = "org.freedesktop.DBus.Properties"
ifaceOmxRoot = ifaceMpris
ifaceOmxPlayer = ifaceOmxRoot + ".Player"
cmdQuit = ifaceOmxRoot + ".Quit"
propCanQuit = ifaceProps + ".CanQuit"
propFullscreen = ifaceProps + ".Fullscreen"
propCanSetFullscreen = ifaceProps + ".CanSetFullscreen"
propCanRaise = ifaceProps + ".CanRaise"
propHasTrackList = ifaceProps + ".HasTrackList"
propIdentity = ifaceProps + ".Identity"
propSupportedURISchemes = ifaceProps + ".SupportedUriSchemes"
propSupportedMimeTypes = ifaceProps + ".SupportedMimeTypes"
propCanGoNext = ifaceProps + ".CanGoNext"
propCanGoPrevious = ifaceProps + ".CanGoPrevious"
propCanSeek = ifaceProps + ".CanSeek"
propCanControl = ifaceProps + ".CanControl"
propCanPlay = ifaceProps + ".CanPlay"
propCanPause = ifaceProps + ".CanPause"
cmdNext = ifaceOmxPlayer + ".Next"
cmdPrevious = ifaceOmxPlayer + ".Previous"
cmdPause = ifaceOmxPlayer + ".Pause"
cmdPlay = ifaceOmxPlayer + ".Play"
cmdPlayPause = ifaceOmxPlayer + ".PlayPause"
cmdStop = ifaceOmxPlayer + ".Stop"
cmdSeek = ifaceOmxPlayer + ".Seek"
cmdSetPosition = ifaceOmxPlayer + ".SetPosition"
propPlaybackStatus = ifaceProps + ".PlaybackStatus"
cmdVolume = ifaceProps + ".Volume"
cmdMute = ifaceProps + ".Mute"
cmdUnmute = ifaceProps + ".Unmute"
propPosition = ifaceProps + ".Position"
propAspect = ifaceProps + ".Aspect"
propVideoStreamCount = ifaceProps + ".VideoStreamCount"
propResWidth = ifaceProps + ".ResWidth"
propResHeight = ifaceProps + ".ResHeight"
propDuration = ifaceProps + ".Duration"
propMinimumRate = ifaceProps + ".MinimumRate"
propMaximumRate = ifaceProps + ".MaximumRate"
cmdListSubtitles = ifaceOmxPlayer + ".ListSubtitles"
cmdHideVideo = ifaceOmxPlayer + ".HideVideo"
cmdUnHideVideo = ifaceOmxPlayer + ".UnHideVideo"
cmdListAudio = ifaceOmxPlayer + ".ListAudio"
cmdListVideo = ifaceOmxPlayer + ".ListVideo"
cmdSelectSubtitle = ifaceOmxPlayer + ".SelectSubtitle"
cmdSelectAudio = ifaceOmxPlayer + ".SelectAudio"
cmdShowSubtitles = ifaceOmxPlayer + ".ShowSubtitles"
cmdHideSubtitles = ifaceOmxPlayer + ".HideSubtitles"
cmdAction = ifaceOmxPlayer + ".Action"
)
// The Player struct provides access to all of omxplayer's D-Bus methods.
type Player struct {
command *exec.Cmd
connection *dbus.Conn
bus *dbus.Object
ready bool
}
// IsRunning checks to see if the OMXPlayer process is running. If it is, the
// function returns true, otherwise it returns false.
func (p *Player) IsRunning() bool {
pid := p.command.Process.Pid
process, err := os.FindProcess(pid)
if err != nil {
return false
}
err = process.Signal(syscall.Signal(0))
return err != nil
}
// IsReady checks to see if the Player instance is ready to accept D-Bus
// commands. If the player is ready and can accept commands, the function
// returns true, otherwise it returns false.
func (p *Player) IsReady() bool {
if p.ready {
return true
}
result, err := p.CanQuit()
if err == nil && result {
p.ready = true
}
return p.ready
}
// WaitForReady waits until the Player instance is ready to accept D-Bus
// commands and then returns.
func (p *Player) WaitForReady() {
for !p.IsReady() {
time.Sleep(50 * time.Millisecond)
}
}
// Quit stops the currently playing video and terminates the omxplayer process.
// See https://github.com/popcornmix/omxplayer#quit for more details.
func (p *Player) Quit() error {
return dbusCall(p.bus, cmdQuit)
}
// CanQuit returns true if the player can quit, false otherwise. See
// https://github.com/popcornmix/omxplayer#canquit for more details.
func (p *Player) CanQuit() (bool, error) {
return dbusGetBool(p.bus, propCanQuit)
}
// Fullscreen returns true if the player is fullscreen, false otherwise. See
// https://github.com/popcornmix/omxplayer#fullscreen for more details.
func (p *Player) Fullscreen() (bool, error) {
return dbusGetBool(p.bus, propFullscreen)
}
// CanSetFullscreen returns true if the player can be set to fullscreen, false
// otherwise. See https://github.com/popcornmix/omxplayer#cansetfullscreen for
// more details.
func (p *Player) CanSetFullscreen() (bool, error) {
return dbusGetBool(p.bus, propCanSetFullscreen)
}
// CanRaise returns true if the player can be brought to the front, false
// otherwise. See https://github.com/popcornmix/omxplayer#canraise for more
// details.
func (p *Player) CanRaise() (bool, error) {
return dbusGetBool(p.bus, propCanRaise)
}
// HasTrackList returns true if the player has a track list, false otherwise.
// See https://github.com/popcornmix/omxplayer#hastracklist for more details.
func (p *Player) HasTrackList() (bool, error) {
return dbusGetBool(p.bus, propHasTrackList)
}
// Identity returns the name of the player instance. See
// https://github.com/popcornmix/omxplayer#identity for more details.
func (p *Player) Identity() (string, error) {
return dbusGetString(p.bus, propIdentity)
}
// SupportedURISchemes returns a list of playable URI formats. See
// https://github.com/popcornmix/omxplayer#supportedurischemes for more details.
func (p *Player) SupportedURISchemes() ([]string, error) {
return dbusGetStringArray(p.bus, propSupportedURISchemes)
}
// SupportedMimeTypes returns a list of supported MIME types. See
// https://github.com/popcornmix/omxplayer#supportedmimetypes for more details.
func (p *Player) SupportedMimeTypes() ([]string, error) {
return dbusGetStringArray(p.bus, propSupportedMimeTypes)
}
// CanGoNext returns true if the player can skip to the next track, false
// otherwise. See https://github.com/popcornmix/omxplayer#cangonext for more
// details.
func (p *Player) CanGoNext() (bool, error) {
return dbusGetBool(p.bus, propCanGoNext)
}
// CanGoPrevious returns true if the player can skip to previous track, false
// otherwise. See https://github.com/popcornmix/omxplayer#cangoprevious for more
// details.
func (p *Player) CanGoPrevious() (bool, error) {
return dbusGetBool(p.bus, propCanGoPrevious)
}
// CanSeek returns true if the player can seek, false otherwise. See
// https://github.com/popcornmix/omxplayer#canseek for more details.
func (p *Player) CanSeek() (bool, error) {
return dbusGetBool(p.bus, cmdSeek)
}
// CanControl returns true if the player can be controlled, false otherwise. See
// https://github.com/popcornmix/omxplayer#cancontrol for more details.
func (p *Player) CanControl() (bool, error) {
return dbusGetBool(p.bus, propCanControl)
}
// CanPlay returns true if the player can play, false otherwise. See
// https://github.com/popcornmix/omxplayer#canplay for more details.
func (p *Player) CanPlay() (bool, error) {
return dbusGetBool(p.bus, propCanPlay)
}
// CanPause returns true if the player can pause, false otherwise. See
// https://github.com/popcornmix/omxplayer#canpause for more details.
func (p *Player) CanPause() (bool, error) {
return dbusGetBool(p.bus, propCanPause)
}
// Next tells the player to skip to the next chapter. See
// https://github.com/popcornmix/omxplayer#next for more details.
func (p *Player) Next() error {
return dbusCall(p.bus, cmdNext)
}
// Previous tells the player to skip to the previous chapter. See
// https://github.com/popcornmix/omxplayer#previous for more details.
func (p *Player) Previous() error {
return dbusCall(p.bus, cmdPrevious)
}
// Pause pauses the player if it is playing. Otherwise, it resumes playback. See
// https://github.com/popcornmix/omxplayer#pause for more details.
func (p *Player) Pause() error {
return dbusCall(p.bus, cmdPause)
}
// Play play the video. If the video is playing, it has no effect,
// if it is paused it will play from current position.
// See https://github.com/popcornmix/omxplayer#play for more details.
func (p *Player) Play() error {
return dbusCall(p.bus, cmdPlay)
}
// PlayPause pauses the player if it is playing. Otherwise, it resumes playback.
// See https://github.com/popcornmix/omxplayer#playpause for more details.
func (p *Player) PlayPause() error {
return dbusCall(p.bus, cmdPlayPause)
}
// Stop tells the player to stop playing the video. See
// https://github.com/popcornmix/omxplayer#stop for more details.
func (p *Player) Stop() error {
return dbusCall(p.bus, cmdStop)
}
// Seek performs a relative seek from the current video position. See
// https://github.com/popcornmix/omxplayer#seek for more details.
func (p *Player) Seek(amount int64) (int64, error) {
log.WithFields(log.Fields{
"path": cmdSeek,
"paramAmount": amount,
}).Debug("omxplayer: dbus call")
call := p.bus.Call(cmdSeek, 0, amount)
if call.Err != nil {
return 0, call.Err
}
return call.Body[0].(int64), nil
}
// SetPosition performs an absolute seek to the specified video position. See
// https://github.com/popcornmix/omxplayer#setposition for more details.
func (p *Player) SetPosition(path string, position int64) (int64, error) {
log.WithFields(log.Fields{
"path": cmdSetPosition,
"paramPath": path,
"paramPosition": position,
}).Debug("omxplayer: dbus call")
call := p.bus.Call(cmdSetPosition, 0, dbus.ObjectPath(path), position)
if call.Err != nil {
return 0, call.Err
}
return call.Body[0].(int64), nil
}
// PlaybackStatus returns the current state of the player. See
// https://github.com/popcornmix/omxplayer#playbackstatus for more details.
func (p *Player) PlaybackStatus() (string, error) {
return dbusGetString(p.bus, propPlaybackStatus)
}
// Volume returns the current volume. Sets a new volume when an argument is
// specified. See https://github.com/popcornmix/omxplayer#volume for more
// details.
func (p *Player) Volume(volume ...float64) (float64, error) {
log.WithFields(log.Fields{
"path": cmdVolume,
"paramVolume": volume,
}).Debug("omxplayer: dbus call")
if len(volume) == 0 {
return dbusGetFloat64(p.bus, cmdVolume)
}
call := p.bus.Call(cmdVolume, 0, volume[0])
if call.Err != nil {
return 0, call.Err
}
return call.Body[0].(float64), nil
}
// Mute mutes the video's audio stream. See
// https://github.com/popcornmix/omxplayer#mute for more details.
func (p *Player) Mute() error {
return dbusCall(p.bus, cmdMute)
}
// Unmute unmutes the video's audio stream. See
// https://github.com/popcornmix/omxplayer#unmute for more details.
func (p *Player) Unmute() error {
return dbusCall(p.bus, cmdUnmute)
}
// Position returns the current position in the video in milliseconds. See
// https://github.com/popcornmix/omxplayer#position for more details.
func (p *Player) Position() (int64, error) {
return dbusGetInt64(p.bus, propPosition)
}
// Aspect returns the aspect ratio. See
// https://github.com/popcornmix/omxplayer/blob/master/OMXControl.cpp#L362.
func (p *Player) Aspect() (float64, error) {
return dbusGetFloat64(p.bus, propAspect)
}
// VideoStreamCount returns the number of available video streams. See
// https://github.com/popcornmix/omxplayer/blob/master/OMXControl.cpp#L369.
func (p *Player) VideoStreamCount() (int64, error) {
return dbusGetInt64(p.bus, propVideoStreamCount)
}
// ResWidth returns the width of the video. See
// https://github.com/popcornmix/omxplayer/blob/master/OMXControl.cpp#L376.
func (p *Player) ResWidth() (int64, error) {
return dbusGetInt64(p.bus, propResWidth)
}
// ResHeight returns the height of the video. See
// https://github.com/popcornmix/omxplayer/blob/master/OMXControl.cpp#L383.
func (p *Player) ResHeight() (int64, error) {
return dbusGetInt64(p.bus, propResHeight)
}
// Duration returns the total length of the video in milliseconds. See
// https://github.com/popcornmix/omxplayer#duration for more details.
func (p *Player) Duration() (int64, error) {
return dbusGetInt64(p.bus, propDuration)
}
// MinimumRate returns the minimum playback rate. See
// https://github.com/popcornmix/omxplayer#minimumrate for more details.
func (p *Player) MinimumRate() (float64, error) {
return dbusGetFloat64(p.bus, propMinimumRate)
}
// MaximumRate returns the maximum playback rate. See
// https://github.com/popcornmix/omxplayer#maximumrate for more details.
func (p *Player) MaximumRate() (float64, error) {
return dbusGetFloat64(p.bus, propMaximumRate)
}
// ListSubtitles returns a list of the subtitles available in the video file.
// See https://github.com/popcornmix/omxplayer#listsubtitles for more details.
func (p *Player) ListSubtitles() ([]string, error) {
return dbusGetStringArray(p.bus, cmdListSubtitles)
}
// HideVideo is an undocumented D-Bus method. See
// https://github.com/popcornmix/omxplayer/blob/master/OMXControl.cpp#L457.
func (p *Player) HideVideo() error {
return dbusCall(p.bus, cmdHideVideo)
}
// UnHideVideo is an undocumented D-Bus method. See
// https://github.com/popcornmix/omxplayer/blob/master/OMXControl.cpp#L462.
func (p *Player) UnHideVideo() error {
return dbusCall(p.bus, cmdUnHideVideo)
}
// ListAudio returns a list of the audio tracks available in the video file. See
// https://github.com/popcornmix/omxplayer#listaudio for more details.
func (p *Player) ListAudio() ([]string, error) {
return dbusGetStringArray(p.bus, cmdListAudio)
}
// ListVideo returns a list of the video tracks available in the video file. See
// https://github.com/popcornmix/omxplayer#listvideo for more details.
func (p *Player) ListVideo() ([]string, error) {
return dbusGetStringArray(p.bus, cmdListVideo)
}
// SelectSubtitle specifies which subtitle track should be used. See
// https://github.com/popcornmix/omxplayer#selectsubtitle for more details.
func (p *Player) SelectSubtitle(index int32) (bool, error) {
log.WithFields(log.Fields{
"path": cmdSelectSubtitle,
"paramIndex": index,
}).Debug("omxplayer: dbus call")
call := p.bus.Call(cmdSelectSubtitle, 0, index)
if call.Err != nil {
return false, call.Err
}
return call.Body[0].(bool), nil
}
// SelectAudio specifies which audio track should be used. See
// https://github.com/popcornmix/omxplayer#selectaudio for more details.
func (p *Player) SelectAudio(index int32) (bool, error) {
log.WithFields(log.Fields{
"path": cmdSelectAudio,
"paramIndex": index,
}).Debug("omxplayer: dbus call")
call := p.bus.Call(cmdSelectAudio, 0, index)
if call.Err != nil {
return false, call.Err
}
return call.Body[0].(bool), nil
}
// ShowSubtitles starts displaying subtitles. See
// https://github.com/popcornmix/omxplayer#showsubtitles for more details.
func (p *Player) ShowSubtitles() error {
return dbusCall(p.bus, cmdShowSubtitles)
}
// HideSubtitles stops displaying subtitles. See
// https://github.com/popcornmix/omxplayer#hidesubtitles for more details.
func (p *Player) HideSubtitles() error {
return dbusCall(p.bus, cmdHideSubtitles)
}
// Action allows for executing keyboard commands. See
// https://github.com/popcornmix/omxplayer#action for more details.
func (p *Player) Action(action int32) error {
log.WithFields(log.Fields{
"path": cmdAction,
"paramAction": action,
}).Debug("omxplayer: dbus call")
return p.bus.Call(cmdAction, 0, action).Err
}