class WebRtc(object): def __init__(self): self._connectedPeers = {} self._logger = logging.getLogger(__name__) self._peerCondition = threading.Condition() self._JanusProcess = None self.videoId = 1 initialized = signal('initialized') self.peersDeadDetacher = None def ensureJanusRunning(self): if len(self._connectedPeers.keys()) <= 0: return self.startJanus() else: return True #Janus was running before it def ensureGstreamerRunning(self): cam = cameraManager() if cam.open_camera(): if not cam.start_video_stream(): self._logger.error('Managing Gstreamer error in WebRTC object') #Janus is forced to be closed self.stopJanus() return False return False else: return True def shutdown(self): self._logger.info('Shutting Down WebRtcManager') self.stopJanus() def startLocalSession(self, sessionId): with self._peerCondition: self._connectedPeers[sessionId] = "local" return True def closeLocalSession(self, sessionId): with self._peerCondition: if len(self._connectedPeers.keys()) > 0: try: peer = self._connectedPeers[sessionId] except KeyError: self._logger.warning('Session [%s] for peer not found' % sessionId) peer = None if peer: del self._connectedPeers[sessionId] self._logger.info("There are %d peers left.", len(self._connectedPeers)) if len(webRtcManager()._connectedPeers.keys()) == 0: #last session self.stopGStreamer() self.stopJanus() return True def startPeerSession(self, clientId): with self._peerCondition: if len(self._connectedPeers.keys()) == 0: #first session self.startJanus() peer = ConnectionPeer(clientId, self) sessionId = peer.start() if sessionId: self._connectedPeers[sessionId] = peer return sessionId else: #something went wrong, no session started. Do we still need Janus up? if len(self._connectedPeers.keys()) == 0: self.stopGStreamer() self.stopJanus() return None def closePeerSession(self, sessionId): with self._peerCondition: if len(self._connectedPeers.keys()) > 0: try: peer = self._connectedPeers[sessionId] except KeyError: self._logger.warning('Session [%s] for peer not found' % sessionId) peer = None if peer: peer.streamingPlugin.send_message({'request': 'destroy'}) peer.close() self.sendEventToPeer(self._connectedPeers[sessionId], 'stopConnection') del self._connectedPeers[sessionId] self._logger.info("There are %d peers left.", len(self._connectedPeers)) if len(self._connectedPeers.keys()) == 0: #last session self.stopGStreamer() self.stopJanus() ready = signal('manage_fatal_error_webrtc') ready.disconnect(self.closeAllSessions) def closeAllSessions(self, sender, message): self._logger.info("Closing all streaming sessions") for key in self._connectedPeers.keys(): if self._connectedPeers[key] != 'local': if message: self.sendEventToPeer(self._connectedPeers[key], sender, message) self.closePeerSession(key) else: self.closeLocalSession(key) self.stopJanus() def preparePlugin(self, sessionId): try: peer = self._connectedPeers[sessionId] except KeyError: self._logger.warning('Peer with session [%s] is not found' % sessionId) peer = None self.sendEventToPeers('stopConnection') if peer: peer.streamingPlugin.send_message({'request': 'list'}) videoEncodingSelected = settings().get(["camera", "encoding"]) if videoEncodingSelected == 'h264': self.videoId = 1 else: #VP8 self.videoId = 2 self._connectedPeers[sessionId].streamingPlugin.send_message({ 'request': 'watch', 'id': self.videoId }) def setSessionDescriptionAndStart(self, sessionId, data): try: peer = self._connectedPeers[sessionId] except KeyError: self._logger.warning('Peer with session [%s] is not found' % sessionId) peer = None self.sendEventToPeers('stopConnection') if peer: #Janus starting state self._connectedPeers[ sessionId].streamingPlugin.set_session_description( data['type'], data['sdp']) self._connectedPeers[sessionId].streamingPlugin.send_message( {'request': 'start'}) #able to serve video self.startGStreamer() def tickleIceCandidate(self, sessionId, candidate, sdp_mid, sdp_mline_index): self._connectedPeers[sessionId].streamingPlugin.add_ice_candidate( candidate, sdp_mid, sdp_mline_index) def pongCallback(self, data, key): if 'pong' != data: if 'error' in data: self._logger.error( 'Webrtc client lost: %s. Automatic peer session closing...', data['error']) self.closePeerSession(key) def pingPongRounder(self, params=None): for key in self._connectedPeers.keys(): if self._connectedPeers[key] != 'local': #sendRequestToClient(self, clientId, type, data, timeout, respCallback) boxrouterManager().sendRequestToClient( self._connectedPeers[key].clientId, 'ping', None, 10, self.pongCallback, [key]) def startGStreamer(self): #Start Gstreamer if not cameraManager().start_video_stream(): self._logger.error('Managing Gstreamer error in WebRTC object') self.stopJanus() def startJanus(self): #Start janus command here args = ['/opt/janus/bin/./janus'] try: self._JanusProcess = subprocess.Popen(args, stdout=subprocess.PIPE) except Exception, error: self._logger.error("Error initiating janus process: %s" % str(error)) self._JanusProcess = None self.sendEventToPeers('stopConnection') return False if self._JanusProcess: from requests import Session session = Session() response = None tryingCounter = 0 while response is None: time.sleep(0.3) try: response = session.post(url='http://127.0.0.1:8088', data={ "message": { "request": 'info', "transaction": 'ready' } }) except Exception, error: #self._logger.warn('Waiting for Janus initialization') tryingCounter += 1 if tryingCounter >= 100: self._logger.error(error) return False ready = signal('manage_fatal_error') ready.connect(self.closeAllSessions) #START TIMER FOR LOST PEERS self.peersDeadDetacher = interval(30.0, self.pingPongRounder, None) self.peersDeadDetacher.start() return True
def startJanus(self): with self._janusStartStopCondition: #Start janus command here if self._JanusProcess and self._JanusProcess.returncode is None: self._logger.debug('Janus was already running') return True #already running args = ['/usr/bin/janus', '-F', '/etc/astrobox/janus', '-C'] nm = networkManager() if nm.isOnline(): args.append('/etc/astrobox/janus/janus.cfg') else: args.append('/etc/astrobox/janus/janus.cfg.local') try: self._JanusProcess = subprocess.Popen(args, stdout=subprocess.PIPE) except Exception, error: self._logger.error("Error initiating janus process: %s" % str(error)) self._JanusProcess = None self.sendEventToPeers('stopConnection') if self._JanusProcess: self._logger.debug('Janus Starting...') response = None tryingCounter = 0 while response is None: time.sleep(0.3) try: response = requests.post(url='http://127.0.0.1:8088', data={ "message": { "request": 'info', "transaction": 'ready' } }) except Exception, error: self._logger.debug( 'Waiting for Janus initialization. Responded with: %s' % error) tryingCounter += 1 if tryingCounter >= 100: self._logger.error("Janus failed to start: %s" % error) return False self._logger.debug('Janus Started.') #Connect the signal for fatal errors when they happen ready = signal('manage_fatal_error_webrtc') ready.connect(self.closeAllSessions) #START TIMER FOR LOST PEERS self.peersDeadDetacher = interval(30.0, self.pingPongRounder, None) self.peersDeadDetacher.start() return True
def startJanus(self): with self._janusStartStopCondition: #Start janus command here if self._JanusProcess and self._JanusProcess.returncode is None: self._logger.debug('Janus was already running') return True #already running args = ['/usr/bin/janus', '-F', '/etc/astrobox/janus', '-C'] nm = networkManager() if nm.isOnline(): args.append('/etc/astrobox/janus/janus.cfg') else: args.append('/etc/astrobox/janus/janus.cfg.local') try: self._JanusProcess = subprocess.Popen( args, stdout=subprocess.PIPE ) except Exception, error: self._logger.error("Error initiating janus process: %s" % str(error)) self._JanusProcess = None self.sendEventToPeers('stopConnection') if self._JanusProcess: self._logger.debug('Janus Starting...') response = None tryingCounter = 0 while response is None: time.sleep(0.3) try: response = requests.post( url= 'http://127.0.0.1:8088', data= { "message":{ "request": 'info', "transaction": 'ready' } } ) except Exception, error: self._logger.debug('Waiting for Janus initialization. Responded with: %s' % error) tryingCounter += 1 if tryingCounter >= 100: self._logger.error("Janus failed to start: %s" % error) return False self._logger.debug('Janus Started.') #Connect the signal for fatal errors when they happen ready = signal('manage_fatal_error_webrtc') ready.connect(self.closeAllSessions) #START TIMER FOR LOST PEERS self.peersDeadDetacher = interval(30.0, self.pingPongRounder, None) self.peersDeadDetacher.start() return True