morphbr@565: #!/usr/bin/python morphbr@565: morphbr@565: import os morphbr@565: import lib morphbr@565: import sys morphbr@565: import imp morphbr@565: import ConfigParser morphbr@565: import logging as log morphbr@565: morphbr@565: log.basicConfig(level=log.DEBUG, morphbr@565: format="%(asctime)s %(levelname)-8s %(message)s", morphbr@565: datefmt='%Y-%m-%d %H:%M:%S') morphbr@565: morphbr@565: config = ConfigParser.ConfigParser() morphbr@565: config.read("stream.conf") morphbr@565: morphbr@565: def load_module(pathlist, name): morphbr@565: fp, path, desc = imp.find_module(name, pathlist) morphbr@565: try: morphbr@565: module = imp.load_module(name, fp, path, desc) morphbr@565: return module morphbr@565: finally: morphbr@565: if fp: morphbr@565: fp.close() morphbr@565: morphbr@565: morphbr@565: media_plugin = config.get("Media", "engine") morphbr@565: media_plugin_module = load_module(["./plugins/media"], media_plugin) morphbr@565: media = media_plugin_module.Media(config) morphbr@565: morphbr@565: comm_plugin = config.get("Comm", "engine") morphbr@565: comm_plugin_module = load_module(["./plugins/comm"], comm_plugin) morphbr@565: server = comm_plugin_module.Server(config) morphbr@565: morphbr@565: log.info("Starting GMyth-Stream server") morphbr@565: morphbr@565: morphbr@565: ''' morphbr@565: PROTOCOL DESCRIPTION morphbr@565: ===================== morphbr@565: morphbr@565: COMMAND OPTIONS morphbr@565: morphbr@565: -> SETUP DESCRIPTION morphbr@565: |-> used to setup transcoding and streaming parameters morphbr@565: |-> must be used before any "PLAY" command morphbr@565: |-> e.g: morphbr@565: morphbr@565: file://file_name mux vcodec vbitrate fps acodec abitrate width height options morphbr@565: dvd://title_number mux vcodec vbitrate fps acodec abitrate width height options morphbr@565: morphbr@565: -> PLAY DESCRIPTION morphbr@565: |-> used to start transcoding and streaming of file morphbr@565: |-> must be used just if SETUP was used before morphbr@565: |-> after it, _must_ send STOP morphbr@565: morphbr@565: -> STOP DESCRIPTION morphbr@565: |-> used to stop transcoding and streaming process morphbr@565: |-> must be used just if PLAY was used before morphbr@565: |-> must be used after PLAY morphbr@565: morphbr@565: -> QUIT DESCRIPTION morphbr@565: |-> used to quit the main loop (quit program) morphbr@565: morphbr@565: ''' morphbr@565: nextport = 0 morphbr@565: setup = (False, "STOPPED") morphbr@565: morphbr@565: def do_setup(server, filename, mux, vcodec, vbitrate, fps, acodec, abitrate, morphbr@565: width, height, *options): morphbr@565: global nextport morphbr@565: global setup morphbr@565: morphbr@565: if setup[1] != "PLAYING": morphbr@565: nextport += 1 morphbr@565: ret = media.setup(filename, mux, vcodec, vbitrate, fps, acodec, morphbr@565: abitrate, width, height, nextport, options) morphbr@565: if ret[0]: morphbr@565: server.sendOk() morphbr@565: else: morphbr@565: server.sendNotOk(ret[1]) morphbr@565: morphbr@565: setup = (True, setup[1]) morphbr@565: morphbr@565: else: server.sendNotOk("You must STOP before SETingUP again") morphbr@565: morphbr@565: return True morphbr@565: morphbr@565: def do_play(server): morphbr@565: global setup morphbr@565: morphbr@565: if setup[0] and setup[1] == "STOPPED": morphbr@565: setup = (setup[0], "PLAYING") morphbr@565: ret = media.play() morphbr@565: if ret[0]: morphbr@565: server.sendOk("%d" % nextport) morphbr@565: else: morphbr@565: server.sendNotOk(ret[1]) morphbr@565: morphbr@565: else: morphbr@565: if setup[1] == "STOPPED": morphbr@565: server.sendNotOk("You must SETUP before PLAYing") morphbr@565: else: morphbr@565: server.sendNotOk("You must STOP before PLAYing again") morphbr@565: morphbr@565: return True morphbr@565: morphbr@565: def do_stop(server): morphbr@565: global setup morphbr@565: morphbr@565: media.stop() morphbr@565: setup = (False, "STOPPED") morphbr@565: server.sendOk() morphbr@565: return True morphbr@565: morphbr@565: def do_list(server, *directory): morphbr@565: file_list = [] morphbr@565: for j in directory: morphbr@565: lib.list_media_files(j, file_list) morphbr@565: morphbr@565: server.sendOk(file_list) morphbr@565: return True morphbr@565: morphbr@565: def do_quit(server): morphbr@565: server.finish = 1 morphbr@565: media.stop() morphbr@565: server.sendOk() morphbr@565: return True morphbr@565: morphbr@565: morphbr@565: mapping = { morphbr@565: "SETUP": do_setup, morphbr@565: "PLAY": do_play, morphbr@565: "STOP": do_stop, morphbr@565: "LIST": do_list, morphbr@565: "QUIT": do_quit, morphbr@565: } morphbr@565: morphbr@565: morphbr@565: def dispatch(server, msg): morphbr@565: pieces = msg.split() morphbr@565: if len(pieces) < 1: morphbr@565: log.error("Invalid client command format: %r" % msg) morphbr@565: server.sendNotOk("Invalid Format") morphbr@565: return False morphbr@565: morphbr@565: cmd = pieces[0] morphbr@565: f = mapping.get(cmd, None) morphbr@565: if not f: morphbr@565: log.error("Unknow command: %r" % msg) morphbr@565: server.sendNotOk("Unknow Command") morphbr@565: return False morphbr@565: morphbr@565: try: morphbr@565: return f(server, *pieces[1:]) morphbr@565: except Exception, e: morphbr@565: log.error("Could not execute %r: %s" % (msg, e)) morphbr@565: server.sendNotOk(str(e)) morphbr@565: return False morphbr@565: morphbr@565: morphbr@565: morphbr@565: while not server.finish: morphbr@565: conn, client, port = server.getRequest() morphbr@565: if nextport == 0: morphbr@565: nextport = port morphbr@565: morphbr@565: while not server.finish: morphbr@565: msg = server.getMsg() morphbr@565: if not msg: morphbr@565: break morphbr@565: morphbr@565: log.info("Client %s sent command: %r" % (client, msg)) morphbr@565: dispatch(server, msg) morphbr@565: morphbr@565: log.info("Closing connection with %s" % (client,)) morphbr@565: server.disconnect_client(conn) morphbr@565: try: morphbr@565: os.wait() morphbr@565: except Exception, e: morphbr@565: log.error(e) morphbr@565: morphbr@565: server.stop() morphbr@565: log.info("Server stopped. Closing...") morphbr@565: