script to synchronize mplay...
Stefan Schuermans authored 10 years ago
|
36) # create member variables
37) self.mplayer = None
38) self.mplayer_buf_stdout = ""
39) self.mplayer_buf_stderr = ""
40) self.mplayer_last_cmd_timestamp = None
41) self.mplayer_name = None
42) self.mplayer_pause = None
43) self.mplayer_pos = None
44) self.mplayer_speed = None
45) self.mplayer_timestamp = None
46) self.offset_samples = []
47) self.playlist = []
48) self.playlist_idx = None
49) self.posy_name = None
50) self.posy_pause = None
51) self.posy_pos = None
52) self.posy_timestamp = None
53) self.sock = None
54) self.verbose = False
55) # startup
56) self.sockSetup()
57)
58) def __del__(self):
59) """deconstruct object"""
60) self.mplayerStop()
61) self.sockClose()
62)
63) def dbg_print(self, txt):
64) """output debug information in verbose mode"""
65) if self.verbose:
66) print >>sys.stderr, txt
67)
68) def mplayerClear(self):
69) """clear MPlayer buffers and information"""
70) self.mplayer_buf_stdin = ""
71) self.mplayer_buf_stderr = ""
72) self.mplayer_last_cmd_timestamp = None
73) self.mplayer_name = None
74) self.mplayer_pause = None
75) self.mplayer_pos = None
76) self.mplayer_speed = None
77) self.mplayer_timestamp = None
78) self.offset_samples = []
79)
80) def mplayerExit(self):
81) """react to MPlayer exit"""
82) # close pipes
83) self.mplayer.stdin.close()
84) self.mplayer.stdout.close()
85) self.mplayer.stderr.close()
86) # close process
87) self.mplayer.wait()
88) self.mplayer = None
89) # clear buffers and information
90) self.mplayerClear()
91) # play next file
92) self.playNext()
93)
94) def mplayerLine(self, line, err):
95) """process line from MPlayer stdout (err = False) or stderr (err = True)"""
96) if len(line) > 0:
97) if err:
98) self.dbg_print("MPlayer stderr: " + line)
99) else:
100) self.dbg_print("MPlayer stdout: " + line)
101) if not err:
102) # MPlayer position information
103) m_mplayer_pos = self.re_mplayer_pos.match(line)
104) if m_mplayer_pos:
105) self.mplayer_timestamp = datetime.datetime.now()
106) self.mplayer_pos = float(m_mplayer_pos.group(1))
107) # synchronize
108) self.sync()
109)
110) def mplayerPause(self, pause):
111) """pause/unpause MPlayer"""
112) # leave if no MPlayer running
113) if self.mplayer is None:
114) return
115) # switch to pause mode
116) if pause:
117) self.dbg_print("MPlayer stdin: pausing seek 0 0")
118) self.mplayer.stdin.write("pausing seek 0 0\n") # rel seek 0s, then pause
119) self.mplayer_pause = True
120) # continue playing
121) else:
122) self.dbg_print("MPlayer stdin: seek 0 0")
123) self.mplayer.stdin.write("seek 0 0\n") # realtive seek of 0s
124) self.mplayer_pause = False
125) self.mplayer_last_cmd_timestamp = datetime.datetime.now()
126)
127) def mplayerSetPos(self, pos):
128) """set MPlayer position"""
129) # leave if no MPlayer running
130) if self.mplayer is None:
131) return
132) # sanitize position to avoid mplayer crashes in any case
133) if pos < 0.0:
134) pos = 0.0
135) # set new position
136) self.dbg_print("MPlayer stdin: seek %5.3f 2" % pos)
137) self.mplayer.stdin.write("seek %5.3f 2\n" % pos) # 2 means absolute pos
138) self.mplayer_pos = pos
139) self.mplayer_last_cmd_timestamp = datetime.datetime.now()
140)
141) def mplayerSetSpeed(self, speed):
142) """set MPlayer speed"""
143) # leave if no MPlayer running
144) if self.mplayer is None:
145) return
146) # sanitize speed to avoid mplayer crashes in any case
147) if speed < 0.5:
148) speed = 0.5
149) if speed > 2.0:
150) speed = 2.0
151) # set new speed
152) self.dbg_print("MPlayer stdin: speed_set %5.3f" % speed)
153) self.mplayer.stdin.write("speed_set %5.3f\n" % speed)
154) self.mplayer_speed = speed
155) self.mplayer_last_cmd_timestamp = datetime.datetime.now()
156)
157) def mplayerStart(self, filename):
158) """start MPlayer process in background"""
159) # stop old MPlayer
160) self.mplayerStop()
161) # start MPlayer
162) cmd = [ "mplayer", "-slave", "-af", "scaletempo", filename ]
163) print >>sys.stderr, "starting background process: " + " ".join(cmd)
164) self.mplayer = subprocess.Popen(cmd, stdin = subprocess.PIPE,
165) stdout = subprocess.PIPE,
166) stderr = subprocess.PIPE)
167) # make output pipes nonblocking
168) fcntl.fcntl(self.mplayer.stdout, fcntl.F_SETFL, os.O_NONBLOCK)
169) fcntl.fcntl(self.mplayer.stderr, fcntl.F_SETFL, os.O_NONBLOCK)
170) # set initial information
171) self.mplayer_name = filename
172) self.mplayer_pause = False
173) self.mplayer_speed = 1.0
174) self.mplayer_last_cmd_timestamp = datetime.datetime.now()
175)
176) def mplayerStdouterr(self, err):
177) """process data from MPlayer stdout (err = False) or stderr (err = True)"""
178) if self.mplayer is None:
179) return
180) # receive data
181) if err:
182) txt = self.mplayer.stderr.read()
183) else:
184) txt = self.mplayer.stdout.read()
185) # check if MPlayer exited
186) if len(txt) == 0:
187) self.mplayerExit()
188) return
189) # MPlayer did not exit
190) # replace CRs with LFs add data to buffer
191) txt = txt.replace("\r", "\n")
192) if err:
193) buf = self.mplayer_buf_stderr + txt
194) else:
195) buf = self.mplayer_buf_stdout + txt
196) # process complete lines and store remaining data in buffer
197) lines = buf.split("\n")
198) for line in lines[:-1]:
199) self.mplayerLine(line, err)
200) if err:
201) self.mplayer_buf_stderr = buf[-1]
202) else:
203) self.mplayer_buf_stdout = buf[-1]
204)
205) def mplayerStop(self):
206) """stop MPlayer process in background"""
207) if self.mplayer is not None:
208) # send quit command
209) self.mplayer.stdin.write("quit\n")
210) # close pipes
211) self.mplayer.stdin.close()
212) self.mplayer.stdout.close()
213) self.mplayer.stderr.close()
214) # terminate process
215) self.mplayer.terminate()
216) self.mplayer.kill()
217) # close process
218) self.mplayer.wait()
219) self.mplayer = None
220) # clear buffers and information
221) self.mplayerClear()
222)
223) def playlistFind(self, posy_name):
224) """find file in playlist by PoSy name"""
225) idx = 0
226) for file_name in self.playlist:
227) if self.posyCheckName(posy_name, file_name):
228) return idx;
229) idx += 1
230) return None
231)
232) def playlistRead(self, playlist):
233) """read playlist file"""
234) # read filenames from playlist
235) filenames = []
236) try:
237) with open(playlist, "rt") as f:
238) filenames = f.readlines()
239) except:
240) return False
241) filenames = [filename.strip() for filename in filenames]
242) # convert filenames to absolute paths
243) playlistdir = os.path.dirname(playlist)
244) filenames = [os.path.join(playlistdir, filename) for filename in filenames]
245) # replace playlist
246) self.playlist = filenames
247) self.playlist_idx = None
248) return True
249)
250) def playNext(self):
251) """play next file in playlist"""
252) # playlist empty -> stop MPlayer
253) if len(self.playlist) == 0:
254) self.playlist_idx = None
255) self.mplayerStop()
256) # playlist not empty -> play next file
257) else:
258) if self.playlist_idx is None:
259) self.playlist_idx = 0
260) else:
261) self.playlist_idx += 1
262) if self.playlist_idx >= len(self.playlist):
263) self.playlist_idx = 0
264) self.mplayerStart(self.playlist[self.playlist_idx])
265)
266) def playPosyName(self, posy_name):
267) """play file by PoSy name (if found)"""
268) # find file in playlist
269) idx = self.playlistFind(posy_name)
270) # file not found -> stop MPlayer
271) if idx is None:
272) self.playlist_idx = None
273) self.mplayerStop()
274) # file found -> (re-)start MPlayer
275) else:
276) self.playlist_idx = idx
277) self.mplayerStart(self.playlist[idx])
278)
279) def posyCheckName(self, posy_name, file_name):
280) """check if filename matches PoSyName"""
281) # remove directory part of file name and check
282) file_name = os.path.basename(file_name)
283) if file_name == posy_name:
284) return True
285) # remove extension and check
286) file_name = os.path.splitext(file_name)[0]
287) if file_name == posy_name:
288) return True
|