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: