-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathschemep3-backend-mplayer.scm
136 lines (108 loc) · 4.51 KB
/
schemep3-backend-mplayer.scm
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
#lang scheme
(require scheme/system)
(require scheme/async-channel)
(require srfi/2)
(require srfi/26)
(require "schemep3-status.scm")
(require "schemep3-database.scm")
(require "schemep3-helpers.scm")
(require "schemep3-playback.scm")
(define mplayer-variables (make-hash))
(define (get-mplayer-variable key)
(hash-ref mplayer-variables key))
(define (set-mplayer-variable key value)
(hash-set! mplayer-variables key value))
(define-syntax define-mplayer-binding
(syntax-rules ()
((_ variable-name)
(set-mplayer-variable (quote variable-name) #f))))
(define-mplayer-binding ANS_TIME_POSITION)
(define-mplayer-binding ANS_PERCENT_POSITION)
(define MPLAYER-POS-PERCENT #"pausing_keep get_percent_pos\n")
(define MPLAYER-POS-ABS #"pausing_keep get_time_pos\n")
(define MPLAYER-QUIT #"pausing_keep quit\n")
(define MPLAYER-PAUSE #"pausing_toggle get_time_pos\n")
(define _mplayer-executable
(if (equal? (system-type) 'windows)
"bin\\mplayer.exe"
"/opt/local/bin/mplayer"))
(define (start-playback file)
(let ((command-line
(format "~A -slave -quiet \"~A\"" _mplayer-executable file)))
(process command-line)))
(define mplayer-backend%
(class* object% (playback-backend<%>)
(define PLAYBACK-REGEX
(filename-extensions-regex (list "mp3" "flac" "m4a" "ogg" "wma")))
(define/public (playback-supported? filename)
(regexp-match? PLAYBACK-REGEX filename))
(define mailbox (make-async-channel 5))
(define (post-message message)
(async-channel-put mailbox message))
(define _player-process-info #f)
(define (current-player-stdin)
(list-ref _player-process-info 1))
(define (current-player-stderr)
(list-ref _player-process-info 3))
(define (current-player-stdout)
(list-ref _player-process-info 0))
;;;; mplayer communication...
(define (send-mplayer-command bytes)
(when _player-process-info
(let ((player-stdin (current-player-stdin)))
(write-bytes bytes player-stdin)
(flush-output player-stdin))))
(define (process-mplayer-string str progress-callback)
(for ((key (in-hash-keys mplayer-variables)))
(and-let* ((value
(or
(and-let* ((m (regexp-match (format "~A='([^\n\r]*)'" key) str)))
(second m))
(and-let* ((m (regexp-match (format "~A=([^\n\r]*)" key) str)))
(string->number (second m))))))
(unless (equal? (get-mplayer-variable key) value)
(set-mplayer-variable key value)
(when (eq? key 'ANS_TIME_POSITION)
(progress-callback
(get-mplayer-variable 'ANS_TIME_POSITION)
(get-mplayer-variable 'ANS_PERCENT_POSITION)))))))
(define (parse-mplayer-output port callback)
(let ((recurse #t))
(let ((evt (sync/timeout 1 port mailbox)))
(cond
((eq? evt port)
(let ((s (read-line port)))
(cond
((string? s)
(process-mplayer-string s callback))
((eof-object? s)
(set! recurse #f)))))
((bytes? evt)
(send-mplayer-command evt))
((not evt)
(unless (paused?)
(send-mplayer-command MPLAYER-POS-PERCENT)
(send-mplayer-command MPLAYER-POS-ABS))
(void))
(else (raise "WTF?!"))))
(when recurse
(parse-mplayer-output port callback))))
(define/public (play file callback)
(status:update "Play ~a" file)
(set! _player-process-info (start-playback file))
(parse-mplayer-output (current-player-stdout) callback)
(close-input-port (current-player-stdout))
(close-input-port (current-player-stderr))
(close-output-port (current-player-stdin))
(values (get-mplayer-variable 'ANS_TIME_POSITION)
(get-mplayer-variable 'ANS_PERCENT_POSITION)))
(define/public (stop)
(post-message MPLAYER-QUIT))
(define/public (pause)
(post-message MPLAYER-PAUSE))
(define/public (seek position)
(post-message (string->bytes/utf-8
(format "seek ~a 1\n" position))))
(super-new)))
(current-backend (new mplayer-backend%))
(preview-backend (new mplayer-backend%))