Пример #1
0
def stop_servers():
    logger = InfoLogger(__name__).get_logger()
    # logger.info('Servers to stop: %d' % len(Servers.server_threads))

    for ins_name, thread in Servers.server_threads.iteritems():
        thread.stop()
        logger.info('Stop server : %s' % ins_name)
Пример #2
0
class BaseConnection(object):
    def __init__(self, stream, address, delimiter):
        self.logger = InfoLogger(__name__).get_logger()
        self.name = self.__class__.__name__

        self.delimiter = delimiter

        self._stream = stream
        self._address = address

        self._stream.set_close_callback(self.on_close)
        self.read_message()

    def read_message(self):
        # self.logger.info("In read_message, %r" % self.delimiter)
        self._stream.read_until(self.delimiter, self.on_message_read)

    def on_message_read(self, data):
        pass

    # def send_to_ws(self, data, robot_uid):
    #     """Send to broswer through websocket"""
    #     pass

    def on_close(self):
        self.logger.info('[%s] client close: %s' % (self.name, str(self._address)))
Пример #3
0
def run_video_feed(robot_uid, sock, func, handle):
    logger = InfoLogger(__name__).get_logger()
    logger.info('[Video] run_video_feed start')

    try:
        while True:

            try:
                select.select([], [sock], [])
            except socket.error:
                logger.info('[Video] socket shutdown')
                break

            # image_container = yield func(handle)
            image_container = func(handle)
            image_data_lst = format_image_data(image_container)
            
            image_uid = uuid.uuid4().hex

            for image_dct in image_data_lst:
                send_data = format_send_data(robot_uid, image_uid, image_dct)
                sock.sendall(send_data)

            # logger.info('[Video] run_video_feed done')

    except Exception as e:
        logger.info('[Video] run_video_feed error : %s' % e)

    logger.info('[Video] run_video_feed exit done')
Пример #4
0
def run_audio_stream(robot_uid, sock, proc):
    logger = InfoLogger(__name__).get_logger()
    logger.info('[Audio] run_audio_stream start')

    try:
        while True:
            if proc.poll():
                break

            output = proc.stdout.read(ConfigAudio.buffer_size)

            try:
                select.select([], [sock], [])
            except socket.error:
                logger.info('[Audio] socket shutdown')
                break

            format_data = format_send_data(robot_uid, output)
            sock.sendall(format_data)

            # logger.info('[Audio] send output : %s' % format_data)

    except Exception as e:
        logger.info('[Audio] run_audio_stream error : %s' % e)

    if not proc.poll():
        proc.terminate()
    #     proc.kill()

    logger.info('[Audio] run_audio_stream exit done')
Пример #5
0
class BaseTCPServer(TCPServer):
    def __init__(self, port, connection):
        super(BaseTCPServer, self).__init__()

        self.name = self.__class__.__name__
        self.logger = InfoLogger(self.name).get_logger()

        self.port = port
        self.connection = connection

    def handle_stream(self, stream, address):
        self.logger.info("[%s] new connection: %s %s" % (self.name, address, stream))
        self.connection(stream, address)

    def start(self):
        try:
            self.logger.info("[%s] starting at port %s" % (self.name, self.port))

            self.listen(self.port)
            self.logger.info("[%s] socket setup done" % self.name)

            ioloop = IOLoop()
            ioloop.current().start()

        except Exception as e:
            self.logger.info("[%s] start error: %s" % (self.name, e))
Пример #6
0
    def start_server_thread(cls, server_ins):
        ins_name = server_ins.__class__.__name__

        if ins_name in cls.server_threads:
            return

        thread = ServerThread(server_ins)

        thread.setName('Thread-%s' % ins_name)
        cls.server_threads[ins_name] = thread

        logger = InfoLogger(__name__).get_logger()
        logger.info('server_threads count : %d' % len(cls.server_threads))

        thread.start()
Пример #7
0
class WebsocketServer(object):
    def __init__(self):
        self.logger = InfoLogger(__name__).get_logger()
        # self.ioloop = IOLoop()

        self.shell = ConfigSSH.local_ws_shell
        self.port = ConfigSSH.local_ws_port

        self.height = ConfigSSH.height
        self.width = ConfigSSH.width
        self.winheight = ConfigSSH.winheight
        self.winwidth = ConfigSSH.winwidth

        self.max_terminals = ConfigSSH.max_terminals

        self.running = False

    def start(self):
        self.logger.info('Starting websocket server')

        term_settings = {
            'height': self.height,
            'width': self.width,
            'winheight': self.winheight,
            "winwidth": self.winwidth,
        }

        # term_manager = SingleTermManager(shell_command=[self.shell])
        term_manager = UniqueTermManager(shell_command = [self.shell], \
            max_terminals = self.max_terminals, term_settings = term_settings)

        handlers = [
            # (r"/websocket", MyTermSocket, {'term_manager': term_manager}),
            # (r"/websocket", TermSocket, {'term_manager': term_manager}),
            (r"/websocket/([^/]*)", TermSocket, {
                'term_manager': term_manager
            }),
        ]

        app = tornado.web.Application(handlers)

        app.listen(self.port)
        self.logger.info('Listen on port ' + str(self.port))

        self.running = True
        self.logger.info('Start websocket server done')

        # self.ioloop.current().start()
        IOLoop.current().start()

    def stop(self):
        # self.ioloop.current().stop()
        IOLoop.current().stop()
        self.running = False
        self.logger.info('Stop websocket server done')

    def is_running(self):
        return self.running
Пример #8
0
def run_write_client(sock, ws_connect):
    logger = InfoLogger(__name__).get_logger()
    logger.info('[writer] start')

    ws = yield ws_connect

    while True:
        try:
            recv_sock = sock.recv(1024)
            # logger.info('[writer] recv_sock : %r' % recv_sock)

            if recv_sock:
                msg_list = recv_sock.split(ConfigSSH.delimiter)

                for msg_str in msg_list:
                    # msg_str may be '', if json loads failed, continue to next one
                    try:
                        msg_dict = json.loads(msg_str)
                    except:
                        continue

                    msg = msg_dict.get('msg', None)

                    if msg:
                        # yield ws.write_message(msg)
                        ws.write_message(msg)
                        # logger.info('[writer] write to ws : %r' % msg)
                    else:
                        logger.info('[writer] read no msg from sock : %r' %
                                    msg)

            else:
                # sock.shutdown(socket.SHUT_RDWR) is called
                logger.info('[writer] socket shutdown')

                # send to ws, let run_read_client know and exit
                ws.write_message(r'["stdin", "\r"]')

                break

        except Exception as e:
            logger.info('[writer] error: %s' % e)
            break

    logger.info('[writer] exit done')
Пример #9
0
def run_read_client(sock, ws_connect, robot_uid, term_id):
    logger = InfoLogger(__name__).get_logger()
    logger.info('[reader] start')

    ws = yield ws_connect

    pairs = SocketMap.pairs.get(term_id, None)
    if pairs:
        pairs['websocket'] = ws
        SocketMap.pairs[term_id] = pairs

    while True:
        try:
            msg = yield ws.read_message()
            # logger.info('[reader] ws.read_message : %r' % msg)

            # ws server may return None after UnicodeDecodeError raised
            # if msg is None:
            #     break

            if msg:
                # make sure the socket is not closed
                try:
                    select.select([], [sock], [])
                except socket.error:
                    logger.info('[reader] socket shutdown')
                    break

                sock_msg = format_sock_msg(robot_uid, term_id, msg)
                sock.sendall(sock_msg)

                # logger.info('[reader] send to sock : %r' % sock_msg)
            else:
                logger.info('[reader] read no msg from ws : %r' % msg)
                break

        except Exception as e:
            logger.info('[reader] error: %s' % e)
            # break
            continue

    logger.info('[reader] exit done')
Пример #10
0
class ServerThread(threading.Thread):
    def __init__(self, server_ins):
        super(ServerThread, self).__init__()
        self.server_ins = server_ins
        self._stop = threading.Event()

        self.logger = InfoLogger(__name__).get_logger()

    def stop(self):
        self._stop.set()

    def stopped(self):
        return self._stop.isSet()

    def run(self):
        thread_name = threading.currentThread().getName()
        server_name = self.server_ins.__class__.__name__
        self.logger.info('[%s] Run server=%s' % (thread_name, server_name))

        self.server_ins.start()
Пример #11
0
class PuppetWebSocketServer(object):
    def __init__(self):
        self.logger = InfoLogger(__name__).get_logger()
        self.host = ConfigWebSocket.host
        self.port = ConfigWebSocket.port

    def start(self):
        try:
            app = Application([
                (r'/puppet', PuppetWebSocketHandler),
                (r'/puppet/ssh/([^/]*)', SSHWebSocketHandler),
                (r'/puppet/video/([^/]*)', VideoWebSocketHandler),
                (r'/puppet/audio/([^/]*)', AudioWebSocketHandler),
            ])
            self.logger.info("PuppetWebSocket Handler setup done")

            if ConfigSSL.enable:
                app.listen(address=self.host,
                           port=self.port,
                           ssl_options={
                               "certfile": ConfigSSL.certfile,
                               "keyfile": ConfigSSL.keyfile,
                           })
            else:
                app.listen(address=self.host, port=self.port)
            self.logger.info('Listening ws at ' + str(self.host) + ':' +
                             str(self.port))

            ioloop = IOLoop()
            ioloop.current().start()

        except Exception as e:
            self.logger.info("PuppetWebSocketServer start error: %s" % e)
Пример #12
0
def run_media_stream(robot_uid, ff_obj):
    logger = InfoLogger(__name__).get_logger()
    logger.info('[Media] run_media_stream start')

    try:
        ff_obj.run()

    except Exception as e:
        logger.info('[Media] run_media_stream error : %s' % e)

    logger.info('[Media] run_media_stream exit done')
Пример #13
0
class Manager(object):
    def __init__(self):
        self.pid_file = ConfigManager.pid_file
        self.logger = InfoLogger(__name__).get_logger()

    def set_pid(self, pid):
        with open(self.pid_file, 'a') as f:
            f.write(str(pid) + '\n')

    def get_pid(self):
        if not os.path.exists(self.pid_file):
            return []

        pids = [
            int(pid.rstrip('\n'))
            for pid in open(self.pid_file, 'r').readlines()
        ]
        return pids

    def kill_process(self, pid=None):
        if pid:
            pids = [pid]
        else:
            pids = self.get_pid()

        try:
            for pid in pids:
                self.logger.info("Stopping pid %s" % pid)

                try:
                    os.kill(pid, signal.SIGTERM)

                except OSError, err:
                    if err.errno == errno.ESRCH:
                        self.logger.info("pid %s not running" % pid)
                        continue

                self.logger.info("Stop pid %s done" % pid)

            # clear file
            with open(self.pid_file, 'w') as f:
                f.write('')

            return "Done"

        except OSError, err:
            # if err.errno == errno.ESRCH:
            #     return "Not running"
            if err.errno == errno.EPERM:
                return "No permission to signal this process!"
            else:
                return "Unknown error"
Пример #14
0
def run_video_feed(func, handle, image_pipe):
    logger = InfoLogger(__name__).get_logger()
    logger.info('[Media] run_video_feed start')

    try:
        while not image_pipe.is_closed():
            image_container = func(handle)
            image_pipe.write(image_container[6])

    except Exception as e:
        logger.info('[Media] run_video_feed error : %s' % e)

    logger.info('[Media] run_video_feed exit done')
Пример #15
0
def run_audio_feed(proc, audio_pipe):
    logger = InfoLogger(__name__).get_logger()
    logger.info('[Media] run_audio_feed start')

    try:
        while not audio_pipe.is_closed():
            # audio_pipe.write(proc.stdout.read(80))
            audio_pipe.write(proc.stdout.readline())

    except Exception as e:
        logger.info('[Media] run_audio_feed error : %s' % e)

    logger.info('[Media] run_audio_feed exit done')
Пример #16
0
class BaseHTTPServer(object):
    def __init__(self, port):
        self.name = self.__class__.__name__
        self.logger = InfoLogger(self.name).get_logger()

        self.port = port

    def set_app(self, app_tup_lst):
        app = Application(app_tup_lst)
        self.logger.info("[%s] app setup done" % self.name)
        return app

    def set_server(self, app):
        server = HTTPServer(app)

        if ConfigSSL.enable:
            server = HTTPServer(app, 
                ssl_options = {
                    "certfile" : ConfigSSL.certfile,
                    "keyfile" : ConfigSSL.keyfile,
                }
            )
        else:
            server = HTTPServer(app)

        server.listen(self.port)
        return server

    def start(self, app_tup_lst):
        try:
            app = self.set_app(app_tup_lst)
            server = self.set_server(app)

            self.logger.info("[%s] listen at port: %s" % (self.name, str(self.port)))

            ioloop = IOLoop()
            ioloop.current().start()

        except Exception as e:
            self.logger.info("[%s] start error: %s" % (self.name, e))
Пример #17
0
def stop_servers():
    logger = InfoLogger(__name__).get_logger()
    # logger.info('Servers to stop: %d' % len(Servers.server_threads))

    for ins_name, thread in Servers.server_threads.iteritems():
        thread.stop()
        logger.info('Stop server : %s' % ins_name)


# -----------------------------------------
# Get args from shell
# -----------------------------------------

if args.run:
    logger = InfoLogger(__name__).get_logger()
    logger.info('Start running Puppet servers')

    pid = os.getpid()

    manager = Manager()
    manager.set_pid(pid)

    start_servers()

elif args.restart:
    logger = InfoLogger(__name__).get_logger()
    logger.info('Restart running Puppet servers')

    logger.info('Stopping Puppet servers')

    stop_servers()
Пример #18
0
def stop_servers():
    logger = InfoLogger(__name__).get_logger()

    for server_name, thread in Servers.server_threads.items():
        thread.stop()
        logger.info('Stop server : %s' % server_name)
Пример #19
0
            #     return "Not running"
            if err.errno == errno.EPERM:
                return "No permission to signal this process!"
            else:
                return "Unknown error"


if args.run:
    logger = InfoLogger(__name__).get_logger()
    start_servers()

    pid = os.getpid()

    manager = Manager()
    result = manager.kill_process()
    logger.info('Stop clients : %s' % result)
    
    manager.set_pid(pid)
    
    client = Client()
    client.connect()

elif args.restart:
    logger = InfoLogger(__name__).get_logger()

    stop_servers()
    logger.info('Stop servers done')

    manager = Manager()
    result = manager.kill_process()
    logger.info('Stop clients : %s' % result)
Пример #20
0
class Client(object):
    def __init__(self):
        self.server_host = ConfigServer.host
        self.server_port = ConfigServer.port
        self.delimiter = ConfigServer.delimiter
        self.timeout = ConfigServer.timeout
        self.reconnect_delta = ConfigServer.reconnect_delta

        self.collector_handle_delta = ConfigCollector.handle_delta

        self.logger = InfoLogger(__name__).get_logger()

        self.thread_stop = False

        self.collector = Collector()
        self.executor = Executor()

    def connect(self):
        self.logger.info('start connect')

        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(self.timeout)

        try:
            sock.connect((self.server_host, self.server_port))

            self.logger.info('connect success')

            self.setup_threads(sock)

        except KeyboardInterrupt:
            self.logger.info('Got Ctrl+C, exiting...')
            self.stop_all_thread()
            self.disconnect(sock)

        except socket.timeout:
            self.logger.info('socket connect timeout, reconnect')
            self.reconnect()

        except socket.error as s_error:
            # [Errno 111] Connection refused: client is starting, server is down
            # [Errno 32] Broken pipe: client is running, server is down
            if s_error.errno in (errno.ECONNREFUSED, errno.EPIPE):
                self.logger.info('socket connect error, try to reconnect')
                self.logger.info(str(s_error))
                self.reconnect()
            else:
                raise

        except Exception as e:
            self.logger.info('Client connect error: %s' % e)

    def disconnect(self, sock):
        try:
            sock.close()
            self.logger.info('disconnect done')
        except:
            # sock is not available
            pass

    def reconnect(self):
        try:
            self.logger.info('try to reconnect socket')

            self.stop_all_thread()
            time.sleep(self.reconnect_delta)

            self.connect()

        except Exception as e:
            self.logger.info('Client reconnect error: %s' % e)

    def setup_threads(self, sock):
        try:
            self.logger.info('Setup new threads')
            self.thread_stop = False

            collector_thread = threading.Thread( \
                target = self.run_collector_thread, \
                kwargs = {'sock' : sock, 'stop' : lambda: self.thread_stop})

            executor_thread = threading.Thread( \
                target = self.run_executor_thread, \
                kwargs = {'sock' : sock, 'stop' : lambda: self.thread_stop})

            collector_thread.daemon = False
            executor_thread.daemon = False

            collector_thread.start()
            executor_thread.start()

            while collector_thread.isAlive() or executor_thread.isAlive():
                collector_thread.join(10)
                executor_thread.join(10)

        except Exception as e:
            self.logger.info('setup_threads error: %s' % e)

    def stop_all_thread(self):
        self.thread_stop = True

    def run_collector_thread(self, sock, stop):
        try:
            while 1:
                data = self.collect_data()
                sock.sendall(data)

                time.sleep(self.collector_handle_delta)

                if stop():
                    self.logger.info('collector stopped')
                    break

        except socket.error as s_error:
            if s_error.errno == errno.EPIPE:
                self.logger.info('collector get broken pipe, stopped, try to reconnect')
                self.reconnect()

            elif s_error.errno == errno.ETIMEDOUT:
                self.logger.info('collector socket connect timeout, try to reconnect')
                self.reconnect()

            else:
                self.logger.info('run_collector_thread error: %s' % s_error)
                raise

        except Exception as e:
            self.logger.info('run_collector_thread error: %s' % e)

    def run_executor_thread(self, sock, stop):
        try:
            while 1:
                try:
                    data = sock.recv(1024)

                except socket.timeout:
                    if stop():
                        self.logger.info('executor stopped')
                        break
                    else:
                        continue

                self.logger.info('Receive data : %r' % data)

                if data:
                    res = self.executor.command_explain(data)

                    if res:
                        res_format = self.format_data(res)
                        sock.sendall(res_format)

                else:
                    # Server stopped, received an empty string 
                    self.logger.info('executor receive empty data from server, stopped')
                    break

        except Exception as e:
            self.logger.info('run_executor_thread error: %s' % e)

    def collect_data(self):
        try:
            data = self.format_data(self.collector.combine_robot_info())
            
        except Exception as e:
            self.logger.info('collect_data error: %s' % e)
            data = ''

        return data

    def format_data(self, data):
        return str(data) + self.delimiter
Пример #21
0
class ClientProxy(object):
    def __init__(self, robot_uid):
        self.logger = InfoLogger(__name__).get_logger()

        self.robot_uid = robot_uid
        self.running = False

    def start(self, term_id):
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.connect((ConfigSSH.sock_host, ConfigSSH.sock_port))

            SocketMap.pairs.setdefault(term_id, {
                'socket': sock,
                'websocket': None
            })
            self.logger.info('socket connect done')

            # socket init send, let cloud server know where the client comes from
            sock_init = format_sock_msg(self.robot_uid, term_id)
            sock.sendall(sock_init)

            # create ws connect here to make sure only a term socket is opened
            ws_connect = websocket_connect(ConfigSSH.local_ws + '/' + term_id)

            write_thread = threading.Thread( \
                target = start_write_client, \
                kwargs = {'sock' : sock, 'ws_connect' : ws_connect})

            read_thread = threading.Thread( \
                target = start_read_client, \
                kwargs = {'sock' : sock, 'ws_connect' : ws_connect,\
                          'robot_uid' : self.robot_uid, 'term_id' : term_id})

            self.logger.info('read/write thread setup done')

            write_thread.start()
            read_thread.start()

            self.running = True
            self.logger.info('ClientProxy start done')

        except Exception as e:
            self.logger.info('ClientProxy.start error : %s' % e)

    def stop(self, term_id):
        sock = SocketMap.pairs.get(term_id, {}).get('socket', None)

        if sock:
            try:
                # shutdown will send '' to socket,
                # writer can cache and exit
                sock.shutdown(socket.SHUT_RDWR)

                sock.close()
                self.logger.info('stop socket done')

            except Exception as e:
                self.logger.info('stop socket error : %s' % e)

        else:
            self.logger.info('no socket to stop')

        ws = SocketMap.pairs.get(term_id, {}).get('websocket', None)

        if ws:
            ws.close()

        self.running = False
        self.logger.info('ClientProxy stop done')

    def is_running(self):
        return self.running

    def restart(self, term_id):
        self.stop(term_id)
        time.sleep(1)
        self.start(term_id)
Пример #22
0
class VideoFeedProxy(object):
    def __init__(self, robot_uid):
        self.logger = InfoLogger(__name__).get_logger()

        self.host = ConfigVideo.host
        self.port = ConfigVideo.port
        self.robot_uid = robot_uid

        self.sock = None

    def start(self, func, handle):
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.connect((self.host, self.port))
            self.logger.info('video_feed socket setup done')

            self.sock = sock

            v_thread = threading.Thread( \
                target = start_video_feed, \
                kwargs = {'robot_uid' : self.robot_uid, 'sock' : sock,
                          'func' : func, 'handle' : handle})

            v_thread.start()

            self.logger.info('VideoProxy start done')

        except Exception as e:
            self.logger.info('VideoProxy.start error : %s' % e)

    def stop(self):

        if self.sock:
            try:
                # shutdown will send '' to socket, 
                # writer can cache and exit
                self.sock.shutdown(socket.SHUT_RDWR)

                self.sock.close()
                # self.sock = None
                self.logger.info('VideoProxy stop socket done')

            except Exception as e:
                self.logger.info('VideoProxy stop socket error : %s' % e)

        else:
            self.logger.info('VideoProxy no socket to stop')

        self.logger.info('VideoProxy stop done')
Пример #23
0
class Executor(object):
    def __init__(self):
        self.logger = InfoLogger(__name__).get_logger()

        self.sys_command = SystemCommand()
        self.behavior_command = BehaviorCommand()
        self.package_command = PackageCommand()
        self.video_command = VideoCommand()
        self.demo_command = DemoCommand()
        self.ssh_command = SSHCommand()
        self.audio_command = AudioCommand()
        self.media_command = MediaCommand()

        self.command_maps = (
            self.sys_command,
            self.behavior_command,
            self.package_command,
            self.video_command,
            self.demo_command,
            self.ssh_command,
            self.audio_command,
            self.media_command,
        )

    def get_command_func(self, command):
        # command_map = {
        #     'reboot'      : self.sys_command.reboot,
        #     'shutdown'    : self.sys_command.shutdown,
        #     'change_pw'   : self.sys_command.change_pw,
        #     'change_name' : self.sys_command.change_name,
        #     'basic_awareness_enable'  : self.sys_command.basic_awareness_enable,
        #     'basic_awareness_disable' : self.sys_command.basic_awareness_disable,
        #     'set_output_vol' : self.sys_command.set_output_vol,
        #     'rest'    : self.sys_command.rest,
        #     'wake_up' : self.sys_command.wake_up,

        #     'count_off' : self.demo_command.count_off,
        #     'where_are_you' : self.demo_command.where_are_you,
        # }

        # return command_map.get(command, None)

        for command_cls in self.command_maps:
            if hasattr(command_cls, command):
                return getattr(command_cls, command)

        return None

    def command_explain(self, command_string):
        try:
            exec_szer = ExecutorSerializer()
            exec_obj = exec_szer.parse_from_string(command_string)

            command = exec_obj.executor.command
            args = exec_obj.executor.args
            origin = exec_obj.executor.origin

            self.logger.info('command: %s' % command)
            self.logger.info('args: %s' % str(args))
            self.logger.info('origin: %s' % origin)

            res = None
            exception = None

            func = self.get_command_func(command)

            if func:
                taken_args = inspect.getargspec(func).args

                try:
                    # taken_args : ['self', ...]
                    if len(taken_args) > 1:
                        res = func(args)
                    else:
                        res = func()

                    self.logger.info('Command excuted')

                except Exception as e:
                    self.logger.info('Executor run func error: %s' % e)
                    exception = str(e)

                try:
                    format_res = json.dumps(res)
                except:
                    format_res = str(res)

                raiser_szer = RaiserSerializer()
                raiser_str = raiser_szer.dict_to_string({
                    'command':
                    command,
                    'args':
                    args,
                    'origin':
                    origin,
                    'response':
                    format_res,
                    'exception':
                    str(exception),
                })

                self.logger.info('raiser_str: %r' % raiser_str)

                return raiser_str

        except Exception as e:
            self.logger.info('Executor command explain error: %s' % e)
Пример #24
0
class MediaStreamProxy(object):
    def __init__(self, robot_uid):
        self.logger = InfoLogger(__name__).get_logger()

        self.robot_uid = robot_uid

        self.host = ConfigMedia.host
        self.port = ConfigMedia.port
        self.path = ConfigMedia.path

        self.a_format = ConfigMedia.a_format
        self.analyze_duration = ConfigMedia.analyze_duration

        self.v_format = ConfigMedia.v_format
        self.pix_fmt = ConfigMedia.pix_fmt
        self.v_resolution = ConfigMedia.v_resolution

        self.audio_codec = ConfigMedia.audio_codec
        self.audio_bitrate = ConfigMedia.audio_bitrate
        self.strict_lvl = ConfigMedia.strict_lvl

        self.video_bitrate = ConfigMedia.video_bitrate
        self.output_format = ConfigMedia.output_format

        self.a_proc = None
        self.v_thread = None
        self.a_thread = None

        self.ff = None
        self.m_thread = None

        self.image_pipe = None
        self.audio_pipe = None

    def start(self, func, handle, bit_dict=None):
        try:
            self.image_pipe = ImagePipe()
            self.audio_pipe = AudioPipe()

            # Video thread
            self.v_thread = threading.Thread( \
                target = run_video_feed,      \
                kwargs = {'func' : func, 'handle' : handle, 
                          'image_pipe' : self.image_pipe})

            # Pipe for media stream
            audio_pipe_r = self.audio_pipe.get_read_pipe()
            image_pipe_r = self.image_pipe.get_read_pipe()

            audio_input = 'pipe:%s' % str(audio_pipe_r)
            image_input = 'pipe:%s' % str(image_pipe_r)

            # Cover bitrate config from args
            if bit_dict:
                self.audio_bitrate = bit_dict.get('audio_bitrate')
                self.video_bitrate = bit_dict.get('video_bitrate')

            # -re (input) : Read input at native frame rate. 
            # Set analyzeduration to 0 for audio to disable analyze delay
            audio_args = '-f {f} -analyzeduration {ad} -re'.format(
                f = self.a_format, ad = self.analyze_duration)

            image_args = '-f {f} -pix_fmt {pf} -s:v {sv} -re'.format(
                f = self.v_format, pf = self.pix_fmt, sv = self.v_resolution)

            # For dev
            # receiver = '/tmp/test.flv'
            # if os.path.exists(receiver):
            #     os.unlink(receiver)
            receiver = 'rtmp://' + self.host + ':' + str(self.port) + \
                self.path + str(self.robot_uid)

            # -c:a : audio codec, must be set in output
            # -b:a : audio bitrate
            # -b:v : video bitrate
            # output total bitrate = (video bitrate + audio bitrate)kbits/s
            # -muxdelay seconds   : Set the maximum demux-decode delay.
            # -muxpreload seconds : Set the initial demux-decode delay.
            receiver_args = """-map 0 -c:a {ca} -strict -{s} -b:a {ba}
                               -map 1 -b:v {bv} 
                               -f {f} -muxdelay 0.1 -muxpreload 0""".\
                format(ca = self.audio_codec, s = self.strict_lvl, 
                       ba = self.audio_bitrate, bv = self.video_bitrate,
                       f = self.output_format)

            ff_input = OrderedDict(
                [ (audio_input, audio_args), (image_input, image_args), ]
            )
            ff_output = {receiver : receiver_args,}

            self.ff = ffmpy.FFmpeg(inputs = ff_input, outputs = ff_output)
            self.logger.info('[MediaStreamProxy] ff.cmd : %s' % self.ff.cmd)

            self.m_thread = threading.Thread( \
                target = run_media_stream, \
                kwargs = {'robot_uid' : self.robot_uid, 'ff_obj' : self.ff})

            # Audio related
            # Do not use stdout=PIPE or stderr=PIPE with this function as 
            # that can deadlock based on the child process output volume.
            # Use Popen with the communicate() method when you need pipes.
            a_command = 'arecord -f cd -t {a_format}'.format(a_format = self.a_format)
            self.a_proc = subprocess.Popen(shlex.split(a_command), \
                stdout = self.audio_pipe.get_write_pipe())

            self.m_thread.start()
            self.v_thread.start()

            self.logger.info('[MediaStreamProxy] start done')

        except Exception as e:
            self.logger.info('[MediaStreamProxy] start error : %s' % e)

    def stop(self):
        try:
            # Close working pipes
            if self.image_pipe:
                self.image_pipe.close()
                self.logger.info('[MediaStreamProxy] close image_pipe done')

            if self.audio_pipe:
                self.audio_pipe.close()
                self.logger.info('[MediaStreamProxy] close audio_pipe done')

            # Stop audio process
            if self.a_proc:
                self.a_proc.terminate()
                # self.a_proc.kill()

                # Use wait() to terminate the defunct process
                self.a_proc.wait()
                self.logger.info('[MediaStreamProxy] stop audio proc done')

            # Stop ffmpeg process
            if self.ff:
                self.ff.process.terminate()
                # self.ff.process.kill()
                self.logger.info('[MediaStreamProxy] stop ffmpeg proc done')

        except Exception as e:
            self.logger.info('[MediaStreamProxy] stop error : %s' % e)

        self.logger.info('[MediaStreamProxy] stop done')
Пример #25
0
class AudioStreamProxy(object):
    def __init__(self, robot_uid=None):
        self.logger = InfoLogger(__name__).get_logger()

        self.host = ConfigAudio.host
        self.port = ConfigAudio.port
        self.file_type = ConfigAudio.file_type
        self.rate = ConfigAudio.rate

        self.robot_uid = robot_uid

        self.sock = None
        self.proc = None

    def start(self):
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.connect((self.host, self.port))
            self.logger.info('audio_stream socket setup done')

            self.sock = sock

            command = 'arecord -t {file_type} -r {rate}'.\
                format(file_type = self.file_type, rate = self.rate)

            proc = subprocess.Popen(shlex.split(command),
                                    stdout=subprocess.PIPE)

            self.proc = proc

            a_thread = threading.Thread( \
                target = run_audio_stream, \
                kwargs = {'robot_uid' : self.robot_uid, 'sock' : sock, 'proc' : proc})

            a_thread.start()

            # multiple client read one proc at the same time?

            self.logger.info('AudioStreamProxy start done')

        except Exception as e:
            self.logger.info('AudioStreamProxy.start error : %s' % e)

    def stop(self):
        if self.proc:
            try:
                self.proc.terminate()
                # self.proc.kill()
                self.logger.info('AudioStreamProxy stop proc done')

            except Exception as e:
                self.logger.info('AudioStreamProxy stop proc error : %s' % e)

        if self.sock:
            try:
                # shutdown will send '' to socket,
                # writer can cache and exit
                self.sock.shutdown(socket.SHUT_RDWR)

                self.sock.close()
                # self.sock = None
                self.logger.info('AudioStreamProxy stop socket done')

            except Exception as e:
                self.logger.info('AudioStreamProxy stop socket error : %s' % e)

        else:
            self.logger.info('AudioStreamProxy no socket to stop')

        self.logger.info('AudioStreamProxy stop done')