2 Minimal VLC VLM client for AceProxy. Client class.
10 from vlcmessages import *
13 class VlcException(Exception):
16 Exception from VlcClient
21 class VlcClient(object):
28 self, host='127.0.0.1', port=4212, password='admin', connect_timeout=10,
29 result_timeout=10, out_port=8081):
31 self._recvbuffer = None
33 self._out_port = out_port
37 self._resulttimeout = result_timeout
39 self._shuttingDown = gevent.event.Event()
40 # Authentication done event
41 self._auth = gevent.event.AsyncResult()
43 self._resultlock = gevent.coros.RLock()
45 self._result = gevent.event.AsyncResult()
49 self._password = password
52 logger = logging.getLogger('VlcClient_init')
59 self._socket = telnetlib.Telnet(host, port, connect_timeout)
60 logger.info("Successfully connected with VLC socket!")
61 except Exception as e:
63 "Socket creation error! VLC is not running? ERROR: " + repr(e))
65 # Spawning recvData greenlet
66 gevent.spawn(self._recvData)
69 # Waiting for authentication event
71 if self._auth.get(timeout=self._resulttimeout) == False:
72 errmsg = "Authentication error"
74 raise VlcException(errmsg)
75 except gevent.Timeout:
76 errmsg = "Authentication timeout"
78 raise VlcException(errmsg)
81 # Destructor just calls destroy() method
86 logger = logging.getLogger("VlcClient_destroy")
88 if self._shuttingDown.isSet():
89 # Already in the middle of destroying
92 # If socket is still alive (connected)
95 logger.info("Destroying VlcClient...")
96 self._write(VlcMessage.request.SHUTDOWN)
97 # Set shuttingDown flag for recvData
98 self._shuttingDown.set()
100 # Ignore exceptions on destroy
103 def _write(self, message):
105 logger = logging.getLogger("VlcClient_write")
107 # Return if in the middle of destroying
108 if self._shuttingDown.isSet():
113 logger.info('VLC command: ' + message)
114 self._socket.write(message + "\r\n")
115 except EOFError as e:
116 raise VlcException("Vlc Write error! ERROR: " + repr(e))
118 def _broadcast(self, brtype, stream_name, input=None, muxer='ts', pre_access='', qtype='default'):
119 if self._shuttingDown.isSet():
122 # Start/stop broadcast with VLC
125 broadcast = 'startBroadcast'
127 broadcast = 'stopBroadcast'
129 logger = logging.getLogger("VlcClient_" + broadcast)
131 self._result = gevent.event.AsyncResult()
133 self._resultlock.acquire()
134 # Write message to VLC socket
136 msg = VlcMessage.request.startBroadcast(stream_name, input, self._out_port, muxer, pre_access, qtype)
139 if stream_name not in self.streams:
140 self._resultlock.release()
141 logger.error("Attempting to delete not existing stream %s" % stream_name)
143 self._write(VlcMessage.request.stopBroadcast(stream_name))
147 result = self._result.get(timeout=self._resulttimeout)
149 logger.error(broadcast + " error")
150 raise VlcException(broadcast + " error")
151 except gevent.Timeout:
152 logger.error(broadcast + " result timeout")
153 raise VlcException(broadcast + " result timeout")
155 logger.info("working with %s stream: %s" % (stream_name,broadcast))
157 self.streams[stream_name]=time.time()
159 del self.streams[stream_name]
160 self._resultlock.release()
161 logger.info("worked with %s stream: %s" % (stream_name,broadcast))
164 logger.info("Broadcast started")
166 logger.info("Broadcast stopped")
168 def startBroadcast(self, stream_name, input, muxer='ts', pre_access='', qtype='default'):
169 logger = logging.getLogger("VlcClient_startBroadcast")
170 logger.debug("Starting broadcast......")
171 return self._broadcast(True, stream_name, input, muxer, pre_access, qtype)
173 def stopBroadcast(self, stream_name):
174 return self._broadcast(False, stream_name)
176 def mark(self,stream_name):
177 self.streams[stream_name]=time.time()
179 def clean_streams(self,timeout=15):
180 self._resultlock.acquire()
182 for stream,lasttime in self.streams.iteritems():
183 if time.time()-lasttime>timeout:
185 for stream in to_stop:
187 self.stopBroadcast(stream)
190 self._resultlock.release()
192 def check_stream(self,stream_name):
193 if stream_name in self.streams:
194 self.streams[stream_name]=time.time()
199 def pauseBroadcast(self, stream_name):
200 return self._write(VlcMessage.request.pauseBroadcast(stream_name))
202 def playBroadcast(self, stream_name):
203 return self._write(VlcMessage.request.playBroadcast(stream_name))
207 logger = logging.getLogger("VlcClient_recvData")
212 self._recvbuffer = self._socket.read_until("\n")
213 # Stripping "> " from VLC
214 self._recvbuffer = self._recvbuffer.lstrip("> ")
216 # If something happened during read, abandon reader
217 if not self._shuttingDown.isSet():
218 logger.error("Exception at socket read")
219 self._shuttingDown.set()
222 # Parsing everything only if the string is not empty
225 # First line (VLC version)
226 self._vlcver = self._recvbuffer.strip()
227 # Send password here since PASSWORD doesn't have \n
228 self._write(self._password)
230 elif self._recvbuffer.startswith(VlcMessage.response.SHUTDOWN):
231 # Exit from this loop
232 logger.debug("Got SHUTDOWN from VLC")
235 elif self._recvbuffer.startswith(VlcMessage.response.WRONGPASS):
237 logger.error("Wrong VLC password!")
238 self._auth.set(False)
241 elif self._recvbuffer.startswith(VlcMessage.response.AUTHOK):
243 logger.info("Authentication successful")
246 elif VlcMessage.response.BROADCASTEXISTS in self._recvbuffer:
247 # Broadcast already exists
248 logger.error("Broadcast already exists!")
249 self._result.set(False)
251 elif VlcMessage.response.STOPERR in self._recvbuffer:
252 # Media unknown (stopping non-existent stream)
253 logger.error("Broadcast does not exist!")
254 self._result.set(False)
256 # Do not move this before error handlers!
257 elif self._recvbuffer.startswith(VlcMessage.response.STARTOK):
259 logger.info("Broadcast started")
260 self._result.set(True)
262 elif self._recvbuffer.startswith(VlcMessage.response.STOPOK):
264 logger.info("Broadcast stopped")
265 self._result.set(True)