Exemplo n.º 1
0
    print(data)


def callback_function(error, result):
    print("callback")
    if error:
        print(error)
        return
    print(result)


client = MeteorClient("ws://127.0.0.1:3000/websocket")

client.on("connected", connected)
client.on("failed", failed)

client.connect()

timestamp = str(datetime.now())
lat = 1.2956
lng = 103.7767
speed = 50
bearing = 50
altitude = 50

client.insert(
    "Telemetry",
    {"timestamp": timestamp, "lat": lat, "lng": lng, "speed": speed, "bearing": bearing, "altitude": altitude},
    callback=insert_callback,
)
Exemplo n.º 2
0
class MWorker:
    multiprocessPluginManager = ""  # yapsy manager
    meteorClient = ""  # python-meteor client
    # session=requests.Session()               #http client
    meteorUrl = "ws://127.0.0.1:3000/websocket"
    CYCLE_DEFAULT_DELAY = 20  # 10 seconds
    SYNCHRO_TIMEOUT = 10  # meteor functions are asynchron. this is delay for how long i should wait till
    # it is considered as fail... 2 sec are default
    subscription_status = {}  # this will assure, subscription is ready...    "subscription_name":true/false
    workername = "localhostworker"  # this is worker name - this must be initialised at moment of start, and
    # must by uniqued...

    data = ""
    error = ""
    syncwaitdone = False

    def __init__(self, meteorUrl):
        """
        constructor
        :return:
        """

        self.meteorUrl = meteorUrl
        self.logm("MWorker:constructor", "python meteor client initialisation:")
        self.initMeteorConnect()
        self.logm("MWorker:constructor", "getting unassigned")
        # self.infiniteCycle()
        self.getUnassigned()

    def infiniteCycle(self):
        """
        this is to keep thread running - it can be interupted by ctrl+c


        :return:
        """
        while True:
            try:
                time.sleep(1)
            except KeyboardInterrupt:
                break

    def initMeteorConnect(self):
        """
        this will use library python-meteor in order to escablish session to selected meteor

        :return:
        """
        self.logm("MWorkerLib:initMeteorConnect:", "meteor python lib client iniciaisation...")
        self.meteorClient = MeteorClient('ws://127.0.0.1:3000/websocket', auto_reconnect=True)
        self.meteorClient.connect()
        self.subscribeCollectionSynchron(['unassigned', 'active', 'trash'], self.SYNCHRO_TIMEOUT)

        self.logm("MWorkerLib:initMeteorConnect:", "meteor python lib client iniciaisation done...")

    def meteorCollectionSubscribed(self, subscription):
        self.subscription_status[subscription] = True;
        self.logm("MWorkerLib:subscribed:", 'SUBSCRIBED {}'.format(subscription))

    def meteorConnected(self):
        self.logm("MWorkerLib:connected:", ' CONNECTED')

    def initYapsy(self):
        """
        inicialisation of yapsi subsystems...
        :return:
        """
        self.multiprocessPluginManager = MultiprocessPluginManager()
        self.multiprocessPluginManager.setPluginPlaces(["plugins"])
        self.multiprocessPluginManager.collectPlugins()
        self.logm("MWorkerLib:initYapsy:", "following pluggins ready")
        for pluginInfo in self.multiprocessPluginManager.getAllPlugins():
            self.logm("MWorkerLib:initYapsy:", ">" + pluginInfo.name)

    def isSubscriptionProcessDone(self):
        """
        this will check, if in self.subscription_status   all collections are set to true
        :return: true if all requested collections are subscribed, orthervice false..
        """
        kk = self.subscription_status.keys()

        for col in kk:
            if self.subscription_status[col] == False:
                self.logm("MWorkerLib:isSubscriptionProcessDone:", self.subscription_status)
                return False
        return True

    def subscribeCollectionSynchron(self, collections, timeout):
        """
        this is synchron method. this means, there is loop for "timeout" seconds,
        so subscription can be estalished...
        :param: timeout  - number of seconds for cycle this function will have
        :param: collections   - array of collections to be subscribed with self.meteorClient...
                                ['unassigned', 'active', 'trash']
        :return: will return true, or collection if some is false
        """
        self.logm("MWorkerLib:subscribeCollectionsynchron:", "begining with subscription")
        self.meteorClient.on('subscribed', self.meteorCollectionSubscribed)

        self.meteorClient.on('connected', self.meteorConnected)

        for col in collections:
            self.subscription_status[col] = False
            self.meteorClient.subscribe(col)
        self.logm("MWorkerLib:subscribeCollectionSynchron",
                  "subscription init done, now waiting...:" + str(self.meteorClient.subscriptions.keys()))

        epoch = int(time.time())
        while (((int(time.time()) - epoch) < timeout) and (
                (self.isSubscriptionProcessDone() == False))):
            try:
                time.sleep(1)
                self.logm("MWorkerLib:subscribeCollectionSynchron",
                          "inside waiting cycle :" + str(self.meteorClient.subscriptions.keys()))
            except KeyboardInterrupt:
                break
        if (self.isSubscriptionProcessDone() == False):
            self.logm("MWorkerLib:subscribeCollectionSynchron",
                      "some requested subscription failed...:" + str(self.subscription_status))
            return False
        else:
            self.logm("MWorkerLib:subscribeCollectionSynchron", "requested subscription successfuly subscribed...")
            return True

    def getUnassigned(self):
        """
        get list of unassigned tasks
        :return: list of unassigned tasks
        """

        self.logm("MWorkerLib:getUnassigned", "geting all unassigned")
        all_posts = self.meteorClient.find('unassigned')

        self.logm("MWorkerLib:getUnassigned", "found following unassigned:" + str(all_posts))

    def subscription_callback(self, error):
        if error:
            self.logm("MWorkerLib:subscription_callback", "subsribing to unassigned failed")
            return
        self.logm("MWorkerLib:subscription_callback", "subsribing to unassigned succeed")

    def logm(self, tag="undefined tag", text="undefined text"):
        """
         logger wrapper ....
        :param tag:  tag
        :param level:   level ( 1..10 )
        :param text:   dscription of logging
        :return:
        """
        timestamp = self.getTimestamp()
        print("{d} t:{a}   t:{c}   ".format(a=tag, c=text, d=timestamp))

    ####################################### support methods
    def getTimestamp(self):
        ts = time.time()
        return datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')

    def callViewToolkit(self, method, parameters, callback):
        """
        this will execute call...
        please note, for simple geting collection data, no need to create method...


        :param method:    name of function
        :param parameters: what to give to viewtoolkit
        :callback  -  as all meteor calls are async, callback is required
            def callback_function(error, result):
                if error:
                    print(error)
                    return
                print(result)


        :return:
        """
        self.logm("MWorkerLib:callViewToolkit", "method:" + method + " with parameters:" + parameters + " called")
        self.meteorClient.call(method, parameters, callback)

    def isPluginActiveInPluginManager(self, pluginname):
        """
        this is to check if plugin which is parameter exist in worker, and if yes, if it is activated...
        :param pluginname:
        :return: true in case plugin is activated
        """

        for pluginInfo in self.multiprocessPluginManager.getAllPlugins():
            self.logm("MWorkerLib:isPlugginActiveInPluginManager:",
                      "checking plugin " + pluginInfo.name + "against " + pluginname)
            if (pluginname == pluginInfo.name):
                self.logm("MWorkerLib:isPlugginActiveInPluginManager:",
                          "plugin was found, let see if it is activated " + str(pluginInfo.is_activated))
                if pluginInfo.is_activated:
                    self.logm("MWorkerLib:isPlugginActiveInPluginManager:",
                              "yes, plugin exist and was activated. returning true")
                    return True
        self.logm("MWorkerLib:isPlugginActiveInPluginManager:",
                  "could not found plugin you uare asking for, or it is not activated, returning False")
        return False

    def activatePlugin(self, pluginname):
        """
        plugin activation itself
        :param pluginname:
        :return:
        """
        self.logm("MWorkerLib:isPlugginActiveInPluginManager:activatePlugin",
                  "plugin {a} will be activated now...".format(a=pluginname))
        self.multiprocessPluginManager.activatePluginByName(pluginname)
        self.logm("MWorkerLib:isPlugginActiveInPluginManager:activatePlugin",
                  "plugin {a} was activated...".format(a=pluginname))

    def moveJobFromActiveToTrash(self,jobname):
        """
        will move job by its name  from active to trash
        :param jobname:
        :return:
        """
        #kontrola, zda trash ma v sobe vytvoreneho workera:
        if(self.isWorkerInTrash()==False):
            self.createWorkerRecordInTrash()

        job=self.getJobInActiveByName(jobname)
        if (job==None):
            return False
        if self.createJobInTrashSynchronised(job):
            self.deleteJobFromActiveSynchronised(jobname)

    def deleteJobFromActiveSynchronised(self,jobname):
        """
        delete job from active
        :param jobname:
        :return:
        """
        result = False
        self.syncwaitdone = False  # zacatek locku
        self.logm("MWorkerLib:deleteJobFromActiveSynchronised",
                  "worker:" + self.workername + " is going to remove job from active " + str(jobname))
        self.meteorClient.remove( 'active',{'_id':self.workername,'jobs._id':jobname}, callback=self.callback_synchro)
        res = self.syncWait()  # konec locku
        self.logm("MWorkerLib:deleteJobFromActiveSynchronised",
                  "worker:" + self.workername + " removed " + str(jobname)+ "result is "+str(res))
        return res




    def createJobInTrashSynchronised(self,job):
        """
        this will create job in trash collection under worker name...

        :param job:
        :return:
        """

        #inseritng job
        self.logm("MWorkerLib:createJobInTrash",
                  "worker:" + self.workername + " is going to insert to trash following: " + str(job))
        self.syncwaitdone = False  # zacatek locku
        self.meteorClient.update('trash', {'_id': self.workername}, {'$push': {"jobs":job}},
                                 callback=self.callback_synchro)
        res = self.syncWait()  # konec locku
        return res

    def     getJobInActiveByName(self,jobname):
        """
        this will get job back
        :param jobname:  name of job in active ...
        :return:  return job, or None
        """
        res = self.meteorClient.find_one('active',{'_id':self.workername,'jobs.jobname':jobname})
        if res==[]:
            return None
        return res

    def moveJobFromUnassignedToActiveSynchronised(self, jobname):
        """
        this will shift job from unassigned to active... based on job name, which must be unique in hwhile system
        :param jobname:
        :return:
        """
        #kontrola, zda existuje worker v active, a kdyz ne, tak se vlozi podle template
        if(self.isWorkerInActive()==False):
            self.logm("MWorkerLib:moveJobFromUnassignedToActiveSynchronised",
                  " dont see record for worker {w} in active !! creating it ".format(w=self.workername))
            self.createWorkerRecordInActive()


        resulttmp = self.findJobinUnassigned(jobname)
        if(len(resulttmp)!=1):
            raise NoJobFound(" given job name "+jobname+" doesnt exist")
        job=resulttmp[0]
        self.logm("MWorkerLib:moveJobFromUnassignedToActiveSynchronised",
                  " job  {a} will be activated now...".format(a=str(job)))
        if (self.createMyJobInActiveSynchronised(job)):
            if(self.deleteJobFromUnassignedSynchronised(job)):
                self.logm("MWorkerLib:moveJobFromUnassignedToActiveSynchronised",
                  " job inserting to db is ok, job deleted from unassigned ")
                return True
        self.logm("MWorkerLib:moveJobFromUnassignedToActiveSynchronised",
                  "job inserting to db failed")
        return False


    def isWorkerInTrash(self):
        """
        will check is self.workername can be found in trash
        :return: true if it can be found, false if not
        """
        result = self.meteorClient.find('trash',{"_id":self.workername})
        self.logm("MWorkerLib:isWorkerInTrash",
                  "checking, if i see my worker name in trash "+str(result))
        if len(result)==1:
            self.logm("MWorkerLib:isWorkerInTrash",
                  " worker with my name found in trash, erturning true")
            return True
        else:
            self.logm("MWorkerLib:isWorkerInTrash",
                  "found nothing, returning False")
            return False


    def isWorkerInActive(self):
        """
        will check is self.workername can be found in active
        :return: true if it can be found, false if not
        """
        result = self.meteorClient.find('active',{"_id":self.workername})
        self.logm("MWorkerLib:isWorkerInActive",
                  "checking, if i see my worker name in active "+str(result))
        if len(result)==1:
            self.logm("MWorkerLib:isWorkerInActive",
                  " worker with my name found in active, erturning true")
            return True
        else:
            self.logm("MWorkerLib:isWorkerInActive",
                  "found nothing, returning False")
            return False

    def createWorkerRecordInActive(self):
        """
        will create new worker - it will not be checking if there is already worker created in active...
        :return:
        """
        template={"_id":self.workername,"worker":self.workername,"workerusername":"******","jobs":[]}
        self.logm("MWorkerLib:createWorkerRecordInActive",
                  "worker:" + self.workername + " is going to by added to collection active ")
        self.syncwaitdone = False  # zacatek locku
        self.meteorClient.insert('active',   template,
                                 callback=self.callback_synchro)
        res = self.syncWait()  # konec locku
        return res


    def createWorkerRecordInTrash(self):
        """
        will create new worker - it will not be checking if there is already worker created in active...
        :return:
        """
        template={"_id":self.workername,"worker":self.workername,"workerusername":"******","jobs":[]}
        self.logm("MWorkerLib:createWorkerRecordInTrash",
                  "worker:" + self.workername + " is going to by added to collection trash ")
        self.syncwaitdone = False  # zacatek locku
        self.meteorClient.insert('trash',   template,
                                 callback=self.callback_synchro)
        res = self.syncWait()  # konec locku
        return res


    def findJobinUnassigned(self, jobname):
        """
        will return job from unassigned by jobname
        this is synchron method... it will wait for ( synchron_timeout ) seconds, and return false
        :param job:
        :return:  false on timeout ( synchron_timeout ) or if return is different from 1.
        """
        return self.meteorClient.find('unassigned', {"_id": jobname})

    def createMyJobInActiveSynchronised(self, job):
        """
        this will take as input dict of job... and add it to jobs[] in proper worker...
        :param job:  dict of job...
        :return: false on timeout ( synchron_timeout ) or if return is different from 1.
        """
        template = {
            'pluginname': job['pluginname'],
            'jobname': job['jobname'],
            
            'starttime': int(time.time()),  # epocha
            'ttl': job['expectedttl'],
            'inputparams': job['inputparams'],
            'progress': 0,
            'result': "undefined"
        }

        self.logm("MWorkerLib:createMyJobInActive",
                  "worker:" + self.workername + " is going to insert to active following: " + str(job))
        self.syncwaitdone = False  # zacatek locku
        self.meteorClient.update('active', {'_id': self.workername}, {'$push': {'jobs': template}},
                                 callback=self.callback_synchro)
        res = self.syncWait()  # konec locku
        return res

    def callback_synchro(self, error, data):

        self.data = data
        self.error = error
        if error:
            self.logm("MWorkerLib:update_callback_synchro",
                      "worker:" + self.workername + " failed error is " + str(error))
            self.syncwaitdone = True
            return

        self.logm("MWorkerLib:update_callback_synchro", "is ok. number of updates is " + str(data))
        self.syncwaitdone = True

    def syncWait(self):
        """
        this will wait till data of error are not empty.
        it will do for self.SYNCHRO_TIMEOUT seconds. then it will return False

        also it will check what is return value from request. if update is 0,
        false, othervice true
        """

        epoch = int(time.time())
        while (((int(time.time()) - epoch) < self.SYNCHRO_TIMEOUT) and (self.syncwaitdone == False)):
            try:
                time.sleep(1)
                self.logm("MWorkerLib:syncWait",
                          "inside waiting cycle :")
            except KeyboardInterrupt:
                break

        if (self.syncwaitdone == False):
            # cycle was broken before timeou
            return False

        try:
            # zkouska, zda se updatoval aspon jeden radek
            if (int(self.data) == 0):
                # mongo changed nothing, but there was no error
                return False
            else:
                return True
        except:
            pass

        # nothing found, cykluus end on timeout
        return False

    def deleteJobFromUnassignedSynchronised(self, job):
        """
        this will delete selected job from unassigned
        this is synchron method... it will wait for ( synchron_timeout ) seconds, and return false

        :param job:
        :return: false on timeout ( synchron_timeout ) or if return is different from 1.
        """
        self.syncwaitdone = False  # zacatek locku
        self.logm("MWorkerLib:createMyJobInActive",
                  "worker:" + self.workername + " is going to remove job from unassigned " + str(job))
        self.meteorClient.remove('unassigned', {'_id': job['_id']}, callback=self.callback_synchro)
        res = self.syncWait()  # konec locku
        self.logm("MWorkerLib:createMyJobInActive",
                  "worker:" + self.workername + " removed " + str(job)+ "result is "+str(res))
        return res
    #########################testing


    def testScenario1(self):
        """
        this is scenario 1...
        this will move job from unassigned to active, then from active to trash...
        also it will list unassigned tasks
        :return:



        self.logm("MWorkerLib:testScenario1", "start test scenario 1")
        self.logm("MWorkerLib:testScenario1", "moving from unassigned to active")
        all_posts = self.meteorClient.find('unassigned')
        #job = (all_posts).keys()

        #get first unassigned:
        firstUnassigned=self.meteorClient.find('unassigned')[0]
        ttltmp=100
        #pro testovaci ucely jsem vytvoril v active workera:
        # db.active.insert({"_id":"localhostworker","worker":"localhostworker","workerusername":"******","jobs":[]})

        template={
             'pluginname':firstUnassigned['pluginname'],
             'starttime':int(time.time()),    #epocha
             'ttl':ttltmp,
             'inputparams':firstUnassigned['inputparams'],
             'progress':0,
             'result':"undefined"
        }
        #insert to active:
        #musim pouzit id_ protoze klient rve ze kod je insecure a musi se pouzit id
        #s _id je dalsi problem. protoze interne mongodb pouziva objekt, ne stringu
        #tak bude vyhodnejsi nahradit pri vytvoreni workeru v active _id s nejakym retezcem  _
        worker=self.meteorClient.find_one('active',{"worker" : "localhostworker"})
        #worker["workerusername"]="******"
        self.logm("MWorkerLib:testScenario1", "worker:"+str(worker)+" "+worker['_id'])
        worker1=self.meteorClient.find_one('active',{"_id":worker["_id"]})

        self.logm("MWorkerLib:testScenario1", "worker:"+str(worker1)+" "+worker1['_id'])
        self.meteorClient.update('active',{'_id':worker['_id']},{'$push':{'jobs':template}},callback=update_callback)

        #self.infiniteCycle()
        self.logm("MWorkerLib:testScenario1", "deleting job from unassigned")
        self.meteorClient.remove('unassigned',{'_id':firstUnassigned['_id']},callback=remove_callback)




        time.sleep(5)
        """
        job = {'_id': "asdasdsad", 'jobname': "asdasd", 'pluginname': "asdasda", 'inputparams': "assad",
               'expectedttl': "100"}


        #otestovane a funkcni 11.2.2016:
        #tohle presune job s danym jmenem do active pod jmeno mistniho workera...
        #self.moveJobFromUnassignedToActiveSynchronised("blabla")

        self.moveJobFromActiveToTrash("blabla")
Exemplo n.º 3
0
class DDP(Thread):
    def __init__(self):
        Thread.__init__(self)
        self.meteor = conf.get('ddp', 'meteor')

        self.client = MeteorClient(self.meteor, debug=False)
        self.client.on('added', self.on_added)
        self.client.on('changed', self.on_changed)
        self.client.on('subscribed', self.on_subscribed)
        self.client.on('connected', self.on_connected)
        self.client.on('removed', self.on_removed)
        self.client.on('closed', self.on_closed)
        self.client.on('logged_in', self.on_logged_in)

        self.displayName = conf.get('ddp', 'room_name')
        self.vu_min = -50
        self.vu_range = 50
        self.vu_data = 0
        self.last_vu = None
        self.ip = conf.get('ingest', 'address')
        self.id = conf.get('ingest', 'hostname')
        self._user = conf.get('ddp', 'user')
        self._password = conf.get('ddp', 'password')
        self._http_host = conf.get('ddp', 'http_host')
        self._audiostream_port = conf.get('audiostream', 'port') or 31337
        self.store_audio = conf.get_boolean('ddp', 'store_audio')
        self.screenshot_file = conf.get('ddp', 'existing_screenshot')
        self.high_quality = conf.get_boolean('ddp', 'hq_snapshot')
        self.paused = False
        self.recording = False
        self.currentMediaPackage = None
        self.currentProfile = None
        self.has_disconnected = False
        screen = Gdk.Screen.get_default()
        self._screen_width = screen.get_width()
        self._screen_height = screen.get_height()
        self.cardindex = None

        cam_available = conf.get('ddp', 'cam_available') or 0
        if cam_available in ('True', 'true', True, '1', 1):
            self.cam_available = 1
        elif cam_available in ('False', 'false', False, '0', 0):
            self.cam_available = 0
        else:
            self.cam_available = int(cam_available)
        # Getting audiostream params. either using existing audiostreaming server like icecast or the audiostream plugin
        if conf.get('ddp', 'existing_stream_host'):
            self._stream_host = conf.get('ddp', 'existing_stream_host')
        else:
            self._stream_host = self.ip

        if conf.get_int('ddp', 'existing_stream_port'):
            self._audiostream_port = conf.get_int('ddp',
                                                  'existing_stream_port')
        else:
            self._audiostream_port = conf.get_int('audiostream',
                                                  'port') or 31337

        if conf.get('ddp', 'existing_stream_key'):
            self.stream_key = conf.get('ddp', 'existing_stream_key')
        else:
            self.stream_key = uuid.uuid4().get_hex()

        if conf.get('ddp', 'extra_params'):
            self.extra_params_list = conf.get('ddp', 'extra_params').split(';')
        else:
            self.extra_params_list = []
        logger.info(
            'audiostream URI: {}'.format('http://' + self._stream_host + ':' +
                                         str(self._audiostream_port) + '/' +
                                         self.stream_key))

        dispatcher.connect('init', self.on_init)
        dispatcher.connect('recorder-vumeter', self.vumeter)
        dispatcher.connect('timer-short', self.update_vu)
        dispatcher.connect('timer-short', self.heartbeat)
        dispatcher.connect('recorder-started', self.on_start_recording)
        dispatcher.connect('recorder-stopped', self.on_stop_recording)
        dispatcher.connect('recorder-status', self.on_rec_status_update)

    def run(self):
        self.connect()

    def connect(self):
        if not self.has_disconnected:
            try:
                self.client.connect()
            except Exception:
                logger.warn('DDP connection failed')

    def update(self, collection, query, update):
        if self.client.connected and self.subscribedTo('GalicasterControl'):
            try:
                self.client.update(collection,
                                   query,
                                   update,
                                   callback=self.update_callback)
            except Exception:
                logger.warn("Error updating document "
                            "{collection: %s, query: %s, update: %s}" %
                            (collection, query, update))

    def insert(self, collection, document):
        if self.client.connected and self.subscribedTo('GalicasterControl'):
            try:
                self.client.insert(collection,
                                   document,
                                   callback=self.insert_callback)
            except Exception:
                logger.warn(
                    "Error inserting document {collection: %s, document: %s}" %
                    (collection, document))

    def heartbeat(self, element):
        if self.client.connected:
            self.update_images()
        else:
            self.connect()

    def on_start_recording(self, sender, id):
        self.recording = True
        self.currentMediaPackage = self.media_package_metadata(id)
        self.currentProfile = conf.get_current_profile().name
        self.update('rooms', {'_id': self.id}, {
            '$set': {
                'currentMediaPackage': self.currentMediaPackage,
                'currentProfile': self.currentProfile,
                'recording': self.recording
            }
        })

    def on_stop_recording(self, mpid, sender=None):
        self.recording = False
        self.currentMediaPackage = None
        self.currentProfile = None
        self.update('rooms', {'_id': self.id}, {
            '$unset': {
                'currentMediaPackage': '',
                'currentProfile': ''
            },
            '$set': {
                'recording': self.recording
            }
        })
        self.update_images(1.5)

    def on_init(self, data):
        self.update_images(1.5)

    def update_images(self, delay=0.0):
        worker = Thread(target=self._update_images, args=(delay, ))
        worker.start()

    def _update_images(self, delay):
        time.sleep(delay)
        files = {}

        if not self.screenshot_file:
            # take a screenshot with pyscreenshot
            im = ImageGrab.grab(bbox=(0, 0, self._screen_width,
                                      self._screen_height),
                                backend='imagemagick')
        else:
            try:
                # used if screenshot already exists
                im = Image.open(self.screenshot_file)
            except IOError as e:
                logger.warn("Unable to open screenshot file {0}".format(
                    self.screenshot_file))
                return
        output = cStringIO.StringIO()
        image_format = 'JPEG'
        if not self.high_quality:
            im.thumbnail((640, 360), Image.ANTIALIAS)
        else:
            image_format = 'PNG'

        if im.mode != "RGB":
            im = im.convert("RGB")
        im.save(output, format=image_format
                )  # to reduce jpeg size use param: optimize=True
        files['galicaster'] = ('galicaster.jpg', output.getvalue(),
                               'image/jpeg')
        try:
            # add verify=False for testing self signed certs
            requests.post(
                "%s/image/%s" % (self._http_host, self.id),
                files=files,
                auth=(self._user, self._password
                      ))  # to ignore ssl verification, use param: verify=False
        except Exception:
            logger.warn('Unable to post images')

    def vumeter(self, element, data, data_chan2, vu_bool):
        if data == "Inf":
            data = 0
        else:
            if data < -self.vu_range:
                data = -self.vu_range
            elif data > 0:
                data = 0
        self.vu_data = int(
            ((data + self.vu_range) / float(self.vu_range)) * 100)

    def update_vu(self, element):
        if self.vu_data != self.last_vu:
            update = {'vumeter': self.vu_data}
            self.update('rooms', {'_id': self.id}, {'$set': update})
            self.last_vu = self.vu_data

    def on_rec_status_update(self, element, data):
        if data == 'paused':
            is_paused = True
        else:
            is_paused = False
        if is_paused:
            self.update_images(.75)
        if self.paused == is_paused:
            self.update('rooms', {'_id': self.id},
                        {'$set': {
                            'paused': is_paused
                        }})
            self.paused = is_paused
        if data == 'recording':
            self.update_images(.75)

    def media_package_metadata(self, id):
        mp = context.get('recorder').current_mediapackage
        line = mp.metadata_episode
        duration = mp.getDuration()
        line["duration"] = long(duration / 1000) if duration else None
        # FIXME Does series_title need sanitising as well as duration?
        created = mp.getDate()
        # line["created"] = calendar.timegm(created.utctimetuple())
        for key, value in mp.metadata_series.iteritems():
            line["series_" + key] = value
        for key, value in line.iteritems():
            if value in [None, []]:
                line[key] = ''
        # return line
        return line

    def subscription_callback(self, error):
        if error:
            logger.warn("Subscription callback returned error: %s" % error)

    def insert_callback(self, error, data):
        if error:
            logger.warn("Insert callback returned error: %s" % error)

    def update_callback(self, error, data):
        if error:
            logger.warn("Update callback returned error: %s" % error)

    def on_subscribed(self, subscription):
        if (subscription == 'GalicasterControl'):
            me = self.client.find_one('rooms')
            # Data to push when inserting or updating
            data = {
                'displayName': self.displayName,
                'ip': self.ip,
                'paused': self.paused,
                'recording': self.recording,
                'heartbeat': int(time.time()),
                'camAvailable': self.cam_available,
                'inputs': self.inputs(),
                'stream': {
                    'host': self._stream_host,
                    'port': self._audiostream_port,
                    'key': self.stream_key
                }
            }
            # Parse extra Meteor Mongodb collection elements and append
            for params in self.extra_params_list:
                param = params.split(':')
                data[param[0]] = param[1]

            if self.currentMediaPackage:
                data['currentMediaPackage'] = self.currentMediaPackage
            if self.currentProfile:
                data['currentProfile'] = self.currentProfile

            if me:
                # Items to unset
                unset = {}
                if not self.currentMediaPackage:
                    unset['currentMediaPackage'] = ''
                if not self.currentProfile:
                    unset['currentProfile'] = ''

                # Update to push
                update = {'$set': data}

                if unset:
                    update['$unset'] = unset
                self.update('rooms', {'_id': self.id}, update)
            else:
                data['_id'] = self.id
                self.insert('rooms', data)

    def inputs(self):
        inputs = {'presentations': ['Presentation']}
        inputs['cameras'] = []
        labels = conf.get('ddp', 'cam_labels')
        cam_labels = []
        if labels:
            cam_labels = [l.strip() for l in labels.split(',')]
        for i in range(0, self.cam_available):
            label = cam_labels[i] if i < len(cam_labels) else "Camera %d" % (
                i + 1)
            inputs['cameras'].append(label)
        return inputs

    def on_added(self, collection, id, fields):
        pass

    def on_changed(self, collection, id, fields, cleared):
        me = self.client.find_one('rooms')
        if self.paused != me['paused']:
            self.set_paused(me['paused'])

        if context.get('recorder').is_recording() != me['recording']:
            self.set_recording(me)

    def on_removed(self, collection, id):
        self.on_subscribed(None)

    def set_paused(self, new_status):
        if not self.paused:
            self.paused = new_status
            context.get('recorder').pause()
        else:
            self.paused = False
            context.get('recorder').resume()

    def set_recording(self, me):
        self.recording = me['recording']
        if self.recording:
            # FIXME: Metadata isn't passed to recorder
            meta = me.get('currentMediaPackage', {}) or {}
            profile = me.get('currentProfile', 'nocam')
            series = (meta.get('series_title', ''), meta.get('isPartOf', ''))
            user = {
                'user_name': meta.get('creator', ''),
                'user_id': meta.get('rightsHolder', '')
            }
            title = meta.get('title', 'Unknown')
            context.get('recorder').record()
        else:
            context.get('recorder').stop()

    def on_connected(self):
        logger.info('Connected to Meteor')
        token = conf.get('ddp', 'token')
        self.client.login(self._user, self._password, token=token)

    def on_logged_in(self, data):
        conf.set('ddp', 'token', data['token'])
        conf.update()
        try:
            self.client.subscribe('GalicasterControl',
                                  params=[self.id],
                                  callback=self.subscription_callback)
        except Exception:
            logger.warn('DDP subscription failed')

    def on_closed(self, code, reason):
        self.has_disconnected = True
        logger.error('Disconnected from Meteor: err %d - %s' % (code, reason))

    def subscribedTo(self, publication):
        return self.client.subscriptions.get(publication) != None
Exemplo n.º 4
0
import time

from MeteorClient import MeteorClient

client = MeteorClient('ws://127.0.0.1:3000/websocket', debug=True)
client.connect()

client.subscribe('SessionsList')
name = time.strftime("%I:%M:%S")
time.sleep(1)

client.insert('Sessions', {'title': name})
time.sleep(1)

# confirm that a publication was started based on the session name passed in
client.subscribe(name)
time.sleep(1)
Exemplo n.º 5
0
class DDP(Thread):

    def __init__(self):
        Thread.__init__(self)
        self.meteor = conf.get('ddp', 'meteor')

        self.client = MeteorClient(self.meteor, debug=False)
        self.client.on('added', self.on_added)
        self.client.on('changed', self.on_changed)
        self.client.on('subscribed', self.on_subscribed)
        self.client.on('connected', self.on_connected)
        self.client.on('removed', self.on_removed)
        self.client.on('closed', self.on_closed)
        self.client.on('logged_in', self.on_logged_in)

        self.displayName = conf.get('sussexlogin', 'room_name')
        self.vu_min = -70
        self.vu_range = 40
        self.do_vu = 0
        self.last_vu = None
        self.ip = socket.gethostbyname(socket.gethostname())
        self.id = conf.get('ingest', 'hostname')
        self._user = conf.get('ddp', 'user')
        self._password = conf.get('ddp', 'password')
        self._http_host = conf.get('ddp', 'http_host')
        self._audiostream_port = conf.get('audiostream', 'port') or 31337
        self.netreg_id = conf.get('ddp', 'netreg_id')
        self.store_audio = conf.get_boolean('ddp', 'store_audio')
        self.paused = False
        self.recording = False
        self.currentMediaPackage = None
        self.currentProfile = None
        self.has_disconnected = False

        cam_available = conf.get(
            'sussexlogin',
            'cam_available') or cam_available
        if cam_available in ('True', 'true', True, '1', 1):
            self.cam_available = 1
        elif cam_available in ('False', 'false', False, '0', 0):
            self.cam_available = 0
        else:
            self.cam_available = int(cam_available)

        self.audiofaders = []
        faders = conf.get('ddp', 'audiofaders').split()
        for fader in faders:
            audiofader = {}
            fader = 'audiofader-' + fader
            audiofader['name'] = conf.get(fader, 'name')
            audiofader['display'] = conf.get(fader, 'display')
            audiofader['min'] = conf.get_int(fader, 'min')
            audiofader['max'] = conf.get_int(fader, 'max')
            audiofader['type'] = conf.get(fader, 'type')
            audiofader['setrec'] = conf.get_boolean(fader, 'setrec')
            audiofader['mute'] = conf.get_boolean(fader, 'mute')
            audiofader['unmute'] = conf.get_boolean(fader, 'unmute')
            audiofader['setlevel'] = conf.get_int(fader, 'setlevel')
            try:
                audiofader['control'] = alsaaudio.Mixer(
                    control=audiofader['name'])
                self.audiofaders.append(audiofader)
            except Exception as e:
                logger.warn(e)
        fd, eventmask = self.audiofaders[0]['control'].polldescriptors()[0]
        self.watchid = gobject.io_add_watch(fd, eventmask, self.mixer_changed)

        dispatcher.connect('galicaster-init', self.on_init)
        dispatcher.connect('update-rec-vumeter', self.vumeter)
        dispatcher.connect('galicaster-notify-timer-short', self.heartbeat)
        dispatcher.connect('start-before', self.on_start_recording)
        dispatcher.connect('restart-preview', self.on_stop_recording)
        dispatcher.connect('update-rec-status', self.on_rec_status_update)

    def run(self):
        self.connect()

    def connect(self):
        if not self.has_disconnected:
            try:
                self.client.connect()
            except Exception:
                logger.warn('DDP connection failed')

    def update(self, collection, query, update):
        if self.client.connected and self.subscribedTo('GalicasterControl'):
            try:
                self.client.update(
                    collection,
                    query,
                    update,
                    callback=self.update_callback)
            except Exception:
                logger.warn(
                    "Error updating document "
                    "{collection: %s, query: %s, update: %s}" %
                    (collection, query, update))

    def insert(self, collection, document):
        if self.client.connected and self.subscribedTo('GalicasterControl'):
            try:
                self.client.insert(
                    collection,
                    document,
                    callback=self.insert_callback)
            except Exception:
                logger.warn(
                    "Error inserting document {collection: %s, document: %s}" %
                    (collection, document))

    def heartbeat(self, element):
        if self.client.connected:
            self.update_images()
        else:
            self.connect()

    def on_start_recording(self, sender, id):
        self.recording = True
        self.currentMediaPackage = self.media_package_metadata(id)
        self.currentProfile = context.get_state().profile.name
        self.update(
            'rooms', {
                '_id': self.id
            }, {
                '$set': {
                    'currentMediaPackage': self.currentMediaPackage,
                    'currentProfile': self.currentProfile,
                    'recording': self.recording
                }
            })

    def on_stop_recording(self, sender=None):
        self.recording = False
        self.currentMediaPackage = None
        self.currentProfile = None
        self.update(
            'rooms', {
                '_id': self.id
            }, {
                '$unset': {
                    'currentMediaPackage': '',
                    'currentProfile': ''
                }, '$set': {
                    'recording': self.recording
                }
            })
        self.update_images(1.5)

    def on_init(self, data):
        self.update_images(1.5)

    def update_images(self, delay=0):
        worker = Thread(target=self._update_images, args=(delay,))
        worker.start()

    def _update_images(self, delay):
        time.sleep(delay)
        files = {}
        audio_devices = ['audiotest', 'autoaudio', 'pulse']
        for track in context.get_state().profile.tracks:
            if track.device not in audio_devices:
                file = os.path.join('/tmp', track.file + '.jpg')
                try:
                    if(os.path.getctime(file) > time.time() - 3):
                        files[track.flavor] = (track.flavor + '.jpg',
                                               open(file, 'rb'),
                                               'image/jpeg')
                except Exception:
                    logger.warn("Unable to check date of or open file (%s)"
                                % file)
        im = ImageGrab.grab(bbox=(10, 10, 1280, 720), backend='imagemagick')
        im.thumbnail((640, 360))
        output = cStringIO.StringIO()
        if im.mode != "RGB":
            im = im.convert("RGB")
        im.save(output, format="JPEG")
        files['galicaster'] = ('galicaster.jpg', output.getvalue(),
                               'image/jpeg')
        try:
            # add verify=False for testing self signed certs
            requests.post(
                "%s/image/%s" %
                (self._http_host, self.id), files=files, auth=(
                    self._user, self._password))
        except Exception:
            logger.warn('Unable to post images')

    def mixer_changed(self, source=None, condition=None, reopen=True):
        if reopen:
            for audiofader in self.audiofaders:
                audiofader['control'] = alsaaudio.Mixer(
                    control=audiofader['name'])
        self.update_audio()
        return True

    def vumeter(self, element, data):
        if self.do_vu == 0:
            if data == "Inf":
                data = 0
            else:
                if data < -self.vu_range:
                    data = -self.vu_range
                elif data > 0:
                    data = 0
            data = int(((data + self.vu_range) / float(self.vu_range)) * 100)
            if data != self.last_vu:
                update = {'vumeter': data}
                self.update('rooms', {'_id': self.id}, {'$set': update})
                self.last_vu = data
        self.do_vu = (self.do_vu + 1) % 20

    def on_rec_status_update(self, element, data):
        is_paused = data == 'Paused'
        if is_paused:
            self.update_images(.75)
        if self.paused != is_paused:
            self.update(
                'rooms', {
                    '_id': self.id}, {
                    '$set': {
                        'paused': is_paused}})
            self.paused = is_paused
        if data == '  Recording  ':
            subprocess.call(['killall', 'maliit-server'])
            self.update_images(.75)

    def media_package_metadata(self, id):
        mp = context.get_repository().get(id)
        line = mp.metadata_episode.copy()
        duration = mp.getDuration()
        line["duration"] = long(duration / 1000) if duration else None
        # Does series_title need sanitising as well as duration?
        created = mp.getDate()
        line["created"] = calendar.timegm(created.utctimetuple())
        for key, value in mp.metadata_series.iteritems():
            line["series_" + key] = value
        for key, value in line.iteritems():
            if value in [None, []]:
                line[key] = ''
        return line

    def subscription_callback(self, error):
        if error:
            logger.warn("Subscription callback returned error: %s" % error)

    def insert_callback(self, error, data):
        if error:
            logger.warn("Insert callback returned error: %s" % error)

    def update_callback(self, error, data):
        if error:
            logger.warn("Update callback returned error: %s" % error)

    def on_subscribed(self, subscription):
        if(subscription == 'GalicasterControl'):
            me = self.client.find_one('rooms')
            stream_key = uuid.uuid4().get_hex()

            # Data to push when inserting or updating
            data = {
                'displayName': self.displayName,
                'ip': self.ip,
                'paused': self.paused,
                'recording': self.recording,
                'heartbeat': int(time.time()),
                'camAvailable': self.cam_available,
                'netregId': self.netreg_id,
                'inputs': self.inputs(),
                'stream': {
                    'port': self._audiostream_port,
                    'key': stream_key
                },
                'galicasterVersion': galicaster.__version__
            }
            if self.currentMediaPackage:
                data['currentMediaPackage'] = self.currentMediaPackage
            if self.currentProfile:
                data['currentProfile'] = self.currentProfile

            if me:
                # Items to unset
                unset = {}
                if not self.currentMediaPackage:
                    unset['currentMediaPackage'] = ''
                if not self.currentProfile:
                    unset['currentProfile'] = ''

                # Update to push
                update = {
                    '$set': data
                }

                if unset:
                    update['$unset'] = unset
                self.update('rooms', {'_id': self.id}, update)
            else:
                audio = self.read_audio_settings()
                data['_id'] = self.id
                data['audio'] = audio
                self.insert('rooms', data)

    def inputs(self):
        inputs = {
            'presentations': ['Presentation']
        }
        inputs['cameras'] = []
        labels = conf.get('sussexlogin', 'matrix_cam_labels')
        cam_labels = []
        if labels:
            cam_labels = [l.strip() for l in labels.split(',')]
        for i in range(0, self.cam_available):
            label = cam_labels[i] if i < len(
                cam_labels) else "Camera %d" % (i + 1)
            inputs['cameras'].append(label)
        return inputs

    def set_audio(self, fields):
        faders = fields.get('audio')
        if faders:
            for fader in faders:
                mixer = None
                level = fader.get('level')
                for audiofader in self.audiofaders:
                    if audiofader['name'] == fader['name']:
                        mixer = audiofader['control']
                        break
                if mixer:
                    l, r = mixer.getvolume(fader['type'])
                    if level >= 0 and l != level:
                        mixer.setvolume(level, 0, fader['type'])
                        mixer.setvolume(level, 1, fader['type'])
            if self.store_audio:
                # Relies on no password sudo access for current user to alsactl
                subprocess.call(['sudo', 'alsactl', 'store'])

    def on_added(self, collection, id, fields):
        self.set_audio(fields)
        self.update_audio()

    def on_changed(self, collection, id, fields, cleared):
        self.set_audio(fields)
        me = self.client.find_one('rooms')
        if self.paused != me['paused']:
            self.set_paused(me['paused'])
        if context.get_state().is_recording != me['recording']:
            self.set_recording(me)

    def on_removed(self, collection, id):
        self.on_subscribed(None)

    def set_paused(self, new_status):
        self.paused = new_status
        dispatcher.emit("toggle-pause-rec")

    def set_recording(self, me):
        self.recording = me['recording']
        if self.recording:
            meta = me.get('currentMediaPackage', {}) or {}
            profile = me.get('currentProfile', 'nocam')
            series = (meta.get('series_title', ''), meta.get('isPartOf', ''))
            user = {'user_name': meta.get('creator', ''),
                    'user_id': meta.get('rightsHolder', '')}
            title = meta.get('title', 'Unknown')
            dispatcher.emit('sussexlogin-record',
                            (user, title, series, profile))
        else:
            dispatcher.emit("stop-record", '')

    def on_connected(self):
        logger.info('Connected to Meteor')
        token = conf.get('ddp', 'token')
        self.client.login(self._user, self._password, token=token)

    def on_logged_in(self, data):
        conf.set('ddp', 'token', data['token'])
        conf.update()
        try:
            self.client.subscribe(
                'GalicasterControl',
                params=[
                    self.id],
                callback=self.subscription_callback)
        except Exception:
            logger.warn('DDP subscription failed')

    def on_closed(self, code, reason):
        self.has_disconnected = True
        logger.error('Disconnected from Meteor: err %d - %s' % (code, reason))

    def update_audio(self):
        me = self.client.find_one('rooms')
        audio = self.read_audio_settings()
        update = False
        if me:
            mAudio = me.get('audio')
            mAudioNames = [x['name'] for x in mAudio]
            audioNames = [x['name'] for x in audio]
            if set(mAudioNames) != set(audioNames):
                update = True
            if not update:
                for key, fader in enumerate(audio):
                    if mAudio[key].get('level') != fader.get('level'):
                        update = True
            if update:
                self.update(
                    'rooms', {
                        '_id': self.id}, {
                        '$set': {
                            'audio': audio}})

    def read_audio_settings(self):
        audio_settings = []
        for audiofader in self.audiofaders:
            if audiofader['display']:
                audio_settings.append(
                    self.control_values(audiofader)
                )
            # ensure fixed values
            mixer = audiofader['control']
            if audiofader['setrec']:
                mixer.setrec(1)
            if audiofader['mute']:
                mixer.setmute(1)
            if audiofader['unmute']:
                mixer.setmute(0)
            if audiofader['setlevel'] >= 0:
                mixer.setvolume(audiofader['setlevel'], 0, audiofader['type'])
                if 'Joined Playback Volume' not in mixer.volumecap():
                    mixer.setvolume(audiofader['setlevel'],
                                    1, audiofader['type'])
        return audio_settings

    def control_values(self, audiofader):
        controls = {}
        left, right = audiofader['control'].getvolume(audiofader['type'])
        controls['min'] = audiofader['min']
        controls['max'] = audiofader['max']
        controls['level'] = left
        controls['type'] = audiofader['type']
        controls['name'] = audiofader['name']
        controls['display'] = audiofader['display']
        return controls

    def subscribedTo(self, publication):
        return self.client.subscriptions.get(publication) is not None
Exemplo n.º 6
0
class DDP(Thread):
    def __init__(self):
        Thread.__init__(self)
        self.meteor = conf.get('ddp', 'meteor')

        self.client = MeteorClient(self.meteor, debug=False)
        self.client.on('added', self.on_added)
        self.client.on('changed', self.on_changed)
        self.client.on('subscribed', self.on_subscribed)
        self.client.on('connected', self.on_connected)
        self.client.on('removed', self.on_removed)
        self.client.on('closed', self.on_closed)
        self.client.on('logged_in', self.on_logged_in)

        self.displayName = conf.get('sussexlogin', 'room_name')
        self.vu_min = -70
        self.vu_range = 40
        self.do_vu = 0
        self.last_vu = None
        self.ip = socket.gethostbyname(socket.gethostname())
        self.id = conf.get('ingest', 'hostname')
        self._user = conf.get('ddp', 'user')
        self._password = conf.get('ddp', 'password')
        self._http_host = conf.get('ddp', 'http_host')
        self._audiostream_port = conf.get('audiostream', 'port') or 31337
        self.netreg_id = conf.get('ddp', 'netreg_id')
        self.store_audio = conf.get_boolean('ddp', 'store_audio')
        self.paused = False
        self.recording = False
        self.currentMediaPackage = None
        self.currentProfile = None
        self.has_disconnected = False

        cam_available = conf.get('sussexlogin',
                                 'cam_available') or cam_available
        if cam_available in ('True', 'true', True, '1', 1):
            self.cam_available = 1
        elif cam_available in ('False', 'false', False, '0', 0):
            self.cam_available = 0
        else:
            self.cam_available = int(cam_available)

        self.audiofaders = []
        faders = conf.get('ddp', 'audiofaders').split()
        for fader in faders:
            audiofader = {}
            fader = 'audiofader-' + fader
            audiofader['name'] = conf.get(fader, 'name')
            audiofader['display'] = conf.get(fader, 'display')
            audiofader['min'] = conf.get_int(fader, 'min')
            audiofader['max'] = conf.get_int(fader, 'max')
            audiofader['type'] = conf.get(fader, 'type')
            audiofader['setrec'] = conf.get_boolean(fader, 'setrec')
            audiofader['mute'] = conf.get_boolean(fader, 'mute')
            audiofader['unmute'] = conf.get_boolean(fader, 'unmute')
            audiofader['setlevel'] = conf.get_int(fader, 'setlevel')
            try:
                audiofader['control'] = alsaaudio.Mixer(
                    control=audiofader['name'])
                self.audiofaders.append(audiofader)
            except Exception as e:
                logger.warn(e)
        fd, eventmask = self.audiofaders[0]['control'].polldescriptors()[0]
        self.watchid = gobject.io_add_watch(fd, eventmask, self.mixer_changed)

        dispatcher.connect('galicaster-init', self.on_init)
        dispatcher.connect('update-rec-vumeter', self.vumeter)
        dispatcher.connect('galicaster-notify-timer-short', self.heartbeat)
        dispatcher.connect('start-before', self.on_start_recording)
        dispatcher.connect('restart-preview', self.on_stop_recording)
        dispatcher.connect('update-rec-status', self.on_rec_status_update)

    def run(self):
        self.connect()

    def connect(self):
        if not self.has_disconnected:
            try:
                self.client.connect()
            except Exception:
                logger.warn('DDP connection failed')

    def update(self, collection, query, update):
        if self.client.connected and self.subscribedTo('GalicasterControl'):
            try:
                self.client.update(collection,
                                   query,
                                   update,
                                   callback=self.update_callback)
            except Exception:
                logger.warn("Error updating document "
                            "{collection: %s, query: %s, update: %s}" %
                            (collection, query, update))

    def insert(self, collection, document):
        if self.client.connected and self.subscribedTo('GalicasterControl'):
            try:
                self.client.insert(collection,
                                   document,
                                   callback=self.insert_callback)
            except Exception:
                logger.warn(
                    "Error inserting document {collection: %s, document: %s}" %
                    (collection, document))

    def heartbeat(self, element):
        if self.client.connected:
            self.update_images()
        else:
            self.connect()

    def on_start_recording(self, sender, id):
        self.recording = True
        self.currentMediaPackage = self.media_package_metadata(id)
        self.currentProfile = context.get_state().profile.name
        self.update('rooms', {'_id': self.id}, {
            '$set': {
                'currentMediaPackage': self.currentMediaPackage,
                'currentProfile': self.currentProfile,
                'recording': self.recording
            }
        })

    def on_stop_recording(self, sender=None):
        self.recording = False
        self.currentMediaPackage = None
        self.currentProfile = None
        self.update('rooms', {'_id': self.id}, {
            '$unset': {
                'currentMediaPackage': '',
                'currentProfile': ''
            },
            '$set': {
                'recording': self.recording
            }
        })
        self.update_images(1.5)

    def on_init(self, data):
        self.update_images(1.5)

    def update_images(self, delay=0):
        worker = Thread(target=self._update_images, args=(delay, ))
        worker.start()

    def _update_images(self, delay):
        time.sleep(delay)
        files = {}
        audio_devices = ['audiotest', 'autoaudio', 'pulse']
        for track in context.get_state().profile.tracks:
            if track.device not in audio_devices:
                file = os.path.join('/tmp', track.file + '.jpg')
                try:
                    if (os.path.getctime(file) > time.time() - 3):
                        files[track.flavor] = (track.flavor + '.jpg',
                                               open(file, 'rb'), 'image/jpeg')
                except Exception:
                    logger.warn("Unable to check date of or open file (%s)" %
                                file)
        im = ImageGrab.grab(bbox=(10, 10, 1280, 720), backend='imagemagick')
        im.thumbnail((640, 360))
        output = cStringIO.StringIO()
        if im.mode != "RGB":
            im = im.convert("RGB")
        im.save(output, format="JPEG")
        files['galicaster'] = ('galicaster.jpg', output.getvalue(),
                               'image/jpeg')
        try:
            # add verify=False for testing self signed certs
            requests.post("%s/image/%s" % (self._http_host, self.id),
                          files=files,
                          auth=(self._user, self._password))
        except Exception:
            logger.warn('Unable to post images')

    def mixer_changed(self, source=None, condition=None, reopen=True):
        if reopen:
            for audiofader in self.audiofaders:
                audiofader['control'] = alsaaudio.Mixer(
                    control=audiofader['name'])
        self.update_audio()
        return True

    def vumeter(self, element, data):
        if self.do_vu == 0:
            if data == "Inf":
                data = 0
            else:
                if data < -self.vu_range:
                    data = -self.vu_range
                elif data > 0:
                    data = 0
            data = int(((data + self.vu_range) / float(self.vu_range)) * 100)
            if data != self.last_vu:
                update = {'vumeter': data}
                self.update('rooms', {'_id': self.id}, {'$set': update})
                self.last_vu = data
        self.do_vu = (self.do_vu + 1) % 20

    def on_rec_status_update(self, element, data):
        is_paused = data == 'Paused'
        if is_paused:
            self.update_images(.75)
        if self.paused != is_paused:
            self.update('rooms', {'_id': self.id},
                        {'$set': {
                            'paused': is_paused
                        }})
            self.paused = is_paused
        if data == '  Recording  ':
            subprocess.call(['killall', 'maliit-server'])
            self.update_images(.75)

    def media_package_metadata(self, id):
        mp = context.get_repository().get(id)
        line = mp.metadata_episode.copy()
        duration = mp.getDuration()
        line["duration"] = long(duration / 1000) if duration else None
        # Does series_title need sanitising as well as duration?
        created = mp.getDate()
        line["created"] = calendar.timegm(created.utctimetuple())
        for key, value in mp.metadata_series.iteritems():
            line["series_" + key] = value
        for key, value in line.iteritems():
            if value in [None, []]:
                line[key] = ''
        return line

    def subscription_callback(self, error):
        if error:
            logger.warn("Subscription callback returned error: %s" % error)

    def insert_callback(self, error, data):
        if error:
            logger.warn("Insert callback returned error: %s" % error)

    def update_callback(self, error, data):
        if error:
            logger.warn("Update callback returned error: %s" % error)

    def on_subscribed(self, subscription):
        if (subscription == 'GalicasterControl'):
            me = self.client.find_one('rooms')
            stream_key = uuid.uuid4().get_hex()

            # Data to push when inserting or updating
            data = {
                'displayName': self.displayName,
                'ip': self.ip,
                'paused': self.paused,
                'recording': self.recording,
                'heartbeat': int(time.time()),
                'camAvailable': self.cam_available,
                'netregId': self.netreg_id,
                'inputs': self.inputs(),
                'stream': {
                    'port': self._audiostream_port,
                    'key': stream_key
                },
                'galicasterVersion': galicaster.__version__
            }
            if self.currentMediaPackage:
                data['currentMediaPackage'] = self.currentMediaPackage
            if self.currentProfile:
                data['currentProfile'] = self.currentProfile

            if me:
                # Items to unset
                unset = {}
                if not self.currentMediaPackage:
                    unset['currentMediaPackage'] = ''
                if not self.currentProfile:
                    unset['currentProfile'] = ''

                # Update to push
                update = {'$set': data}

                if unset:
                    update['$unset'] = unset
                self.update('rooms', {'_id': self.id}, update)
            else:
                audio = self.read_audio_settings()
                data['_id'] = self.id
                data['audio'] = audio
                self.insert('rooms', data)

    def inputs(self):
        inputs = {'presentations': ['Presentation']}
        inputs['cameras'] = []
        labels = conf.get('sussexlogin', 'matrix_cam_labels')
        cam_labels = []
        if labels:
            cam_labels = [l.strip() for l in labels.split(',')]
        for i in range(0, self.cam_available):
            label = cam_labels[i] if i < len(cam_labels) else "Camera %d" % (
                i + 1)
            inputs['cameras'].append(label)
        return inputs

    def set_audio(self, fields):
        faders = fields.get('audio')
        if faders:
            for fader in faders:
                mixer = None
                level = fader.get('level')
                for audiofader in self.audiofaders:
                    if audiofader['name'] == fader['name']:
                        mixer = audiofader['control']
                        break
                if mixer:
                    l, r = mixer.getvolume(fader['type'])
                    if level >= 0 and l != level:
                        mixer.setvolume(level, 0, fader['type'])
                        mixer.setvolume(level, 1, fader['type'])
            if self.store_audio:
                # Relies on no password sudo access for current user to alsactl
                subprocess.call(['sudo', 'alsactl', 'store'])

    def on_added(self, collection, id, fields):
        self.set_audio(fields)
        self.update_audio()

    def on_changed(self, collection, id, fields, cleared):
        self.set_audio(fields)
        me = self.client.find_one('rooms')
        if self.paused != me['paused']:
            self.set_paused(me['paused'])
        if context.get_state().is_recording != me['recording']:
            self.set_recording(me)

    def on_removed(self, collection, id):
        self.on_subscribed(None)

    def set_paused(self, new_status):
        self.paused = new_status
        dispatcher.emit("toggle-pause-rec")

    def set_recording(self, me):
        self.recording = me['recording']
        if self.recording:
            meta = me.get('currentMediaPackage', {}) or {}
            profile = me.get('currentProfile', 'nocam')
            series = (meta.get('series_title', ''), meta.get('isPartOf', ''))
            user = {
                'user_name': meta.get('creator', ''),
                'user_id': meta.get('rightsHolder', '')
            }
            title = meta.get('title', 'Unknown')
            dispatcher.emit('sussexlogin-record',
                            (user, title, series, profile))
        else:
            dispatcher.emit("stop-record", '')

    def on_connected(self):
        logger.info('Connected to Meteor')
        token = conf.get('ddp', 'token')
        self.client.login(self._user, self._password, token=token)

    def on_logged_in(self, data):
        conf.set('ddp', 'token', data['token'])
        conf.update()
        try:
            self.client.subscribe('GalicasterControl',
                                  params=[self.id],
                                  callback=self.subscription_callback)
        except Exception:
            logger.warn('DDP subscription failed')

    def on_closed(self, code, reason):
        self.has_disconnected = True
        logger.error('Disconnected from Meteor: err %d - %s' % (code, reason))

    def update_audio(self):
        me = self.client.find_one('rooms')
        audio = self.read_audio_settings()
        update = False
        if me:
            mAudio = me.get('audio')
            mAudioNames = [x['name'] for x in mAudio]
            audioNames = [x['name'] for x in audio]
            if set(mAudioNames) != set(audioNames):
                update = True
            if not update:
                for key, fader in enumerate(audio):
                    if mAudio[key].get('level') != fader.get('level'):
                        update = True
            if update:
                self.update('rooms', {'_id': self.id},
                            {'$set': {
                                'audio': audio
                            }})

    def read_audio_settings(self):
        audio_settings = []
        for audiofader in self.audiofaders:
            if audiofader['display']:
                audio_settings.append(self.control_values(audiofader))
            # ensure fixed values
            mixer = audiofader['control']
            if audiofader['setrec']:
                mixer.setrec(1)
            if audiofader['mute']:
                mixer.setmute(1)
            if audiofader['unmute']:
                mixer.setmute(0)
            if audiofader['setlevel'] >= 0:
                mixer.setvolume(audiofader['setlevel'], 0, audiofader['type'])
                if 'Joined Playback Volume' not in mixer.volumecap():
                    mixer.setvolume(audiofader['setlevel'], 1,
                                    audiofader['type'])
        return audio_settings

    def control_values(self, audiofader):
        controls = {}
        left, right = audiofader['control'].getvolume(audiofader['type'])
        controls['min'] = audiofader['min']
        controls['max'] = audiofader['max']
        controls['level'] = left
        controls['type'] = audiofader['type']
        controls['name'] = audiofader['name']
        controls['display'] = audiofader['display']
        return controls

    def subscribedTo(self, publication):
        return self.client.subscriptions.get(publication) is not None
Exemplo n.º 7
0
class DDP(Thread):

    def __init__(self):
        Thread.__init__(self)
        self.meteor = conf.get('ddp', 'meteor')

        self.client = MeteorClient(self.meteor, debug=False)
        self.client.on('added', self.on_added)
        self.client.on('changed', self.on_changed)
        self.client.on('subscribed', self.on_subscribed)
        self.client.on('connected', self.on_connected)
        self.client.on('removed', self.on_removed)
        self.client.on('closed', self.on_closed)
        self.client.on('logged_in', self.on_logged_in)

        self.displayName = conf.get('ddp', 'room_name')
        self.vu_min = -50
        self.vu_range = 50
        self.vu_data = 0
        self.last_vu = None
        self.ip = conf.get('ingest', 'address')
        self.id = conf.get('ingest', 'hostname')
        self._user = conf.get('ddp', 'user')
        self._password = conf.get('ddp', 'password')
        self._http_host = conf.get('ddp', 'http_host')
        self._audiostream_port = conf.get('audiostream', 'port') or 31337
        self.store_audio = conf.get_boolean('ddp', 'store_audio')
        self.screenshot_file = conf.get('ddp', 'existing_screenshot')
        self.high_quality = conf.get_boolean('ddp', 'hq_snapshot')
        self.paused = False
        self.recording = False
        self.currentMediaPackage = None
        self.currentProfile = None
        self.has_disconnected = False
        screen = Gdk.Screen.get_default()
        self._screen_width = screen.get_width()
        self._screen_height = screen.get_height()
        self.cardindex = None

        cam_available = conf.get(
            'ddp',
            'cam_available') or 0
        if cam_available in ('True', 'true', True, '1', 1):
            self.cam_available = 1
        elif cam_available in ('False', 'false', False, '0', 0):
            self.cam_available = 0
        else:
            self.cam_available = int(cam_available)
        # Getting audiostream params. either using existing audiostreaming server like icecast or the audiostream plugin
        if conf.get('ddp', 'existing_stream_host'):
            self._stream_host = conf.get('ddp', 'existing_stream_host')
        else:
            self._stream_host = self.ip

        if conf.get_int('ddp', 'existing_stream_port'):
            self._audiostream_port = conf.get_int('ddp', 'existing_stream_port')
        else:
            self._audiostream_port = conf.get_int('audiostream', 'port') or 31337

        if conf.get('ddp', 'existing_stream_key'):
            self.stream_key = conf.get('ddp', 'existing_stream_key')
        else:
            self.stream_key = uuid.uuid4().get_hex()

        if conf.get('ddp', 'extra_params'):
            self.extra_params_list = conf.get('ddp', 'extra_params').split(';')
        else:
            self.extra_params_list = []
        logger.info('audiostream URI: {}'.format('http://' + self._stream_host + ':' + str(self._audiostream_port) + '/' + self.stream_key))

        dispatcher.connect('init', self.on_init)
        dispatcher.connect('recorder-vumeter', self.vumeter)
        dispatcher.connect('timer-short', self.update_vu)
        dispatcher.connect('timer-short', self.heartbeat)
        dispatcher.connect('recorder-started', self.on_start_recording)
        dispatcher.connect('recorder-stopped', self.on_stop_recording)
        dispatcher.connect('recorder-status', self.on_rec_status_update)

    def run(self):
        self.connect()

    def connect(self):
        if not self.has_disconnected:
            try:
                self.client.connect()
            except Exception:
                logger.warn('DDP connection failed')

    def update(self, collection, query, update):
        if self.client.connected and self.subscribedTo('GalicasterControl'):
            try:
                self.client.update(
                    collection,
                    query,
                    update,
                    callback=self.update_callback)
            except Exception:
                logger.warn(
                    "Error updating document "
                    "{collection: %s, query: %s, update: %s}" %
                    (collection, query, update))

    def insert(self, collection, document):
        if self.client.connected and self.subscribedTo('GalicasterControl'):
            try:
                self.client.insert(
                    collection,
                    document,
                    callback=self.insert_callback)
            except Exception:
                logger.warn(
                    "Error inserting document {collection: %s, document: %s}" %
                    (collection, document))

    def heartbeat(self, element):
        if self.client.connected:
            self.update_images()
        else:
            self.connect()

    def on_start_recording(self, sender, id):
        self.recording = True
        self.currentMediaPackage = self.media_package_metadata(id)
        self.currentProfile = conf.get_current_profile().name
        self.update(
            'rooms', {
                '_id': self.id
            }, {
                '$set': {
                    'currentMediaPackage': self.currentMediaPackage,
                    'currentProfile': self.currentProfile,
                    'recording': self.recording
                }
            })

    def on_stop_recording(self, mpid, sender=None):
        self.recording = False
        self.currentMediaPackage = None
        self.currentProfile = None
        self.update(
            'rooms', {
                '_id': self.id
            }, {
                '$unset': {
                    'currentMediaPackage': '',
                    'currentProfile': ''
                }, '$set': {
                    'recording': self.recording
                }
            })
        self.update_images(1.5)

    def on_init(self, data):
        self.update_images(1.5)

    def update_images(self, delay=0.0):
        worker = Thread(target=self._update_images, args=(delay,))
        worker.start()

    def _update_images(self, delay):
        time.sleep(delay)
        files = {}

        if not self.screenshot_file:
            # take a screenshot with pyscreenshot
            im = ImageGrab.grab(bbox=(0, 0, self._screen_width, self._screen_height), backend='imagemagick')
        else:
            try:
                # used if screenshot already exists
                im = Image.open(self.screenshot_file)
            except IOError as e:
                logger.warn("Unable to open screenshot file {0}".format(self.screenshot_file))
                return
        output = cStringIO.StringIO()
        image_format = 'JPEG'
        if not self.high_quality:
            im.thumbnail((640, 360), Image.ANTIALIAS)
        else:
            image_format = 'PNG'

        if im.mode != "RGB":
            im = im.convert("RGB")
        im.save(output, format=image_format) # to reduce jpeg size use param: optimize=True
        files['galicaster'] = ('galicaster.jpg', output.getvalue(),
                               'image/jpeg')
        try:
            # add verify=False for testing self signed certs
            requests.post(
                "%s/image/%s" %
                (self._http_host, self.id), files=files, auth=(
                    self._user, self._password)) # to ignore ssl verification, use param: verify=False
        except Exception:
            logger.warn('Unable to post images')

    def vumeter(self, element, data, data_chan2, vu_bool):
        if data == "Inf":
            data = 0
        else:
            if data < -self.vu_range:
                data = -self.vu_range
            elif data > 0:
                data = 0
        self.vu_data = int(((data + self.vu_range) / float(self.vu_range)) * 100)

    def update_vu(self, element):
        if self.vu_data != self.last_vu:
                update = {'vumeter': self.vu_data}
                self.update('rooms', {'_id': self.id}, {'$set': update})
                self.last_vu = self.vu_data

    def on_rec_status_update(self, element, data):
        if data == 'paused':
            is_paused = True
        else:
            is_paused = False
        if is_paused:
            self.update_images(.75)
        if self.paused == is_paused:
            self.update(
                'rooms', {
                    '_id': self.id}, {
                    '$set': {
                        'paused': is_paused}})
            self.paused = is_paused
        if data == 'recording':
            self.update_images(.75)

    def media_package_metadata(self, id):
        mp = context.get('recorder').current_mediapackage
        line = mp.metadata_episode
        duration = mp.getDuration()
        line["duration"] = long(duration / 1000) if duration else None
        # FIXME Does series_title need sanitising as well as duration?
        created = mp.getDate()
        # line["created"] = calendar.timegm(created.utctimetuple())
        for key, value in mp.metadata_series.iteritems():
            line["series_" + key] = value
        for key, value in line.iteritems():
            if value in [None, []]:
                line[key] = ''
        # return line
        return line

    def subscription_callback(self, error):
        if error:
            logger.warn("Subscription callback returned error: %s" % error)

    def insert_callback(self, error, data):
        if error:
            logger.warn("Insert callback returned error: %s" % error)

    def update_callback(self, error, data):
        if error:
            logger.warn("Update callback returned error: %s" % error)

    def on_subscribed(self, subscription):
        if(subscription == 'GalicasterControl'):
            me = self.client.find_one('rooms')
            # Data to push when inserting or updating
            data = {
                'displayName': self.displayName,
                'ip': self.ip,
                'paused': self.paused,
                'recording': self.recording,
                'heartbeat': int(time.time()),
                'camAvailable': self.cam_available,
                'inputs': self.inputs(),
                'stream': {
                    'host': self._stream_host,
                    'port': self._audiostream_port,
                    'key': self.stream_key
                }
            }
            # Parse extra Meteor Mongodb collection elements and append
            for params in self.extra_params_list:
                param = params.split(':')
                data[param[0]] = param[1]

            if self.currentMediaPackage:
                data['currentMediaPackage'] = self.currentMediaPackage
            if self.currentProfile:
                data['currentProfile'] = self.currentProfile

            if me:
                # Items to unset
                unset = {}
                if not self.currentMediaPackage:
                    unset['currentMediaPackage'] = ''
                if not self.currentProfile:
                    unset['currentProfile'] = ''

                # Update to push
                update = {
                    '$set': data
                }

                if unset:
                    update['$unset'] = unset
                self.update('rooms', {'_id': self.id}, update)
            else:
                data['_id'] = self.id
                self.insert('rooms', data)

    def inputs(self):
        inputs = {
            'presentations': ['Presentation']
        }
        inputs['cameras'] = []
        labels = conf.get('ddp', 'cam_labels')
        cam_labels = []
        if labels:
            cam_labels = [l.strip() for l in labels.split(',')]
        for i in range(0, self.cam_available):
            label = cam_labels[i] if i < len(
                cam_labels) else "Camera %d" % (i + 1)
            inputs['cameras'].append(label)
        return inputs

    def on_added(self, collection, id, fields):
        pass

    def on_changed(self, collection, id, fields, cleared):
        me = self.client.find_one('rooms')
        if self.paused != me['paused']:
            self.set_paused(me['paused'])

        if context.get('recorder').is_recording() != me['recording']:
            self.set_recording(me)

    def on_removed(self, collection, id):
        self.on_subscribed(None)

    def set_paused(self, new_status):
        if not self.paused:
            self.paused = new_status
            context.get('recorder').pause()
        else:
            self.paused = False
            context.get('recorder').resume()


    def set_recording(self, me):
        self.recording = me['recording']
        if self.recording:
            # FIXME: Metadata isn't passed to recorder
            meta = me.get('currentMediaPackage', {}) or {}
            profile = me.get('currentProfile', 'nocam')
            series = (meta.get('series_title', ''), meta.get('isPartOf', ''))
            user = {'user_name': meta.get('creator', ''),
                    'user_id': meta.get('rightsHolder', '')}
            title = meta.get('title', 'Unknown')
            context.get('recorder').record()
        else:
            context.get('recorder').stop()

    def on_connected(self):
        logger.info('Connected to Meteor')
        token = conf.get('ddp', 'token')
        self.client.login(self._user, self._password, token=token)

    def on_logged_in(self, data):
        conf.set('ddp', 'token', data['token'])
        conf.update()
        try:
            self.client.subscribe(
                'GalicasterControl',
                params=[
                    self.id],
                callback=self.subscription_callback)
        except Exception:
            logger.warn('DDP subscription failed')

    def on_closed(self, code, reason):
        self.has_disconnected = True
        logger.error('Disconnected from Meteor: err %d - %s' % (code, reason))

    def subscribedTo(self, publication):
        return self.client.subscriptions.get(publication) != None
Exemplo n.º 8
0
def processDirectory(path, newCorporaName, newCorporaID, nextDocumentID):
   
   print("Processing files...")

   # Connect to Pterraformer
   client = MeteorClient('ws://127.0.0.1:4567/websocket')
   client.connect()

   # ID of the next available Document record
   id = nextDocumentID
   # ID of the next available Corpus record
   corpusID = newCorporaID

   # Create a new Collection
   client.insert('corpora', { '_id': str(corpusID), 'owner': "public", 'properties': { '@context': 'http://schema.org', 'name': newCorporaName, 'modifyDate': '14/6/14'}})

   
   types = ('./*.pdf', './*.docx', './*.txt') # the tuple of file types

   # Must work with the path object to allow specification of the correct directory
   files_grabbed = []
   for files in types:
       files_grabbed.extend(glob.glob(files))
       
   files_grabbed   # the list of pdf and cpp files


   for filename in files_grabbed:
       print(filename)
       fileExtensionType = filename.split(".")[-1]
       
       if (fileExtensionType == "pdf"):
           rawText = convert_pdf_to_txt(filename)
       elif (fileExtensionType == "docx"):
           rawText = convert_docx_to_txt(filename)
       else:
           rawText = convert_txt_to_txt(filename)
           
       id2 = id
       id = id + 1
       
       #print(rawText[:50])
       
       client.insert('documents', { '_id': str(id2),
           'corpus': str(corpusID),
           'rawText': rawText,
           'properties': {
             '@context': 'http://schema.org/',
             '@type': 'CreativeWork',
             'name': filename,
             'modifyDate': '13/4/2015'
           },
           'parsingResults': {
           },
           'placeReferences': [
           ],
           'matchedPlaces': {
             "type": "FeatureCollection",
             "features": []
           },
           'markedUpText': "hello"
         }, callback=insert_callback)
Exemplo n.º 9
0
import time

from MeteorClient import MeteorClient

client = MeteorClient('ws://127.0.0.1:3000/websocket', debug=True)
client.connect()

client.subscribe('SessionsList')

time.sleep(1)

sessions = client.find('sessions')
session_to_join = sessions[0]

client.subscribe(session_to_join['title'])  # GPS data should follow this
time.sleep(1)

for i in range(0, 5):
    gps = {
        'sessionID': session_to_join['_id'],
        'lat': 110,
        'long': 220,
        'time': time.strftime("%I:%M:%S")
    }
    client.insert("GPSData", gps)
    time.sleep(2)