def __init__(self, id): super(ServerSocket, self).__init__(name='serversoc ') self.connection = None self.id = id try: self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # close gracefully from this end l_onoff = 1 l_linger = 0 self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', l_onoff, l_linger)) # and detect peers that didn't close gracefully with a reset self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) self.socket.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, 2) self.socket.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL, 2) self.socket.setsockopt(socket.SOL_TCP, socket.TCP_KEEPCNT, 2) self.socket.bind((util.local_ip(), 0)) self.socket.listen(1) except socket.error as e: if e.errno == 98: # Address already in use log.critical(str(e) + ' - cant start') raise e except Exception as e: log.critical('serversocket %s caught %s' % (self.id, str(e))) self.start()
def run(self): while not self.terminated: time.sleep(0.1) if self.server_lost_time < time.time(): log.critical('server lost') self.server_lost_time = time.time() + self.SERVER_LOST_SECONDS
def construct_pipeline(self): if self.pipeline: self.pipeline.set_state(Gst.State.NULL) try: # playing a sine wave through this source (always remember the volume or be prepared for a wakeup call): # gst-launch-1.0 audiotestsrc freq=1000 volume=0.004 is-live=true ! audioconvert ! audio/x-raw, channels=2 ! # faac ! aacparse ! avmux_adts ! tcpclientsink host=<hostname> port=4666 # # for playing the pipeline above directly on a second command line (without the server running): # gst-launch-1.0 tcpserversrc host=<hostname> port=4666 ! decodebin ! audioconvert ! alsasink # ip = util.local_ip() pipeline = 'tcpserversrc host=%s port=%i ! appsink name=appsink emit-signals=true sync=false' % \ (ip, self.port) log.info('launching %s pipeline listening at %s:%i' % (self.name, ip, self.port)) self.pipeline = Gst.parse_launch(pipeline) appsink = self.pipeline.get_by_name('appsink') appsink.connect('new-sample', self.new_sample) bus = self.pipeline.get_bus() bus.add_signal_watch() bus.enable_sync_message_emission() bus.connect('message', self.bus_message) self.pipeline.set_state(Gst.State.PLAYING) except Exception as e: log.critical("couldn't construct pipeline, %s" % str(e))
def construct_pipeline(self): try: if self.config['device']: device = 'device=%s' % self.config['device'] else: device = '' pipeline = 'alsasrc %s ! ' \ 'cutter name=cutter leaky=false run-length=%i threshold-dB=%f ! ' \ 'faac ! aacparse ! avmux_adts ! appsink name=appsink' % \ (device, int(float(self.config['timeout']) * util.NS_IN_SEC), float(self.config['threshold_dB'])) log.info('launching pipeline listening to alsa %s' % device) self.pipeline = Gst.parse_launch(pipeline) appsink = self.pipeline.get_by_name('appsink') appsink.set_property('emit-signals', True) appsink.connect('new-sample', self.new_sample) bus = self.pipeline.get_bus() bus.add_signal_watch() bus.enable_sync_message_emission() bus.connect('message', self.bus_message) bus.connect('message::element', self.cutter_message) self.pipeline.set_state(Gst.State.PLAYING) except Exception as e: log.critical("[%s] couldn't construct pipeline, %s" % (self.name, str(e)))
def parse(data): _json = None _audio = None if len(data) < header_length: return data, _json, _audio length = struct.unpack('!H', data[0:2])[0] type = struct.unpack_from('!B', data, 2)[0] _serial = struct.unpack_from('!B', data, 3)[0] data_length = len(data) if data_length >= length + header_length: payload = data[header_length:header_length + length] if type == Payload.AUDIO.value: if trace_packets: log.info('rx audio serial %i - %i bytes' % (_serial, data_length - header_length)) _audio = payload elif type == Payload.JSON.value: if trace_packets: log.info('rx json serial %i - %i bytes' % (_serial, data_length - header_length)) _json = json.loads(payload.decode()) elif type == Payload.FLUSHING.value: if trace_packets: log.info('rx flushing serial %i - %i bytes' % (_serial, data_length - header_length)) pass else: log.critical('got malformed data, %i bytes' % len(data)) log.critical(' '.join(format(x, '02x') for x in data[:min(500, len(data))])) raise util.MalformedPacketException data = data[header_length + length:] return data, _json, _audio
def state_changed(self, new_state): global AudioQueue if new_state == group.State.BUFFERING: self.silence_samples = 0 self.silence_samples_pending = 0 self.silence_samples_sent = 0 self.development_audio_drop_prescaler = 100 if self.m_state != new_state: log.debug('state changing from %s to %s' % (self.m_state, new_state)) self.m_state = new_state play_groups = self.playing_groups() for _group in play_groups: if new_state == group.State.BUFFERING: _group.send({'runtime': {'command': 'buffering'}}) elif new_state == group.State.STOPPED: _group.stop_playing() elif new_state == group.State.PLAYING: _group.start_playing() else: log.critical('internal error #0082') else: log.debug('ignoring a state change request from %s to %s' % (self.m_state, new_state))
def run(self): try: log.debug('player starting') while not self.terminated: time.sleep(0.1) if self.server_audio_state != ServerAudioState.STOPPED: self.pipeline_silence_monitor() if self.last_status_time and ( time.time() - self.last_status_time > 2.0): if self.playing_start_time and self.is_playing(): self.print_stats() if self.bytes_per_sec and self.nof_bps_messages: self.nof_bps_messages -= 1 log.debug( 'receiving %i bytes/sec%s' % (int(self.bytes_per_sec / 2.0), '' if self.nof_bps_messages else ' (automute)')) self.bytes_per_sec = 0 self.last_status_time += 2.0 except Exception as e: log.critical('player thread exception %s' % str(e)) log.debug('player exits')
def handleConnected(self): try: log.info('new websocket connection from %s' % self.address[0]) clients.append(self) emitter.send_message(self, {'command': 'connected'}) except Exception as e: log.critical('exception in handleConnected: %s' % str(e))
def set_play_time(self, play_time_ns): """ :param play_time_ns: the wall clock at which playing should start :return: False if the play time wasn't set """ try: now_ns = time.time() * util.NS_IN_SEC # If the server and client clocks are too far off then we might end up with a negative # relative playing start time which gstreamer understandably refuses to accept. If this is # the case then bail out now. if play_time_ns <= now_ns: log.critical( 'unable to start audio %3.1f seconds ago, server and client times are not in sync' % (now_ns - play_time_ns)) return False # Another sign of clock mismatches will be a start time too far in the future. For now it # will be a relative start time more than 1 second from now that triggers a log error. # For now don't bail out on this one. if play_time_ns > now_ns + util.NS_IN_SEC: log.error( 'will start audio in %3.1f seconds, server and client times are not in sync ?' % (now_ns - play_time_ns)) self.filter_pipeline.set_base_time( self.filter_pipeline.get_pipeline_clock().get_time() + play_time_ns - time.time() * util.NS_IN_SEC) except Exception as e: log.error(f'got fatal exception {e}') log.error( f'{self.filter_pipeline.get_pipeline_clock().get_time()} + {play_time_ns} - {time.time() * util.NS_IN_SEC}' ) raise e return True
def run(self): try: while not self.terminated: try: event = self.input_mux.event_poll() except queue.Empty: continue key = event['key'] value = event['value'] if key == 'audio': self.play_sequencer.new_audio(value) elif key == 'codec': self.play_sequencer.set_codec(value) elif key == 'state': self.play_sequencer.set_state(value) elif key == 'volume': self.play_sequencer.set_volume(value) else: log.critical('got an unknown key %s' % key) except Exception as e: log.critical("server loop caught exception '%s'" % str(e)) self.terminate() log.debug('server exits')
def execute(command): # log.debug('NOT executing "%s"' % command) # return 0 ret = subprocess.run(command, shell=True) if ret.returncode: log.critical('command failed with exitcode %i' % ret.returncode) return ret.returncode
def ctrl_c_handler(_, __): try: print(' ctrl-c handler') if _client: log.info('terminating by user') _client.terminate() _client.join() sys.exit(1) except Exception as e: log.critical('ctrl-c handler got ' + str(e))
def handleMessage(self): global emitter try: data = self.data log.debug('websocket message: %s' % data) message = json.loads(data) message['ip'] = self.address[0] emitter.emit('message', message) except Exception as e: log.critical('exception in handleMessage: %s' % str(e))
def cutter_message(self, bus, message): try: if message.has_name("cutter"): above = message.get_structure().get_value('above') if above: self.emit('status', 'rt_play') else: self.emit('status', 'rt_stop') except Exception as e: log.critical('[%s] parsing cutter message gave "%s"' % (self.name, str(e)))
def bus_message(self, bus, message): if message.type == Gst.MessageType.EOS: log.debug('EOS') elif message.type == Gst.MessageType.ERROR: err, deb = message.parse_error() log.critical("pipeline error: %s '%s'" % (err, deb)) self.emit('status', 'pipeline_error') elif message.type == Gst.MessageType.STATE_CHANGED: old_state, new_state, pending_state = message.parse_state_changed() if message.src == self.pipeline: log.debug('* pipeline state changed to %s' % Gst.Element.state_get_name(new_state))
def ctrl_c_handler(_, __): try: print(' ctrl-c handler') if _server: log.info('terminating by user') _server.terminate() log.debug('terminate done, waiting..') _server.join() sys.exit(1) except Exception as e: log.critical('ctrl-c handler got ' + str(e))
def cutter_message(self, bus, message): try: if message.has_name("cutter"): above = message.get_structure().get_value('above') if not above and self.is_playing: self.stop_playing() elif above and not self.is_playing: self.start_playing() except Exception as e: log.critical('[%s] parsing cutter message gave "%s"' % (self.name, str(e)))
def multicast_rx(self, message): command = message['command'] if command == 'server_socket': if not self.socket: endpoint = message['endpoint'] if endpoint == "None": log.critical("server refused the connection (check the group and device name)") time.sleep(1) util.die('exiting..', 1, True) log.info('server found, connecting to %s' % endpoint) self.server_endpoint = util.split_tcp(endpoint) self.start_socket()
def server_connector(self): delay = 0.1 connected = False while not self.terminated: if self.terminate_socket: self.socket_lock.acquire() self.terminate_socket = False if self.socket: self.socket.join() self.socket = None self.server_endpoint = None self.player.process_server_message({'runtime': {'command': 'stopping'}}) log.info('waiting for server connection') self.server_offline_counter = 10 self.socket_lock.release() if connected: self.hwctrl.connected_to_server(False) connected = False if not self.server_endpoint: if connected: self.hwctrl.connected_to_server(False) connected = False if self.server_offline_counter: self.server_offline_counter -= 1 if not self.server_offline_counter: log.critical('server seems to be offline') try: self.multicast.send({'command': 'get_server_socket', 'to': 'server', 'from': self.id, 'version': util.LUDIT_VERSION}) except OSError: log.warning('got a multicast send exception. Bummer.') if delay < 5.0: delay += 0.1 else: if not connected: self.hwctrl.connected_to_server(True) connected = True delay = 0.1 _delay = delay while _delay > 0.0 and not self.terminated: time.sleep(0.1) _delay -= 0.1 log.debug('server connector exits') return False
def launch_playsequencer(self): try: log.info('launching playsequencer') if self.play_sequencer: self.play_sequencer.terminate() self.play_sequencer = playsequencer.PlaySequencer( self.configuration) self.play_sequencer.connect('allgroupsdisconnected', self.all_groups_disconnected) self.cant_play_warning = 5 except Exception as e: log.critical('playsequencer failed with %s' % str(e))
def transfer_to_game(cmd, request, conn): conn_id = conn.get('id', None) conn_ip = conn.get('ip', None) conn_port = conn.get('port', None) # logger.debug('cmd:%s', cmd) # 登录消息绑定这些 if cmd == 1001: # 组装传到内部的消息 request = dict( body=request, connid=conn_id, ip=conn_ip, ) # 为了适配微信登录和绑定 elif cmd == 1002: uin = FireflyMap().get_user_by_conn(conn_id) request = dict( body=request, connid=conn_id, ip=conn_ip, uin=uin, ) elif cmd >= 4001: # 内部消息不做任何处理 if cmd == proto.CMD_TIME_OUT_CHECK: pass else: # 没有inner说明是外部消息 if not isinstance(request, dict) or 'inner' not in request: uin = FireflyMap().get_user_by_conn(conn_id) if not uin: logger.critical('not found user, cmd:%s, conn_id:%s, ip:%s, port:%s', cmd, conn_id, conn_ip, conn_port) return request = dict( body=request, uin=uin, ) # 到时候调试好了记得把desk加进来 # if 9999 >= cmd >= 7001: # request['desk'] = # 分发消息到game server if cmd in range(1001, 4001): return GlobalObject().root.callChild("_auth_", "auth_function_" + str(cmd), request) elif cmd in range(4001, 7001): return GlobalObject().root.callChild("_hall_", "hall_function_" + str(cmd), request) elif cmd in range(7001, 10001): return GlobalObject().root.callChild("_play_", "play_function_" + str(cmd), request) elif cmd in range(10001, 13001): return GlobalObject().root.callChild("_common_", "common_function_" + str(cmd), request)
def run(self): while not self.terminated: try: self.loop.run_until_complete(self.ws_listen()) except ConnectionRefusedError: pass except websockets.ConnectionClosed: log.info('mopidy websocket was closed') except Exception as e: log.critical('unexpected exception in sourcemopidy, %s' % str(e)) time.sleep(1) log.debug('sourcemopidy exits')
async def ws_listen(self): address = util.tcp2str((self.mopidy_address, self.mopidy_port)) async with websockets.connect('ws://%s/mopidy/ws' % address) as self.ws: try: log.info('connected to mopidy websocket') while 1: response = await self.ws.recv() message = json.loads(response) event = message['event'] try: uri = message['tl_track']['track']['uri'] except KeyError: uri = '' if event == 'track_playback_started': log.info('mopidy started ' + uri) self.start_playing() elif event == 'track_playback_ended': log.info('mopidy stopped ' + uri) self.stop_playing() elif event == 'track_playback_paused': log.info('mopidy paused ' + uri) self.stop_playing() elif event == 'track_playback_resumed': log.info('mopidy resumes ' + uri) self.start_playing() elif event == 'playback_state_changed': old_state = message['old_state'] new_state = message['new_state'] log.info('mopidy state change from %s to %s' % (old_state, new_state)) elif event == 'volume_changed': volume = message['volume'] if volume != self.volume: self.volume = volume log.info('mopidy volume %i' % volume) self.new_volume(volume) elif event == 'tracklist_changed': pass else: log.info('mopidy event not recognized: %s' % message) except Exception as e: log.critical('sourcespotify caught %s' % str(e)) raise e log.debug('sourcemopidy websocket exits')
def run(self): while not self.terminated: try: time.sleep(0.1) if self.timeout_counter: self.timeout_counter -= 1 if not self.timeout_counter: log.warning( 'timeout from source "%s", no data for 4 seconds' % self.now_playing) self.stop_playing() except Exception as e: log.critical('exception in inputmux, %s' % str(e)) log.debug('inputmux exits')
def run(self): try: while not self.terminated: self.construct_pipeline() while not self.eos and not self.terminated: time.sleep(0.1) if self.eos: self.send_event('state', 'stop') self.eos = False except Exception as e: log.critical("source %s exception '%s'" % (self.source_name(), str(e))) self.terminate() log.debug('sourcetcp exits')
def bus_message(self, bus, message): try: if message.type == Gst.MessageType.EOS: log.debug('EOS') elif message.type == Gst.MessageType.ERROR: err, deb = message.parse_error() log.critical("pipeline error: %s '%s'" % (err, deb)) self.send_event('status', 'pipeline_error') elif message.type == Gst.MessageType.STATE_CHANGED: old_state, new_state, pending_state = message.parse_state_changed( ) if message.src == self.pipeline: log.debug('pipeline state changed to %s' % Gst.Element.state_get_name(new_state)) except Exception as e: log.critical('[%s] parsing bus message gave "%s"' % (self.name, str(e)))
def state_changed(self, new_state): global AudioQueue if self.m_state != new_state: log.debug('state changing from %s to %s' % (self.m_state, new_state)) self.m_state = new_state now = time.time() for _group in self.playing_groups(): if new_state == group.State.BUFFERING: _group.send({'runtime': {'command': 'buffering'}}) elif new_state == group.State.STOPPED: _group.stop_playing() elif new_state == group.State.PLAYING: _group.start_playing(now) else: log.critical('internal error #0082') else: log.debug('ignoring a state change request from %s to %s' % (self.m_state, new_state))
def run(self): try: while not self.terminated: try: data = self.socket.recv(1024) except socket.timeout: continue message = json.loads(data) try: self.emit('socket_receive', message) except Exception as e: log.critical('emit message failed with %s' % str(e)) except Exception as e: log.critical('multicast got ' + str(e)) self.socket.close() log.debug('multicast exits')
def run(self): try: log.debug('player starting') while not self.terminated: time.sleep(0.1) if self.server_audio_state != ServerAudioState.STOPPED: self.pipeline_monitor() if (self.is_playing() and self.last_status_time and (time.time() - self.last_status_time > 2)): self.last_status_time = time.time() self.print_stats() except Exception as e: log.critical('player thread exception %s' % str(e)) log.debug('player exits')
def process_message(self, message): command = message['command'] if command == 'setcodec': self.codec = message['codec'] log.info("setting codec to '%s'" % self.codec) self.realtime = False self.start_pipelines() elif command == 'setvolume': volume = int(message['volume']) / 127.0 log.debug('setting volume %.3f' % volume) self.set_volume(volume) elif command == 'configure' or command == 'setparam': param = message['param'] self.set_pipeline_parameter(param) else: log.critical("got unknown server command '%s'" % command)