Пример #1
0
    def select_devices(self):
        """Loads the bins and creates the preview areas for the active profile, creating a new mediapacakge."""
        logger.info("Setting Devices the new way")
        self.mediapackage = mediapackage.Mediapackage()
        self.mediapackage.setTitle("Recording started at " +
                                   datetime.datetime.now().replace(
                                       microsecond=0).isoformat())
        current_profile = self.conf.get_current_profile()
        bins = current_profile.tracks

        for objectbin in bins:
            objectbin['path'] = self.repo.get_attach_path()
        devices = current_profile.get_video_areas()
        areas = self.create_drawing_areas(devices)

        self.error_text = None
        self.error_dialog = None
        if self.error_id:
            logger.info("Error in select devices " + str(self.error_id))
            self.dispatcher.disconnect(self.error_id)
        self.error_id = self.dispatcher.connect("recorder-error",
                                                self.handle_pipeline_error)
        self.audiobar.ClearVumeter()
        self.record = Recorder(bins, areas)
        self.record.mute_preview(not self.focus_is_active)
        return True
Пример #2
0
 def init_recorder(self):
     self.recorder = Recorder(self.bins, self.areas)
     self.recorder.mute_preview(not self.focus_is_active)
     ok = self.recorder.preview()
     if ok:
         if self.mediapackage.manual:
             self.change_state(GC_PREVIEW)
     else:
         if self.restarting:
             logger.error("Restarting Preview Failed")
         self.change_state(GC_ERROR)
         if self.scheduled_recording:
             self.on_failed_scheduled(self.current_mediapackage)
Пример #3
0
    def select_devices(self):
        """Loads the bins and creates the preview areas for the active profile, creating a new mediapacakge."""
        logger.info("Setting Devices the new way")
        self.mediapackage = mediapackage.Mediapackage()
        self.mediapackage.setTitle("Recording started at "+ datetime.datetime.now().replace(microsecond = 0).isoformat())
        current_profile = self.conf.get_current_profile()        
        bins = current_profile.tracks

        for objectbin in bins:
            objectbin['path']=self.repo.get_attach_path()
        devices = current_profile.get_video_areas()
        areas = self.create_drawing_areas(devices)    
        
        self.error_text = None
        self.error_dialog = None
        if self.error_id:
            logger.info("Error in select devices "+str(self.error_id))
            self.dispatcher.disconnect(self.error_id)
        self.error_id = self.dispatcher.connect(
            "recorder-error",
            self.handle_pipeline_error)
        self.audiobar.ClearVumeter()
        self.record = Recorder(bins, areas) 
        self.record.mute_preview(not self.focus_is_active)   
        return True
Пример #4
0
 def init_recorder(self):
     self.recorder = Recorder(self.bins, self.areas) 
     self.recorder.mute_preview(not self.focus_is_active)   
     ok =self.recorder.preview()
     if ok :
         if  self.mediapackage.manual:
             self.mediapackage.setTitle("Recording started at "+ datetime.datetime.now().replace(microsecond = 0).isoformat())
             self.change_state(GC_PREVIEW)
     else:
         if self.restarting:
             logger.error("Restarting Preview Failed")
         self.change_state(GC_ERROR)
Пример #5
0
 def init_recorder(self):
     self.recorder = Recorder(self.bins, self.areas) 
     self.recorder.mute_preview(not self.focus_is_active)   
     ok = self.recorder.preview()
     if ok :
         if self.mediapackage.manual:
             self.change_state(GC_PREVIEW)
     else:
         if self.restarting:
             logger.error("Restarting Preview Failed")
         self.change_state(GC_ERROR)
         if self.scheduled_recording:
             self.on_failed_scheduled(self.current_mediapackage)
Пример #6
0
    def init_recorder(self):
        if self.error_dialog:
            self.error_dialog.dialog_destroy()
            self.error_dialog = None
            self.error_text = None
        self.audiobar.ClearVumeter()
        context.get_state().is_error = False

        current_profile = self.conf.get_current_profile()
        bins = current_profile.tracks
        for objectbin in bins:
            objectbin['path'] = self.repo.get_rectemp_path()

        self.recorder = Recorder(bins) 
        self.recorder.mute_preview(not self.focus_is_active)   
        info = self.recorder.get_display_areas_info()
        if self.swap: 
            info.reverse()
        areas = self.create_drawing_areas(info)
        self.recorder.set_drawing_areas(areas)

        if self.start_recording:
            self.start_recording = False
            ok = self.recorder.preview_and_record()
            self.mediapackage = self.repo.get(self.current_mediapackage)
            # NOTE only call on_rec to update UI. Recorder is already recording.
            self.on_rec()
        else:
            ok = self.recorder.preview()
        if ok :
            if self.mediapackage.manual:
                self.change_state(GC_PREVIEW)
        else:
            logger.error("Restarting Preview Failed")
            context.get_state().is_error = True
            self.change_state(GC_ERROR)
            if self.scheduled_recording:
                self.on_failed_scheduled(self.current_mediapackage)    
Пример #7
0
class RecorderClassUI(gtk.Box):
    """
    Graphic User Interface for Record alone
    """

    __gtype_name__ = 'RecorderClass'

    def __init__(self, package=None):

        logger.info("Creating Recording Area")
        gtk.Box.__init__(self)
        builder = gtk.Builder()
        builder.add_from_file(get_ui_path('recorder.glade'))

        self.repo = context.get_repository()
        self.dispatcher = context.get_dispatcher()
        self.worker = context.get_worker()
        self.record = None
        self.current_mediapackage = None
        self.current = None
        self.next = None
        self.restarting = False
        self.font = None
        self.scheduled_recording = False
        self.focus_is_active = False
        self.net_activity = None

        self.error_id = None
        self.error_text = None
        self.error_dialog = None
        self.start_id = None

        # BUILD
        self.recorderui = builder.get_object("recorderbox")
        self.main_area = builder.get_object("videobox")
        self.areas = None
        self.vubox = builder.get_object("vubox")
        self.gui = builder

        # BIG STATUS
        big_status = builder.get_object("bg_status")
        self.view = self.set_status_view()
        big_status.add(self.view)

        # STATUS BAR
        self.statusbar = status_bar.StatusBarClass()
        self.dispatcher.connect("update-rec-status", self.statusbar.SetStatus)
        self.dispatcher.connect("update-video", self.statusbar.SetVideo)
        self.dispatcher.connect("galicaster-init", self.check_status_area)
        self.dispatcher.connect("galicaster-init", self.check_net)
        self.dispatcher.connect("restart-preview", self.check_status_area)
        self.dispatcher.connect("net-up", self.check_net, True)
        self.dispatcher.connect("net-down", self.check_net, False)
        self.statusbar.SetTimer(0)

        # VUMETER
        self.audiobar = AudioBarClass()

        # UI
        self.vubox.add(self.audiobar.bar)
        self.pack_start(self.recorderui, True, True, 0)

        # Event Manager
        self.dispatcher.connect("start-record", self.on_scheduled_start)
        self.dispatcher.connect("stop-record", self.on_scheduled_stop)
        self.dispatcher.connect("start-before", self.on_start_before)
        self.dispatcher.connect("restart-preview", self.on_restart_preview)
        self.dispatcher.connect("update-rec-vumeter", self.audiobar.SetVumeter)
        self.dispatcher.connect("galicaster-status", self.event_change_mode)
        self.dispatcher.connect("galicaster-notify-quit", self.close)

        nb = builder.get_object("data_panel")
        pages = nb.get_n_pages()
        for index in range(pages):
            page = nb.get_nth_page(index)
            nb.set_tab_label_packing(page, True, True, gtk.PACK_START)

        # STATES
        self.status = GC_INIT
        self.previous = None
        self.change_state(GC_INIT)

        self.dispatcher.connect("reload_profile", self.on_recover_from_error)

        # PERMISSIONS
        self.conf = context.get_conf()
        self.allow_pause = self.conf.get_permission("pause")
        self.allow_start = self.conf.get_permission("start")
        self.allow_stop = self.conf.get_permission("stop")
        self.allow_manual = self.conf.get_permission("manual")
        self.allow_overlap = self.conf.get_permission("overlap")

        # OTHER
        builder.connect_signals(self)
        self.net_activity = self.conf.get_boolean('ingest', 'active')

        self.change_state(GC_READY)

        self.proportion = 1
        self.on_start()

        # SCHEDULER FEEDBACK
        self.scheduler_thread_id = 1
        self.clock_thread_id = 1
        self.start_thread_id = None

        self.scheduler_thread = thread(target=self.scheduler_launch_thread)
        self.clock_thread = thread(target=self.clock_launch_thread)
        self.scheduler_thread.daemon = True
        self.clock_thread.daemon = True
        self.scheduler_thread.start()
        self.clock_thread.start()
        self.dispatcher.emit("galicaster-init")

    def select_devices(self):
        """Loads the bins and creates the preview areas for the active profile, creating a new mediapacakge."""
        logger.info("Setting Devices the new way")
        self.mediapackage = mediapackage.Mediapackage()
        self.mediapackage.setTitle("Recording started at " +
                                   datetime.datetime.now().replace(
                                       microsecond=0).isoformat())
        current_profile = self.conf.get_current_profile()
        bins = current_profile.tracks

        for objectbin in bins:
            objectbin['path'] = self.repo.get_attach_path()
        devices = current_profile.get_video_areas()
        areas = self.create_drawing_areas(devices)

        self.error_text = None
        self.error_dialog = None
        if self.error_id:
            logger.info("Error in select devices " + str(self.error_id))
            self.dispatcher.disconnect(self.error_id)
        self.error_id = self.dispatcher.connect("recorder-error",
                                                self.handle_pipeline_error)
        self.audiobar.ClearVumeter()
        self.record = Recorder(bins, areas)
        self.record.mute_preview(not self.focus_is_active)
        return True

    #  ------------------------- PLAYER ACTIONS ------------------------

    def on_start(self, button=None):
        """Preview at start - Galicaster initialization"""
        logger.info("Starting Preview")
        self.conf.reload()

        #self.start_id = self.dispatcher.connect("start-preview", self.on_start_button)
        self.on_start_button()
        return True

    def on_start_button(self, button=None):
        """Triggers bin loading and start preview"""
        self.select_devices()
        #self.dispatcher.disconnect(self.start_id)
        #self.start_id = None
        ok = self.record.preview()
        if ok:
            if self.mediapackage.manual:
                self.mediapackage.setTitle("Recording started at " +
                                           datetime.datetime.now().replace(
                                               microsecond=0).isoformat())
                self.change_state(GC_PREVIEW)
            else:
                self.change_state(GC_ERROR)

    def on_restart_preview(self, button=None, element=None):
        """Restarting preview, commanded by record"""
        logger.info("Restarting Preview")
        self.conf.reload()
        ok = self.select_devices()
        if ok:
            self.record.preview()
            self.change_state(GC_PREVIEW)
        else:
            logger.error("Restarting Preview Failed")
            self.change_state(GC_ERROR)
        self.restarting = False
        return True

    def on_rec(self, button=None):
        """Manual Recording """
        logger.info("Recording")
        self.dispatcher.emit("starting-record")
        self.record.record()
        self.mediapackage.status = mediapackage.RECORDING
        self.mediapackage.setDate(
            datetime.datetime.utcnow().replace(microsecond=0))
        self.clock = self.record.get_clock()
        self.timer_thread_id = 1
        self.timer_thread = thread(target=self.timer_launch_thread)
        self.timer_thread.daemon = True
        self.timer_thread.start()
        self.change_state(GC_RECORDING)
        return True

    def on_start_before(self, origin, key):
        """ Start a recording before its schedule """
        logger.info("Start recording before schedule")
        self.mediapackage = self.repo.get(key)
        self.mediapackage.manual = True
        self.on_rec()
        return True

    def on_pause(self, button):
        """Pauses or resumes a recording"""
        if self.status == GC_PAUSED:
            logger.debug("Resuming Recording")
            self.change_state(GC_RECORDING)
            self.record.resume()
        elif self.status == GC_RECORDING:
            logger.debug("Pausing Recording")
            self.change_state(GC_PAUSED)
            self.record.pause()
            gui = gtk.Builder()
            gui.add_from_file(get_ui_path("paused.glade"))
            dialog = gui.get_object("dialog")
            self.pause_dialog = dialog
            #image = gui.get_object("image")
            button = gui.get_object("button")
            dialog.set_transient_for(self.get_toplevel())

            response = dialog.run()
            if response == 1:
                self.on_pause(None)
            dialog.destroy()

    def on_stop(self, button):
        """Stops preview or recording and closes the Mediapakage"""
        if self.conf.get_boolean("basic", "stopdialog"):
            text = {
                "title": "Stop",
                "main": "Are you sure you want to\nstop the recording?",
            }
            buttons = ("Stop", gtk.RESPONSE_OK, gtk.STOCK_CANCEL,
                       gtk.RESPONSE_REJECT)
            warning = message.PopUp(message.WARNING, text,
                                    context.get_mainwindow(), buttons)

            if warning.response not in message.POSITIVE:
                return False

        if self.scheduled_recording:
            self.current_mediapackage = None
            self.current = None
            self.scheduled_recording = False
        self.close_recording()

    def close_recording(self):
        """Set the final data on the mediapackage, stop the record and restart the preview"""
        close_duration = (self.clock.get_time() -
                          self.initial_time) * 1000 / gst.SECOND
        # To avoid error messages on stopping pipelines
        if self.error_dialog:
            self.error_dialog.destroy()
            self.error_dialog = None
        self.record.stop_record_and_restart_preview()
        self.change_state(GC_STOP)

        self.mediapackage.status = mediapackage.RECORDED
        self.mediapackage.properties['origin'] = self.conf.hostname
        self.repo.add_after_rec(self.mediapackage, self.record.bins_desc,
                                close_duration)

        code = 'manual' if self.mediapackage.manual else 'scheduled'
        if self.conf.get_lower('ingest', code) == 'immediately':
            self.worker.ingest(self.mediapackage)
        elif self.conf.get_lower('ingest', code) == 'nightly':
            self.worker.ingest_nightly(self.mediapackage)

        self.timer_thread_id = None

    def on_scheduled_start(self, source, identifier):
        """Starts a scheduled recording, replacing the mediapackage in use"""
        logger.info("Scheduled Start")
        self.conf.reload()
        self.current_mediapackage = identifier
        self.scheduled_recording = True
        a = thread(target=self.start_thread, args=(identifier, ))
        a.daemon = False
        a.start()

    def start_thread(self, identifier):
        """Thread handling a scheduled recording"""
        self.start_thread_id = 1

        if self.status == GC_PREVIEW:  # Record directly
            self.mediapackage = self.repo.get(self.current_mediapackage)
            self.on_rec()

        elif self.status in [GC_RECORDING, GC_PAUSED]:

            if self.allow_overlap:
                pass
                # TODO: dont stop and extend recording until the end of the new interval
                # In case of stop, restart with the overlapped job

            else:  # Stop current recording, wait until prewiew restarted and record
                self.restarting = True
                self.close_recording()
                while self.restarting:
                    time.sleep(0.1)
                    if self.start_thread_id == None:
                        return
                self.mediapackage = self.repo.get(self.current_mediapackage)
                self.on_rec()

        elif self.status == GC_INIT:  # Start Preview and Record
            self.on_start_button()
            while self.record.get_status() != gst.STATE_PLAYING:
                time.sleep(0.2)
                if self.start_thread_id == None:
                    return
            self.mediapackage = self.repo.get(self.current_mediapackage)
            self.on_rec()

        title = self.repo.get(identifier).title
        self.dispatcher.emit("update-video", title)

        return None

    def on_scheduled_stop(self, source, identifier):
        """Updates the mediapackage information after a scheduled recoring."""
        logger.info("Scheduled Stop")
        self.current_mediapackage = None
        self.current = None
        self.close_recording()
        self.scheduled_recording = False

    def reload_state_and_permissions(self):
        """Force a state review in case permissions had changed."""
        self.conf.reload()
        self.allow_pause = self.conf.get_permission("pause")
        self.allow_start = self.conf.get_permission("start")
        self.allow_stop = self.conf.get_permission("stop")
        self.allow_manual = self.conf.get_permission("manual")
        self.allow_overlap = self.conf.get_permission("overlap")
        self.change_state(self.status)

    def reload_state(self):
        """Force a state review in case situation had changed"""
        self.change_state(self.status)

    def on_help(self, button):
        """Triggers a pop-up when Help button is clicked"""
        logger.info("Help requested")

        text = {
            "title": "Help",
            "main": " Visit galicaster.teltek.es",
            "text": " ...or contact us on our community list."
        }
        buttons = None
        message.PopUp(message.INFO, text, context.get_mainwindow(), buttons)

    def restart(self):  # FIXME name confusing cause on_restart_preview
        """Called by Core, if in preview, reload configuration and restart preview."""
        if self.status == GC_STOP:
            self.on_start()

        elif self.status == GC_PREVIEW:
            self.change_state(GC_STOP)
            self.record.just_restart_preview()
        else:
            logger.warning("Restart preview called while Recording")

        return True

    def handle_pipeline_error(self, origin, error_message):
        """ Captures a pipeline error.
        If the recording are is active, shows it
        """
        self.change_state(GC_ERROR)
        if self.error_id:
            self.dispatcher.disconnect(self.error_id)
            self.error_id = None

        self.error_text = error_message
        if self.focus_is_active:
            self.launch_error_message(error_message)

    def launch_error_message(self, error_message):
        """Shows an active error message."""
        text = {
            "title": "Recorder",
            "main":
            " Please review your configuration \nor load another profile",
            "text": error_message
        }
        buttons = None
        logger.error("ERROR: " + error_message)
        self.error_dialog = message.PopUp(message.ERROR, text,
                                          context.get_mainwindow(), buttons)

    def on_recover_from_error(self, origin):
        """If an error ocurred, removes preview areas and disconnect error handlers."""
        if self.status in [GC_ERROR, GC_STOP]:
            main = self.main_area
            for child in main.get_children():
                main.remove(child)
                child.destroy()
            self.change_state(GC_INIT)
            self.on_start()

        elif self.status in [GC_PREVIEW, GC_PRE2]:
            #self.restart()
            self.record.stop_preview()
            self.dispatcher.disconnect(self.error_id)
            self.error_id = None
            self.change_state(GC_STOP)
            main = self.main_area
            for child in main.get_children():
                main.remove(child)
                child.destroy()
            self.change_state(GC_INIT)
            self.on_start()

        elif self.status != GC_RECORDING:
            logger.debug("Won't recover from this status")

        else:
            logger.error(
                "Profile changed on the middle of a recording (or something)")

    def on_quit(self, button=None):
        """Close active preview or recoridng and destroys the UI"""
        gui = gtk.Builder()
        gui.add_from_file(get_ui_path("quit.glade"))
        dialog = gui.get_object("dialog")
        dialog.set_transient_for(self.get_toplevel())

        response = dialog.run()
        if response == gtk.RESPONSE_OK:
            dialog.destroy()
            if self.status >= GC_PREVIEW:
                self.record.stop_preview()

            self.change_state(GC_EXIT)
            logger.info("Closing Clock and Scheduler")

            self.scheduler_thread_id = None
            self.clock_thread = None
            # threads closed
            self.emit("delete_event", gtk.gdk.Event(gtk.gdk.DELETE))
        else:
            dialog.destroy()
        return True

    # ------------------------- THREADS ------------------------------

    def timer_launch_thread(self):
        """Thread handling the recording elapsed time timer."""

        # Based on: http://pygstdocs.berlios.de/pygst-tutorial/seeking.html

        thread_id = self.timer_thread_id
        self.initial_time = self.clock.get_time()
        self.initial_datetime = datetime.datetime.utcnow().replace(
            microsecond=0)
        gtk.gdk.threads_enter()
        self.statusbar.SetTimer(0)
        gtk.gdk.threads_leave()

        rec_title = self.gui.get_object("recording1")
        rec_elapsed = self.gui.get_object("recording3")

        while thread_id == self.timer_thread_id:
            #while True:
            actual_time = self.clock.get_time()
            timer = (actual_time - self.initial_time) / gst.SECOND
            dif = datetime.datetime.utcnow() - self.initial_datetime

            if thread_id == self.timer_thread_id:
                gtk.gdk.threads_enter()
                self.statusbar.SetTimer(timer)
                if rec_title.get_text() != self.mediapackage.title:
                    rec_title.set_text(self.mediapackage.title)
                rec_elapsed.set_text("Elapsed Time: " +
                                     self.time_readable(dif))
                gtk.gdk.threads_leave()
            time.sleep(0.2)
        return True

    def scheduler_launch_thread(self):
        """Thread handling the messages scheduler notification area."""
        # Based on: http://pygstdocs.berlios.de/pygst-tutorial/seeking.html
        thread_id = self.scheduler_thread_id
        event_type = self.gui.get_object("nextlabel")
        title = self.gui.get_object("titlelabel")
        status = self.gui.get_object("eventlabel")

        # Status panel
        # status_disk = self.gui.get_object("status1")
        # status_hours = self.gui.get_object("status2")
        # status_mh = self.gui.get_object("status3")

        self.check_schedule()
        parpadeo = True
        changed = False
        signalized = False

        if self.font == None:
            anchura = self.get_toplevel().get_screen().get_width()
            if anchura not in [1024, 1280, 1920]:
                anchura = 1920
            k1 = anchura / 1920.0
            changing_font = pango.FontDescription("bold " + str(k1 * 42))
            self.font = changing_font

        bold = pango.AttrWeight(700, 0, -1)
        red = pango.AttrForeground(65535, 0, 0, 0, -1)
        black = pango.AttrForeground(17753, 17753, 17753, 0, -1)
        font = pango.AttrFontDesc(self.font, 0, -1)

        attr_red = pango.AttrList()
        attr_black = pango.AttrList()

        attr_red.insert(red)
        attr_red.insert(font)
        attr_red.insert(bold)

        attr_black.insert(black)
        attr_black.insert(font)
        attr_black.insert(bold)

        status.set_attributes(attr_black)
        one_second = datetime.timedelta(seconds=1)
        while thread_id == self.scheduler_thread_id:
            if self.font != changing_font:
                attr_black.insert(pango.AttrFontDesc(self.font, 0, -1))
                attr_red.insert(pango.AttrFontDesc(self.font, 0, -1))
                changing_font = self.font
            if self.current:
                start = self.current.getLocalDate()
                duration = self.current.getDuration() / 1000
                end = start + datetime.timedelta(seconds=duration)
                dif = end - datetime.datetime.now()
                #dif2 = datetime.datetime.now() - start
                if dif < datetime.timedelta(0, 0):  # Checking for malfuntions
                    self.current = None
                    self.current_mediapackage = None
                    status.set_text("")
                else:
                    status.set_text("Stopping on " +
                                    self.time_readable(dif + one_second))
                    if event_type.get_text() != CURRENT_TEXT:
                        event_type.set_text(CURRENT_TEXT)
                    if title.get_text() != self.current.title:
                        title.set_text(self.current.title)

                    if dif < datetime.timedelta(0, TIME_RED_STOP):
                        if not changed:
                            status.set_attributes(attr_red)
                            changed = True
                    elif changed:
                        status.set_attributes(attr_black)
                        changed = False
                    if dif < datetime.timedelta(0, TIME_BLINK_STOP):
                        parpadeo = False if parpadeo else True
                # Timer(diff,self.check_schedule)

            elif self.next:
                start = self.next.getLocalDate()
                dif = start - datetime.datetime.now()
                if event_type.get_text != NEXT_TEXT:
                    event_type.set_text(NEXT_TEXT)
                if title.get_text() != self.next.title:
                    title.set_text(self.next.title)
                status.set_text("Starting on " + self.time_readable(dif))

                if dif < datetime.timedelta(0, TIME_RED_START):
                    if not changed:
                        status.set_attributes(attr_red)
                        changed = True
                elif changed:
                    status.set_attributes(attr_black)
                    changed = False

                if dif < datetime.timedelta(0, TIME_UPCOMING):
                    if not signalized:
                        self.dispatcher.emit("upcoming-recording")
                        signalized = True
                elif signalized:
                    signalized = True

                if dif < datetime.timedelta(0, TIME_BLINK_START):
                    if parpadeo:
                        status.set_text("")
                        parpadeo = False
                    else:
                        parpadeo = True
                # Timer(60,self.check_schedule)

            else:  # Not current or pending recordings
                if event_type.get_text():
                    event_type.set_text("")
                if status.get_text():
                    status.set_text("")
                if title.get_text() != "No upcoming events":
                    title.set_text("No upcoming events")

            time.sleep(0.5)
            self.check_schedule()
        return True

    def clock_launch_thread(self):
        """
        Based on: http://pygstdocs.berlios.de/pygst-tutorial/seeking.html
        """
        thread_id = self.clock_thread_id
        clock = self.gui.get_object("local_clock")

        while thread_id == self.clock_thread_id:
            if thread_id == self.clock_thread_id:
                clocktime = datetime.datetime.now().time().strftime("%H:%M")
                clock.set_label(clocktime)
            time.sleep(1)
        return True

    def time_readable(self, timedif):
        """
        Take a timedelta and return it formatted
        """

        if timedif < datetime.timedelta(0, 300):  # 5 minutes tops
            formatted = "{minutes:02d}:{seconds:02d}".format(
                minutes=timedif.seconds // 60, seconds=timedif.seconds % 60)
        elif timedif < datetime.timedelta(1, 0):  # 24 hours
            formatted = "{hours:02d}:{minutes:02d}:{seconds:02d}".format(
                hours=timedif.days * 24 + timedif.seconds // 3600,
                minutes=timedif.seconds % 3600 // 60,
                seconds=timedif.seconds % 60)
        else:  # days
            today = datetime.datetime.now()
            then = today + timedif
            dif = then.date() - today.date()
            formatted = "{days} day{plural}".format(
                days=dif.days, plural='s' if dif.days > 1 else '')

        return formatted

    def check_schedule(self):
        # previous1 = self. current
        previous2 = self.next
        if self.current_mediapackage == None:
            self.current = None
        else:
            self.current = self.repo.get(self.current_mediapackage)
        previous2 = self.next
        self.next = self.repo.get_next_mediapackage()  # could be None
        if previous2 != self.next:
            self.reload_state()

    # ------------------------- POPUP ACTIONS ------------------------

    def on_edit_meta(self, button):
        """Pops up the  Metadata editor of the active Mediapackage"""
        #self.change_state(GC_BLOCKED)
        if not self.scheduled_recording:
            Metadata(self.mediapackage, parent=self)
            self.statusbar.SetVideo(
                None, self.mediapackage.metadata_episode['title'])
            self.statusbar.SetPresenter(None, self.mediapackage.creators)
        #self.change_state(self.previous)
        return True

    def show_next(self, button=None, tipe=None):
        """Pops up the Event Manager"""
        EventManager()
        return True

    def show_about(self, button=None, tipe=None):
        """Pops up de About Dialgo"""
        GCAboutDialog()

    # -------------------------- UI ACTIONS -----------------------------

    def create_drawing_areas(self, source):
        """Create as preview areas as video sources exits"""
        main = self.main_area

        for child in main.get_children():
            main.remove(child)
            child.destroy()
        areas = None
        areas = dict()
        for key, value in source.iteritems():
            new_area = gtk.DrawingArea()
            new_area.set_name("videoarea" + str(key))
            new_area.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("black"))
            areas[re.sub(r'\W+', '', value)] = new_area
            main.pack_start(new_area, True, True, int(self.proportion * 3))

        for child in main.get_children():
            child.show()

        return areas

    def event_change_mode(self, orig, old_state, new_state):
        """Handles the focus or the Rercording Area, launching messages when focus is recoverde"""
        if new_state == 0:
            self.focus_is_active = True
            if self.record:
                self.record.mute_preview(False)
            if self.error_text:
                if self.status != GC_ERROR:
                    self.change_state(GC_ERROR)
                self.launch_error_message(self.error_text)

        if old_state == 0:
            self.focus_is_active = False
            if self.record:
                self.record.mute_preview(True)

    def change_mode(self, button):
        """Launch the signal to change to another area"""
        self.dispatcher.emit("change-mode", 3)  # FIXME use constant

    def set_status_view(self):
        """Set the message and color of the status pilot on the top bar"""

        size = context.get_mainwindow().get_size()
        # k1 = size[0] / 1920.0
        k2 = size[1] / 1080.0

        l = gtk.ListStore(str, str, str)

        main_window = context.get_mainwindow()
        main_window.realize()
        style = main_window.get_style()

        bgcolor = style.bg[gtk.STATE_PRELIGHT]
        fgcolor = style.fg[gtk.STATE_PRELIGHT]

        for i in STATUS:
            if i[0] in ["Recording", "Error"]:
                l.append([i[0], i[1], fgcolor])
            else:
                l.append([i[0], bgcolor, fgcolor])

        v = gtk.CellView()
        v.set_model(l)

        r = gtk.CellRendererText()
        self.renderer = r
        r.set_alignment(0.5, 0.5)
        r.set_fixed_size(int(k2 * 400), -1)

        # k1 = size[0] / 1920.0
        k2 = size[1] / 1080.0
        font = pango.FontDescription("bold " + str(int(k2 * 48)))
        r.set_property('font-desc', font)
        v.pack_start(r, True)
        v.add_attribute(r, "text", 0)
        v.add_attribute(r, "background", 1)
        v.add_attribute(r, "foreground", 2)
        v.set_displayed_row(0)
        return v

    def check_status_area(self, origin, signal=None, other=None):
        """Updates the values on the recording tab"""
        s1 = self.gui.get_object("status1")
        s2 = self.gui.get_object("status2")
        # s3 = self.gui.get_object("status3")
        s4 = self.gui.get_object("status4")

        freespace, text_space = status_bar.GetFreeSpace(
            self.repo.get_attach_path())
        s1.set_text(text_space)
        four_gb = 4000000000.0
        hours = int(freespace / four_gb)
        s2.set_text(str(hours) + " hours left")
        agent = context.get_state().hostname  # TODO just consult it once
        if s4.get_text() != agent:
            s4.set_text(agent)

    def check_net(self, origin, status=None):
        """Update the value of the network status"""
        attr1 = pango.AttrList()
        attr2 = pango.AttrList()
        attr3 = pango.AttrList()
        attr4 = pango.AttrList()
        gray = pango.AttrForeground(20000, 20000, 20000, 0, -1)
        red = pango.AttrForeground(65535, 0, 0, 0, -1)
        green = pango.AttrForeground(0, 65535, 0, 0, -1)
        black = pango.AttrForeground(5000, 5000, 5000, 0, -1)
        attr1.insert(gray)
        attr2.insert(green)
        attr3.insert(red)
        attr4.insert(black)

        s3 = self.gui.get_object("status3")
        if not self.net_activity:
            s3.set_text("Disabled")
            s3.set_attributes(attr1)
        else:
            net = status or context.get_state().net
            try:
                if net:
                    s3.set_text("Up")
                    s3.set_attributes(attr2)
                else:
                    s3.set_text("Down")
                    s3.set_attributes(attr3)
            except KeyError:
                s3.set_text("Connecting")
                s3.set_attributes(attr4)

    def resize(self):
        """Adapts GUI elements to the screen size"""
        size = context.get_mainwindow().get_size()
        altura = size[1]
        anchura = size[0]

        k1 = anchura / 1920.0
        k2 = altura / 1080.0
        self.proportion = k1

        #Recorder
        clock = self.gui.get_object("local_clock")
        logo = self.gui.get_object("classlogo")
        nextl = self.gui.get_object("nextlabel")
        title = self.gui.get_object("titlelabel")
        # eventl = self.gui.get_object("eventlabel")
        pbox = self.gui.get_object("prebox")

        rec_title = self.gui.get_object("recording1")
        rec_elapsed = self.gui.get_object("recording3")
        status_panel = self.gui.get_object('status_panel')

        l1 = self.gui.get_object("tab1")
        l2 = self.gui.get_object("tab2")
        l3 = self.gui.get_object("tab3")

        relabel(clock, k1 * 25, False)
        font = pango.FontDescription("bold " + str(int(k2 * 48)))
        self.renderer.set_property('font-desc', font)
        self.renderer.set_fixed_size(int(k2 * 400), -1)
        pixbuf = gtk.gdk.pixbuf_new_from_file(get_image_path('logo.svg'))
        pixbuf = pixbuf.scale_simple(int(pixbuf.get_width() * k1),
                                     int(pixbuf.get_height() * k1),
                                     gtk.gdk.INTERP_BILINEAR)
        logo.set_from_pixbuf(pixbuf)

        modification = "bold " + str(k1 * 42)
        self.font = pango.FontDescription(modification)
        relabel(nextl, k1 * 25, True)
        relabel(title, k1 * 33, True)

        # REC AND STATUS PANEL
        relabel(rec_title, k1 * 25, True)
        rec_title.set_line_wrap(True)
        rec_title.set_width_chars(40)
        relabel(rec_elapsed, k1 * 28, True)

        for child in status_panel.get_children():
            if type(child) is gtk.Label:
                relabel(child, k1 * 19, True)
        relabel(l1, k1 * 20, False)
        relabel(l2, k1 * 20, False)
        relabel(l3, k1 * 20, False)

        for name in ["recbutton", "pausebutton", "stopbutton", "helpbutton"]:
            button = self.gui.get_object(name)
            button.set_property("width-request", int(k1 * 100))
            button.set_property("height-request", int(k1 * 100))

            image = button.get_children()
            if type(image[0]) == gtk.Image:
                image[0].set_pixel_size(int(k1 * 80))
            elif type(image[0]) == gtk.VBox:
                for element in image[0].get_children():
                    if type(element) == gtk.Image:
                        element.set_pixel_size(int(k1 * 46))
            else:
                relabel(image[0], k1 * 28, False)

        for name in ["previousbutton", "morebutton"]:
            button = self.gui.get_object(name)
            button.set_property("width-request", int(k1 * 70))
            button.set_property("height-request", int(k1 * 70))

            image = button.get_children()
            if type(image[0]) == gtk.Image:
                image[0].set_pixel_size(int(k1 * 56))

        talign = self.gui.get_object("top_align")
        talign.set_padding(int(k1 * 10), int(k1 * 25), 0, 0)
        calign = self.gui.get_object("control_align")
        calign.set_padding(int(k1 * 10), int(k1 * 30), int(k1 * 50),
                           int(k1 * 50))
        vum = self.gui.get_object("vubox")
        vum.set_padding(int(k1 * 20), int(k1 * 10), int(k1 * 40), int(k1 * 40))
        pbox.set_property("width-request", int(k1 * 225))
        return True

    def change_state(self, state):
        """Activates or deactivates the buttons depending on the new state"""
        record = self.gui.get_object("recbutton")
        pause = self.gui.get_object("pausebutton")
        stop = self.gui.get_object("stopbutton")
        helpb = self.gui.get_object("helpbutton")
        editb = self.gui.get_object("editbutton")
        prevb = self.gui.get_object("previousbutton")

        if state != self.status:
            self.previous, self.status = self.status, state

        if state == GC_INIT:
            record.set_sensitive(False)
            pause.set_sensitive(False)
            stop.set_sensitive(False)
            helpb.set_sensitive(True)
            prevb.set_sensitive(True)
            editb.set_sensitive(False)
            self.dispatcher.emit("update-rec-status", "Initialization")

        elif state == GC_PREVIEW:
            record.set_sensitive((self.allow_start or self.allow_manual))
            pause.set_sensitive(False)
            pause.set_active(False)
            stop.set_sensitive(False)
            helpb.set_sensitive(True)
            prevb.set_sensitive(True)
            editb.set_sensitive(False)
            if self.next == None:
                self.dispatcher.emit("update-rec-status", "Idle")
            else:
                self.dispatcher.emit("update-rec-status", "Waiting")

        elif state == GC_RECORDING:
            record.set_sensitive(False)
            pause.set_sensitive(self.allow_pause and self.record.is_pausable())
            stop.set_sensitive((self.allow_stop or self.allow_manual))
            helpb.set_sensitive(True)
            prevb.set_sensitive(False)
            editb.set_sensitive(True and not self.scheduled_recording)
            self.dispatcher.emit("update-rec-status", "  Recording  ")

        elif state == GC_PAUSED:
            record.set_sensitive(False)
            pause.set_sensitive(False)
            stop.set_sensitive(False)
            prevb.set_sensitive(False)
            helpb.set_sensitive(False)
            editb.set_sensitive(False)

            self.dispatcher.emit("update-rec-status", "Paused")

        elif state == GC_STOP:
            if self.previous == GC_PAUSED:
                self.pause_dialog.destroy()
            record.set_sensitive(False)
            pause.set_sensitive(False)
            stop.set_sensitive(False)
            helpb.set_sensitive(True)
            prevb.set_sensitive(True)
            editb.set_sensitive(False)
            self.dispatcher.emit("update-rec-status", "Stopped")

        elif state == GC_BLOCKED:
            record.set_sensitive(False)
            pause.set_sensitive(False)
            stop.set_sensitive(False)
            helpb.set_sensitive(False)
            prevb.set_sensitive(False)
            editb.set_sensitive(False)

        elif state == GC_ERROR:
            record.set_sensitive(False)
            pause.set_sensitive(False)
            stop.set_sensitive(False)
            helpb.set_sensitive(True)
            prevb.set_sensitive(True)
            editb.set_sensitive(False)

        if self.next == None and state == GC_PREVIEW:
            self.view.set_displayed_row(GC_PRE2)
        else:
            self.view.set_displayed_row(state)

    def block(self):
        prev = self.gui.get_object("prebox")
        prev.set_child_visible(False)
        self.focus_is_active = True
        self.event_change_mode(None, 3, 0)

        # Show Help or Edit_meta
        helpbutton = self.gui.get_object("helpbutton")
        helpbutton.set_visible(True)
        editbutton = self.gui.get_object("editbutton")
        editbutton.set_visible(False)

        # Start Preview
        self.dispatcher.emit("start-preview")

    def close(self, signal):
        """Handles the area closure, stopping threads, mediapackage and preview"""
        if self.status in [GC_RECORDING]:
            self.close_recording()
        self.scheduler_thread_id = None
        self.clock_thread_id = None
        self.start_thread_id = None
        if self.status in [GC_PREVIEW]:
            self.record.stop_preview()
        return True
Пример #8
0
class RecorderClassUI(gtk.Box):
    """
    Graphic User Interface for Record alone
    """

    __gtype_name__ = 'RecorderClass'

    def __init__(self, package=None): 
  
        logger.info("Creating Recording Area")
        gtk.Box.__init__(self)
	builder = gtk.Builder()
        builder.add_from_file(get_ui_path('recorder.glade'))
       
        self.repo = context.get_repository()
        self.dispatcher = context.get_dispatcher()
        self.worker = context.get_worker()
        self.recorder = None
        self.current_mediapackage = None
        self.current = None
        self.next = None
        self.restarting = False
        self.font = None
        self.scheduled_recording = False
        self.focus_is_active = False
        self.net_activity = None

        self.error_id = None
        self.error_text = None
        self.error_dialog = None
        self.ok_to_show = False
        self.swap_active = None
        self.swap = False

        # BUILD
        self.recorderui = builder.get_object("recorderbox")
        self.main_area = builder.get_object("videobox")
        self.vubox = builder.get_object("vubox")
        self.gui = builder

        # BIG STATUS
        big_status = builder.get_object("bg_status")
        self.view = self.set_status_view()
        big_status.add(self.view)

        # STATUS BAR
        self.statusbar=status_bar.StatusBarClass()
        self.dispatcher.connect("update-rec-status", self.statusbar.SetStatus)
        self.dispatcher.connect("update-video", self.statusbar.SetVideo)
        self.dispatcher.connect("galicaster-init", self.check_status_area)
        self.dispatcher.connect("galicaster-init", self.check_net)
        self.dispatcher.connect("restart-preview", self.check_status_area)
        self.dispatcher.connect("net-up", self.check_net, True)        
        self.dispatcher.connect("net-down", self.check_net, False)        
        self.statusbar.SetTimer(0)

        # VUMETER
        self.audiobar=Vumeter()

        # UI
        self.vubox.add(self.audiobar)
        self.pack_start(self.recorderui,True,True,0)

        # Event Manager       
        self.dispatcher.connect("start-record", self.on_scheduled_start)
        self.dispatcher.connect("stop-record", self.on_stop)
        self.dispatcher.connect("start-before", self.on_start_before)
        self.dispatcher.connect("restart-preview", self.on_restart_preview)
        self.dispatcher.connect("update-rec-vumeter", self.audiobar.SetVumeter)
        self.dispatcher.connect("galicaster-status", self.event_change_mode)
        self.dispatcher.connect("galicaster-notify-quit", self.close)

        nb=builder.get_object("data_panel")
        pages = nb.get_n_pages()        
        for index in range(pages):
            page=nb.get_nth_page(index)
            nb.set_tab_label_packing(page, True, True,gtk.PACK_START)

        # STATES
        self.status = GC_INIT
        self.previous = None
        self.change_state(GC_INIT)

        self.dispatcher.connect("reload-profile", self.on_recover_from_error)

        # PERMISSIONS
        self.conf = context.get_conf()
        self.allow_pause = self.conf.get_permission("pause")
        self.allow_start = self.conf.get_permission("start")
        self.allow_stop = self.conf.get_permission("stop")
        self.allow_manual = self.conf.get_permission("manual")
        self.allow_overlap = self.conf.get_permission("overlap")
     
        # OTHER
        builder.connect_signals(self)
        self.net_activity = self.conf.get_boolean('ingest', 'active')

        self.change_state(GC_READY)

        self.proportion = 1
        self.on_start()

        # SCHEDULER FEEDBACK
        self.scheduler_thread_id = 1
        self.clock_thread_id = 1
        self.start_thread_id = None

        self.scheduler_thread = thread(target=self.scheduler_launch_thread)
        self.clock_thread = thread(target=self.clock_launch_thread)
        self.scheduler_thread.daemon = True
        self.clock_thread.daemon = True
        self.scheduler_thread.start()
        self.clock_thread.start() 
        self.dispatcher.emit("galicaster-init")

        # SHOW OR HIDE SWAP BUTTON
        if self.conf.get_boolean('basic', 'swapvideos'):
            self.swap_active = True
        else:
            self.swap_active = False

    # Handle for swap videos button
    def swap_videos(self, button=None):
        if self.swap:
            self.swap = False
        else:
            self.swap = True
        self.dispatcher.emit("reload-profile")
        self.audiobar.mute = False        
        self.audiobar.SetVumeter

    def select_devices(self):
        """Loads the bins and creates the preview areas for the active profile, creating a new mediapacakge."""
        self.configure_profile()
        logger.info("Setting Devices the new way")
        now = datetime.datetime.now().replace(microsecond=0)
        self.mediapackage = mediapackage.Mediapackage(title=_("Recording started at {0}").format(now.isoformat()))

        context.get_state().mp=self.mediapackage.identifier

        # profile load depending of the swap value 
        if self.swap:
            self.conf.orde_current_profile()            
            self.conf.reverse_current_profile()
        else:
            self.conf.reverse_current_profile()
            self.conf.orde_current_profile()

        current_profile = self.conf.get_current_profile()
        bins = current_profile.tracks

        for objectbin in bins:
            objectbin['path']=self.repo.get_rectemp_path()
        devices = current_profile.get_video_areas()
        areas = self.create_drawing_areas(devices)  

        self.bins = bins
        self.areas = areas
        
        if self.error_dialog:
            if self.error_id:
                self.dispatcher.disconnect(self.error_id)
                self.error_id = None
            self.error_dialog.dialog_destroy()
            self.error_dialog = None
            self.error_text = None

        self.error_id = self.dispatcher.connect(
            "recorder-error",
            self.handle_pipeline_error)
        self.audiobar.ClearVumeter()
        if self.ok_to_show:
            self.init_recorder()
        return True



    #  ------------------------- PLAYER ACTIONS ------------------------


    def on_start(self, button=None):
        """Preview at start - Galicaster initialization"""
        logger.info("Starting Preview")
        self.conf.reload()
        self.select_devices()
        return True

    def on_start_button(self, button=None):
        """Triggers bin loading and start preview"""
        self.select_devices()

    def init_recorder(self):
        self.recorder = Recorder(self.bins, self.areas) 
        self.recorder.mute_preview(not self.focus_is_active)   
        ok = self.recorder.preview()
        if ok :
            if self.mediapackage.manual:
                self.change_state(GC_PREVIEW)
        else:
            if self.restarting:
                logger.error("Restarting Preview Failed")
            self.change_state(GC_ERROR)
            if self.scheduled_recording:
                self.on_failed_scheduled(self.current_mediapackage)
                
            # TODO kill counter in case of error and scheduler

    def go_ahead(self):
        """Continue Recorder init create Record module and start_preview"""
        if not self.ok_to_show:
            self.init_recorder()
        self.ok_to_show = True

    def on_restart_preview(self, button=None, element=None): 
        """Restarting preview, commanded by record""" 
        logger.info("Restarting Preview")
        self.conf.reload()
        #self.configure_profile()
        self.select_devices()
        self.restarting = False
        return True

    def configure_profile(self):
        profile = self.conf.get_current_profile()
        context.get_state().profile = profile
        if profile.execute:
            out = os.system(profile.execute)
            logger.info("Executing {0} with out {1}".format(profile.execute, out))
            if out:
                self.dispatcher.emit("recorder-error", "Error executing command configuring profile")


    def on_rec(self,button=None): 
        """Manual Recording """
        logger.info("Recording")
        self.dispatcher.emit("starting-record")
        self.recorder.record()
        self.mediapackage.status=mediapackage.RECORDING
        now = datetime.datetime.utcnow().replace(microsecond=0)
        self.mediapackage.setDate(now)
        self.timer_thread_id = 1
        self.timer_thread = thread(target=self.timer_launch_thread) 
        self.timer_thread.daemon = True
        self.timer_thread.start()
        self.change_state(GC_RECORDING)
        context.get_state().is_recording = True
        return True  


    def on_start_before(self, origin, key):
        """ Start a recording before its schedule or via rest """
        if key:
            logger.info("Start recording before schedule")
            self.mediapackage = self.repo.get(key)
            context.get_state().mp=self.mediapackage.identifier
        else:
            logger.info("Rest triggered recording")
        self.on_rec()
        return True            


    def on_pause(self,button):
        """Pauses or resumes a recording"""
        if self.status == GC_PAUSED:
            self.dispatcher.emit("enable-no-audio")
            logger.debug("Resuming Recording")
            self.change_state(GC_RECORDING)
            self.recorder.resume()
        elif self.status == GC_RECORDING:
            self.dispatcher.emit("disable-no-audio")
            logger.debug("Pausing Recording")
            self.change_state(GC_PAUSED)
            self.recorder.pause()
            gui = gtk.Builder()
            gui.add_from_file(get_ui_path("paused.glade"))
            self.pause_dialog = self.create_pause_dialog(self.get_toplevel())
    
            response = self.pause_dialog.run()
            if response == 1:
                self.on_pause(None)
            self.pause_dialog.destroy()     


    def create_pause_dialog(self, parent):
       
        gui = gtk.Builder()
        gui.add_from_file(get_ui_path("paused.glade"))
        dialog = gui.get_object("dialog") 
        dialog.set_transient_for(parent)
        dialog.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_TOOLBAR)
        dialog.set_modal(True)
        dialog.set_keep_above(False)
        dialog.set_skip_taskbar_hint(True)
        size = context.get_mainwindow().get_size()
        k2 = size[1] / 1080.0
        size= int(k2*150)
        dialog.set_default_size(size,size)
        button = gui.get_object("image")
        pixbuf = gtk.gdk.pixbuf_new_from_file(get_image_path('gc-pause.svg'))
        pixbuf = pixbuf.scale_simple(
            size,
            size,
            gtk.gdk.INTERP_BILINEAR)
        button.set_from_pixbuf(pixbuf)
        return dialog

            
    def on_ask_stop(self,button):
        """Stops preview or recording and closes the Mediapakage"""
        self.dispatcher.emit("disable-no-audio")
        if self.conf.get_boolean("basic", "stopdialog"):
            text = {"title" : _("Recorder"),
                    "main" : _("Are you sure you want to\nstop the recording?"),
            }
            buttons = ( gtk.STOCK_STOP, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT)
            warning = message.PopUp(message.WARNING, text,
              context.get_mainwindow(), buttons
            )
            self.dispatcher.emit("enable-no-audio")
            if warning.response not in message.POSITIVE:
                return False
            else:
                self.on_stop("UI","current")

    def on_stop(self,source,identifier): 
        """Close recording and clean schedule if neccesary"""
        if self.scheduled_recording:
            self.current_mediapackage = None
            self.current = None
            self.scheduled_recording = False
            logger.info("Scheduled Stop")
        else:
            logger.info("Stop recording")
        self.close_recording()  

    def close_recording(self):
        """Set the final data on the mediapackage, stop the record and restart the preview"""
        paused = self.paused_time.total_seconds()*1000000000 # pass to ns
        close_duration = int((self.recorder.get_time()-self.initial_time-paused)*1000/gst.SECOND)
        # To avoid error messages on stopping pipelines
        if self.error_dialog:
            if self.error_id:
                self.dispatcher.disconnect(self.error_id)
                self.error_id = None
            self.error_dialog.dialog_destroy()
            self.error_dialog = None
            self.error_text = None
        self.recorder.stop_record_and_restart_preview()
        self.change_state(GC_STOP)

        self.mediapackage.status = mediapackage.RECORDED
        self.mediapackage.properties['origin'] = self.conf.hostname
        self.repo.add_after_rec(self.mediapackage, self.recorder.bins_desc, 
                                close_duration, self.mediapackage.manual)
        
        code = 'manual' if self.mediapackage.manual else 'scheduled'
        if self.conf.get_lower('ingest', code) == 'immediately':
            self.worker.ingest(self.mediapackage)
        elif self.conf.get_lower('ingest', code) == 'nightly':
            self.worker.ingest_nightly(self.mediapackage)

        context.get_state().is_recording = False
        self.timer_thread_id = None

    def on_scheduled_start(self, source, identifier):
        """Starts a scheduled recording, replacing the mediapackage in use"""
        logger.info("Scheduled Start")
        self.conf.reload()
        self.current_mediapackage = identifier
        self.scheduled_recording = True
        #a=thread(target=self.start_thread, args=(identifier,))
        #a.daemon = False
        #a.start()
        if self.status == GC_PREVIEW: # Record directly
            self.mediapackage = self.repo.get(self.current_mediapackage)
            self.on_rec() 
        
        elif self.status in [ GC_RECORDING, GC_PAUSED ] :

            if self.allow_overlap:
                pass
                # TODO: dont stop and extend recording until the end of the new interval
                # In case of stop, restart with the overlapped job

            else: # Stop current recording, wait until prewiew restarted and record
                self.restarting = True
                self.close_recording()                
                while self.restarting:
                    time.sleep(0.1) 
                    #if self.start_thread_id == None:
                    #    return
                self.mediapackage = self.repo.get(self.current_mediapackage)   
                self.on_rec()       
                      
        elif self.status == GC_INIT:  # Start Preview and Record
            self.on_start_button()
            while self.record.get_status() != gst.STATE_PLAYING:
                time.sleep(0.2)
                if self.start_thread_id == None:
                    return
            self.mediapackage = self.repo.get(self.current_mediapackage)
            self.on_rec()

        title = self.repo.get(identifier).title
        self.dispatcher.emit("update-video", title)

    def start_thread(self,identifier):
        """Thread handling a scheduled recording"""
        self.start_thread_id = 1        
        if self.status == GC_PREVIEW: # Record directly
            self.mediapackage = self.repo.get(self.current_mediapackage)
            context.get_state().mp = self.mediapackage.identifier
            self.on_rec() 
        
        elif self.status in [ GC_RECORDING, GC_PAUSED ] :

            if self.allow_overlap:
                pass
                # TODO: dont stop and extend recording until the end of the new interval
                # In case of stop, restart with the overlapped job

            else: # Stop current recording, wait until prewiew restarted and record
                self.restarting = True
                self.close_recording()                
                while self.restarting:
                    time.sleep(0.1) 
                    if self.start_thread_id == None:
                        return
                self.mediapackage = self.repo.get(self.current_mediapackage)   
                self.on_rec()       
                      
        elif self.status == GC_INIT:  # Start Preview and Record
            self.on_start_button()
            while self.recorder.get_status() != gst.STATE_PLAYING:
                time.sleep(0.2)
                if self.start_thread_id == None:
                    return
            self.mediapackage = self.repo.get(self.current_mediapackage)
            self.on_rec()

        elif self.status == GC_ERROR:
            if self.error_dialog:
                if self.error_id:
                    self.dispatcher.disconnect(self.error_id)
                    self.error_id = None
                self.error_dialog.dialog_destroy()
                self.error_dialog = None
                self.error_text = None
            self.on_start_button()
            while self.recorder.get_status() != gst.STATE_PLAYING:
                time.sleep(0.2)
                if self.start_thread_id == None:
                    return
            self.mediapackage = self.repo.get(self.current_mediapackage)
            self.on_rec()              

        title = self.repo.get(identifier).title
        self.dispatcher.emit("update-video", title)        
        return None

    def on_scheduled_stop(self,source,identifier):
        """Updates the mediapackage information after a scheduled recoring."""
        logger.info("Scheduled Stop")
        self.current_mediapackage = None
        self.current = None
        self.close_recording()
        self.scheduled_recording = False

    def on_failed_scheduled(self, identifier):
        """Updates the mediapackage information after a scheduled recoring."""
        #TODO change MP status to failed 
        logger.info("Scheduled {0} failed on error".format(identifier))
        self.current_mediapackage = None
        self.current = None
        self.scheduled_recording = False
        self.start_thread_id = None


    def reload_state_and_permissions(self):
        """Force a state review in case permissions had changed."""
        self.conf.reload()
        self.allow_pause = self.conf.get_permission("pause")
        self.allow_start = self.conf.get_permission("start")
        self.allow_stop = self.conf.get_permission("stop")
        self.allow_manual = self.conf.get_permission("manual")
        self.allow_overlap = self.conf.get_permission("overlap")
        self.change_state(self.status)

    def reload_state(self):
        """Force a state review in case situation had changed"""
        self.change_state(self.status)



    def on_help(self,button):
        """Triggers a pop-up when Help button is clicked"""
        logger.info("Help requested")   

        text = {"title" : _("Help"),
                "main" : _(" Visit galicaster.teltek.es"),
                "text" : _(" ...or contact us on our community list.")
		}
        buttons = None
        message.PopUp(message.INFO, text,
                      context.get_mainwindow(), buttons)

    def restart(self): # FIXME name confusing cause on_restart_preview
        """Called by Core, if in preview, reload configuration and restart preview."""
        if self.status == GC_STOP:
            self.on_start()
            
        elif self.status == GC_PREVIEW:
            self.change_state(GC_STOP)
            self.recorder.just_restart_preview()
        else:
            logger.warning("Restart preview called while Recording")

        return True

    def handle_pipeline_error(self, origin, error_message):
        """ Captures a pipeline error.
        If the recording are is active, shows it
        """
        self.change_state(GC_ERROR)
        self.recorder.stop_elements()
        context.get_state().is_recording = False
        if self.error_id:
            self.dispatcher.disconnect(self.error_id)
            self.error_id = None
            #TODO kill previous error if needed
        
        self.error_text = error_message
        if self.focus_is_active:
            self.launch_error_message(error_message)
        
    def launch_error_message(self, error_message):
        """Shows an active error message."""
        text = {
            "title" : _("Recorder"),
            "main" : _(" Please review your configuration \nor load another profile"),                
            "text" : error_message
			}
        self.error_dialog = message.PopUp(message.ERROR, text, 
                                context.get_mainwindow(), None)
        
        

    def on_recover_from_error(self, origin):
        """If an error ocurred, removes preview areas and disconnect error handlers."""   

        if self.error_id:
            self.dispatcher.disconnect(self.error_id)
            self.error_id = None
            self.error_dialog = None
            self.error_text = None
     
        if self.status in [GC_ERROR,GC_STOP]:
            main = self.main_area  
            for child in main.get_children():
                main.remove(child)
                child.destroy()   
            self.change_state(GC_INIT)
            self.on_start()

        elif self.status in [GC_PREVIEW, GC_PRE2]:
            #self.restart()
            self.recorder.stop_preview()
            self.change_state(GC_STOP)
            main = self.main_area  
            for child in main.get_children():
                main.remove(child)
                child.destroy()   
            self.change_state(GC_INIT)
            self.on_start()            
                
        elif self.status != GC_RECORDING:
            logger.debug("Won't recover from this status")
        else:
            logger.error("Profile changed on the middle of a recording")


    def on_quit(self,button=None): 
        """Close active preview or recoridng and destroys the UI"""
        gui = gtk.Builder()
        gui.add_from_file(get_ui_path("quit.glade"))
        dialog = gui.get_object("dialog")
        dialog.set_transient_for(self.get_toplevel())

        response =dialog.run()
        if response == gtk.RESPONSE_OK:   
            dialog.destroy()
            if self.status >= GC_PREVIEW:
                self.recorder.stop_preview()

            self.change_state(GC_EXIT)
            logger.info("Closing Clock and Scheduler")

            self.scheduler_thread_id = None
            self.clock_thread = None 
            # threads closed
            self.emit("delete_event", gtk.gdk.Event(gtk.gdk.DELETE))    
        else:
            dialog.destroy()            
        return True

    # ------------------------- THREADS ------------------------------
 

    def timer_launch_thread(self):
        """Thread handling the recording elapsed time timer."""
        
        # Based on: http://pygstdocs.berlios.de/pygst-tutorial/seeking.html
        
        thread_id= self.timer_thread_id
        self.initial_time=self.recorder.get_time()
        self.initial_datetime=datetime.datetime.utcnow().replace(microsecond = 0)
        gtk.gdk.threads_enter()
        self.statusbar.SetTimer(0)
        gtk.gdk.threads_leave()
        self.paused_time = datetime.timedelta(0,0)

        rec_title = self.gui.get_object("recording1")
        rec_elapsed = self.gui.get_object("recording3")
              
        while thread_id == self.timer_thread_id:            
        #while True:
            actual_time=self.recorder.get_time()               
            timer=(actual_time-self.initial_time)/gst.SECOND
            if self.status==GC_PAUSED:
                self.paused_time = self.paused_time + datetime.timedelta(0,0,200000)               
            dif = datetime.datetime.utcnow() - self.initial_datetime - self.paused_time

            if thread_id==self.timer_thread_id:
                gtk.gdk.threads_enter()
                self.statusbar.SetTimer(timer)
                if rec_title.get_text() != self.mediapackage.getTitle():
                    rec_title.set_text(self.mediapackage.getTitle())
                rec_elapsed.set_text(_("Elapsed Time: ") + self.time_readable(dif))
                gtk.gdk.threads_leave()
            time.sleep(0.2)          
        return True

    def scheduler_launch_thread(self):
        """Thread handling the messages scheduler notification area."""
        # Based on: http://pygstdocs.berlios.de/pygst-tutorial/seeking.html
        thread_id= self.scheduler_thread_id
        event_type = self.gui.get_object("nextlabel")
        title = self.gui.get_object("titlelabel")
        status = self.gui.get_object("eventlabel")

        # Status panel
        # status_disk = self.gui.get_object("status1")
        # status_hours = self.gui.get_object("status2")
        # status_mh = self.gui.get_object("status3")

        self.check_schedule()
        parpadeo = True
        changed = False
        signalized = False
        
        if self.font == None:
            anchura = self.get_toplevel().get_screen().get_width()
            if anchura not in [1024,1280,1920]:
                anchura = 1920            
            k1 = anchura / 1920.0
            changing_font = pango.FontDescription("bold "+str(k1*42))       
            self.font = changing_font
        
        bold = pango.AttrWeight(700, 0, -1)
        red = pango.AttrForeground(65535, 0, 0, 0, -1)        
        black = pango.AttrForeground(17753, 17753, 17753, 0, -1)
        font=pango.AttrFontDesc(self.font, 0, -1)

        attr_red = pango.AttrList()
        attr_black = pango.AttrList()

        attr_red.insert(red)
        attr_red.insert(font)
        attr_red.insert(bold)

        attr_black.insert(black)
        attr_black.insert(font)
        attr_black.insert(bold)

        status.set_attributes(attr_black)
        one_second=datetime.timedelta(seconds=1)
        while thread_id == self.scheduler_thread_id: 
            if self.font != changing_font:
                attr_black.insert(pango.AttrFontDesc(self.font, 0, -1))
                attr_red.insert(pango.AttrFontDesc(self.font, 0, -1))
                changing_font = self.font
            if self.current:
                start = self.current.getLocalDate()
                duration = self.current.getDuration() / 1000
                end = start + datetime.timedelta(seconds=duration)
                dif = end - datetime.datetime.now()
                #dif2 = datetime.datetime.now() - start
                if dif < datetime.timedelta(0,0): # Checking for malfuntions
                    self.current = None
                    self.current_mediapackage = None
                    status.set_text("")
                else:
                    status.set_text(_("Stopping in {0}").format(self.time_readable(dif+one_second)))
                    if event_type.get_text() != CURRENT_TEXT:
                        event_type.set_text(CURRENT_TEXT) 
                    if title.get_text() != self.current.title:
                        title.set_text(self.current.title)             
                        
                    if dif < datetime.timedelta(0,TIME_RED_STOP):
                        if not changed:
                            status.set_attributes(attr_red)
                            changed = True
                    elif changed:
                        status.set_attributes(attr_black)
                        changed = False
                    if dif < datetime.timedelta(0,TIME_BLINK_STOP):
                        parpadeo = False if parpadeo else True
                # Timer(diff,self.check_schedule)

            elif self.next:
                start = self.next.getLocalDate()
                dif = start - datetime.datetime.now()
                if event_type.get_text != NEXT_TEXT:
                    event_type.set_text(NEXT_TEXT)
                if title.get_text() != self.next.title:
                    title.set_text(self.next.title)
                status.set_text(_("Starting in {0}").format(self.time_readable(dif)))

                if dif < datetime.timedelta(0,TIME_RED_START):
                    if not changed:
                        status.set_attributes(attr_red)
                        changed = True
                elif changed:
                    status.set_attributes(attr_black)
                    changed = False

                if dif < datetime.timedelta(0,TIME_UPCOMING):
                    if not signalized:
                        self.dispatcher.emit("upcoming-recording")
                        signalized = True
                elif signalized:
                    signalized = True                   

                if dif < datetime.timedelta(0,TIME_BLINK_START):
                    if parpadeo:
                        status.set_text("")
                        parpadeo =  False
                    else:
                        parpadeo = True
                # Timer(60,self.check_schedule)

            else: # Not current or pending recordings
                if event_type.get_text():                
                    event_type.set_text("")
                if status.get_text():
                    status.set_text("")
                if title.get_text() != _("No upcoming events"):
                    title.set_text(_("No upcoming events"))
                
            time.sleep(0.5)
            self.check_schedule()            
        return True


    def clock_launch_thread(self):
        """
        Based on: http://pygstdocs.berlios.de/pygst-tutorial/seeking.html
        """
        thread_id= self.clock_thread_id
        clock = self.gui.get_object("local_clock")

        while thread_id == self.clock_thread_id:            
            if thread_id==self.clock_thread_id:
                clocktime = datetime.datetime.now().time().strftime("%H:%M")
                clock.set_label(clocktime)           
            time.sleep(1)          
        return True


    def time_readable(self, timedif):
        """
        Take a timedelta and return it formatted
        """       
           
        if timedif < datetime.timedelta(0,300): # 5 minutes tops
            formatted = "{minutes:02d}:{seconds:02d}".format( 
                            minutes = timedif.seconds // 60, 
                            seconds = timedif.seconds % 60 )
        elif timedif < datetime.timedelta(1,0): # 24 hours
            formatted = "{hours:02d}:{minutes:02d}:{seconds:02d}".format(
                hours =  timedif.days*24 + timedif.seconds // 3600, 
                minutes = timedif.seconds % 3600 // 60 ,
                seconds = timedif.seconds % 60 
                )
        else: # days
            today = datetime.datetime.now()
            then = today + timedif
            dif = then.date() - today.date()
            formatted = "{days} day{plural}".format(
                days =  dif.days,
                plural = 's' if dif.days >1 else '')

        return formatted
    
   
    def check_schedule(self):
        # previous1 = self. current
        previous2 = self.next
        if self.current_mediapackage == None:
            self.current = None
        else:
            self.current = self.repo.get(self.current_mediapackage)
        previous2 = self.next
        self.next = self.repo.get_next_mediapackage() # could be None
        if previous2 != self.next:
            self.reload_state()



    # ------------------------- POPUP ACTIONS ------------------------

    def on_edit_meta(self,button):
        """Pops up the  Metadata editor of the active Mediapackage"""
        self.dispatcher.emit("disable-no-audio")
        #self.change_state(GC_BLOCKED)
        if not self.scheduled_recording:
            Metadata(self.mediapackage, series.get_series(), parent=self)
            mp = self.mediapackage
            self.statusbar.SetVideo(None,mp.getTitle())
            if self.mediapackage.getCreator() != None:
                self.statusbar.SetPresenter(None,mp.getCreator() if mp.getCreator() != None else '')
            self.dispatcher.emit("enable-no-audio")
        #self.change_state(self.previous)  
        return True 

    def show_next(self,button=None,tipe = None):   
        """Pops up the Event Manager"""
        self.dispatcher.emit("disable-no-audio")
        EventManager()
        self.dispatcher.emit("enable-no-audio")
        return True

    def show_about(self,button=None,tipe = None):
        """Pops up de About Dialgo"""
        about_dialog = GCAboutDialog()
        self.dispatcher.emit("disable-no-audio")
        about_dialog.set_transient_for(context.get_mainwindow())
        about_dialog.set_modal(True)
        about_dialog.set_keep_above(False)
        about_dialog.show()
        about_dialog.connect('response', self.on_about_dialog_response)
    
    def on_about_dialog_response(self, origin, response_id):
        if response_id == gtk.RESPONSE_CLOSE or response_id == gtk.RESPONSE_CANCEL:
            self.dispatcher.emit("enable-no-audio") 
            origin.hide()


    # -------------------------- UI ACTIONS -----------------------------

    def create_drawing_areas(self, source):
        """Create as preview areas as video sources exits"""
        main = self.main_area

        for child in main.get_children():
            main.remove(child)
            child.destroy()        
        areas = None
        areas = dict()
        for key,value in source.iteritems():
            new_area = gtk.DrawingArea()
            new_area.set_name("videoarea"+str(key))
            new_area.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("black"))
            areas[re.sub(r'\W+', '', value)]=new_area
            main.pack_start(new_area,True,True,int(self.proportion*3))

        for child in main.get_children():
            child.show()
         
        return areas

    def event_change_mode(self, orig, old_state, new_state):
        """Handles the focus or the Rercording Area, launching messages when focus is recoverde"""
        if new_state == 0: 
            self.focus_is_active = True
            if self.recorder:
                self.recorder.mute_preview(False)
            if self.error_text:            
                if self.status != GC_ERROR:
                    self.change_state(GC_ERROR)
                self.launch_error_message(self.error_text)            

        if old_state == 0:
            self.focus_is_active = False
            if self.recorder:
                self.recorder.mute_preview(True)

    def change_mode(self, button):
        """Launch the signal to change to another area"""
        self.dispatcher.emit("change-mode", 3) # FIXME use constant

    def set_status_view(self):
        """Set the message and color of the status pilot on the top bar"""

        size = context.get_mainwindow().get_size()
        # k1 = size[0] / 1920.0
        k2 = size[1] / 1080.0

        l = gtk.ListStore(str,str,str)

        main_window = context.get_mainwindow()
        main_window.realize()
        style=main_window.get_style()

        bgcolor = style.bg[gtk.STATE_PRELIGHT]  
        fgcolor = style.fg[gtk.STATE_PRELIGHT]  

        for i in STATUS:
            if i[0] in ["Recording", "Error"]:
                l.append([_(i[0]), i[1], fgcolor])
            else:            
                l.append([_(i[0]), bgcolor, fgcolor])

        v = gtk.CellView()
        v.set_model(l)


        r = gtk.CellRendererText()
        self.renderer=r
        r.set_alignment(0.5,0.5)
        r.set_fixed_size(int(k2*400),-1)


        # k1 = size[0] / 1920.0
        k2 = size[1] / 1080.0
        font = pango.FontDescription("bold "+ str(int(k2*48)))
        r.set_property('font-desc', font)
        v.pack_start(r,True)
        v.add_attribute(r, "text", 0)
        v.add_attribute(r, "background", 1)   
        v.add_attribute(r, "foreground", 2)   
        v.set_displayed_row(0)
        return v

    def check_status_area(self, origin, signal=None, other=None): 
        """Updates the values on the recording tab"""
        s1 = self.gui.get_object("status1")
        s2 = self.gui.get_object("status2")
        # s3 = self.gui.get_object("status3")
        s4 = self.gui.get_object("status4")
 
        freespace,text_space=status_bar.GetFreeSpace(self.repo.get_rectemp_path())
        s1.set_text(text_space)
        four_gb = 4000000000.0
        hours = int(freespace/four_gb)
        s2.set_text(_("{0} hours left").format(str(hours)))
        agent = context.get_state().hostname # TODO just consult it once
        if s4.get_text() != agent:
            s4.set_text(agent)

    def check_net(self, origin, status=None):
        """Update the value of the network status"""
        attr1= pango.AttrList()
        attr2= pango.AttrList()
        attr3= pango.AttrList()
        attr4= pango.AttrList()
        gray= pango.AttrForeground(20000, 20000, 20000, 0, -1)
        red = pango.AttrForeground(65535, 0, 0, 0, -1)
        green = pango.AttrForeground(0, 65535, 0, 0, -1)
        black= pango.AttrForeground(5000, 5000, 5000, 0, -1)
        attr1.insert(gray)
        attr2.insert(green)
        attr3.insert(red)
        attr4.insert(black)

        s3 = self.gui.get_object("status3")
        if not self.net_activity:
            s3.set_text("Disabled")
            s3.set_attributes(attr1)
        else:
            net = status
            try:
                if net:
                    s3.set_text("Up")
                    s3.set_attributes(attr2)
                else:
                    s3.set_text("Down")  
                    s3.set_attributes(attr3)
            except KeyError:
                s3.set_text("Connecting")
                s3.set_attributes(attr4)

    def resize(self):
        """Adapts GUI elements to the screen size"""
        size = context.get_mainwindow().get_size()
        altura = size[1]
        anchura = size[0]
        
        k1 = anchura / 1920.0
        k2 = altura / 1080.0
        self.proportion = k1

        #Recorder
        clock = self.gui.get_object("local_clock")
        logo = self.gui.get_object("classlogo")       
        nextl = self.gui.get_object("nextlabel")
        title = self.gui.get_object("titlelabel")
        # eventl = self.gui.get_object("eventlabel")
        pbox = self.gui.get_object("prebox")

        rec_title = self.gui.get_object("recording1")
        rec_elapsed = self.gui.get_object("recording3")
        status_panel = self.gui.get_object('status_panel')

        l1 = self.gui.get_object("tab1")
        l2 = self.gui.get_object("tab2")
        l3 = self.gui.get_object("tab3")
                    
        relabel(clock,k1*25,False)
        font = pango.FontDescription("bold "+str(int(k2*48)))
        self.renderer.set_property('font-desc', font)
        self.renderer.set_fixed_size(int(k2*400),-1)
        pixbuf = gtk.gdk.pixbuf_new_from_file(get_image_path('logo.svg'))  
        pixbuf = pixbuf.scale_simple(
            int(pixbuf.get_width()*k1),
            int(pixbuf.get_height()*k1),
            gtk.gdk.INTERP_BILINEAR)
        logo.set_from_pixbuf(pixbuf)

        modification = "bold "+str(k1*42)
        self.font = pango.FontDescription(modification)     
        relabel(nextl,k1*25,True)
        relabel(title,k1*33,True)

        # REC AND STATUS PANEL
        relabel(rec_title, k1*25, True)
        rec_title.set_line_wrap(True)
        rec_title.set_width_chars(40)
        relabel(rec_elapsed, k1*28, True)

        for child in status_panel.get_children():
            if type(child) is gtk.Label:
                relabel(child,k1*19,True)
        relabel(l1,k1*20,False)
        relabel(l2,k1*20,False)
        relabel(l3,k1*20,False)

        for name  in ["recbutton","pausebutton","stopbutton","editbutton","swapbutton","helpbutton"]:
            button = self.gui.get_object(name)
            button.set_property("width-request", int(k1*100) )
            button.set_property("height-request", int(k1*100) )

            image = button.get_children()
            if type(image[0]) == gtk.Image:
                image[0].set_pixel_size(int(k1*80))   
            elif type(image[0]) == gtk.VBox:
                for element in image[0].get_children():
                    if type(element) == gtk.Image:
                        element.set_pixel_size(int(k1*46))
            else:
                relabel(image[0],k1*28,False)
        # change stop button
        for name in ["pause","stop"]:
            button = self.gui.get_object(name+"button")
            image = button.get_children()[0]
            pixbuf = gtk.gdk.pixbuf_new_from_file(get_image_path('gc-'+name+'.svg'))
            pixbuf = pixbuf.scale_simple(
                int(80*k1),
                int(80*k1),
                gtk.gdk.INTERP_BILINEAR)
            image.set_from_pixbuf(pixbuf)  

        for name  in ["previousbutton", "morebutton"]:
            button = self.gui.get_object(name)
            button.set_property("width-request", int(k1*70) )
            button.set_property("height-request", int(k1*70) )

            image = button.get_children()
            if type(image[0]) == gtk.Image:
                image[0].set_pixel_size(int(k1*56))  


        talign = self.gui.get_object("top_align")
        talign.set_padding(int(k1*10),int(k1*25),0,0)
        calign = self.gui.get_object("control_align")
        calign.set_padding(int(k1*10),int(k1*30),int(k1*50),int(k1*50))
        vum = self.gui.get_object("vubox")
        vum.set_padding(int(k1*20),int(k1*10),int(k1*40),int(k1*40))         
        pbox.set_property("width-request", int(k1*225) )        
        return True

        
    def change_state(self, state):
        """Activates or deactivates the buttons depending on the new state"""
        record = self.gui.get_object("recbutton")
        pause = self.gui.get_object("pausebutton")
        stop = self.gui.get_object("stopbutton")
        helpb = self.gui.get_object("helpbutton")
        editb = self.gui.get_object("editbutton")
        prevb = self.gui.get_object("previousbutton")
        swapb = self.gui.get_object("swapbutton")
        if not self.swap_active:
            swapb.hide()

        if state != self.status:
            self.previous,self.status = self.status,state

        if state == GC_INIT:
            record.set_sensitive(False)
            pause.set_sensitive(False)
            stop.set_sensitive(False)
            helpb.set_sensitive(True)
            prevb.set_sensitive(True)
            editb.set_sensitive(False)
            swapb.set_sensitive(False)
            self.dispatcher.emit("update-rec-status", "Initialization")            

        elif state == GC_PREVIEW:    
            record.set_sensitive( (self.allow_start or self.allow_manual) )
            pause.set_sensitive(False)
            pause.set_active(False)
            stop.set_sensitive(False)
            helpb.set_sensitive(True)
            prevb.set_sensitive(True)
            editb.set_sensitive(False)
            swapb.set_sensitive(True)
            if self.next == None:
                self.dispatcher.emit("update-rec-status", "Idle")            
            else:
                self.dispatcher.emit("update-rec-status", "Waiting")     

        elif state == GC_RECORDING:
            record.set_sensitive(False)
            pause.set_sensitive(self.allow_pause and self.recorder.is_pausable()) 
            stop.set_sensitive( (self.allow_stop or self.allow_manual) )
            helpb.set_sensitive(True)
            prevb.set_sensitive(False)
            swapb.set_sensitive(False)
            editb.set_sensitive(True and not self.scheduled_recording)    
            self.dispatcher.emit("update-rec-status", "  Recording  ")
       
        elif state == GC_PAUSED:
            record.set_sensitive(False)
            pause.set_sensitive(False) 
            stop.set_sensitive(False)
            prevb.set_sensitive(False)
            helpb.set_sensitive(False)
            editb.set_sensitive(False)
  
            self.dispatcher.emit("update-rec-status", "Paused")
            
        elif state == GC_STOP:
            if self.previous == GC_PAUSED:
                self.pause_dialog.destroy()
            record.set_sensitive(False)
            pause.set_sensitive(False)
            stop.set_sensitive(False)
            helpb.set_sensitive(True)
            prevb.set_sensitive(True)
            editb.set_sensitive(False)

        elif state == GC_BLOCKED: 
            record.set_sensitive(False)
            pause.set_sensitive(False)
            stop.set_sensitive(False)
            helpb.set_sensitive(False)   
            prevb.set_sensitive(False)
            editb.set_sensitive(False)

        elif state == GC_ERROR:             
            record.set_sensitive(False)
            pause.set_sensitive(False)
            stop.set_sensitive(False)
            helpb.set_sensitive(True) 
            prevb.set_sensitive(True )
            editb.set_sensitive(False)


        context.get_state().status = STATUS[state][0]

        if self.next == None and state == GC_PREVIEW:
            self.view.set_displayed_row(GC_PRE2)
        else:
            self.view.set_displayed_row(state)


    def block(self):
        prev = self.gui.get_object("prebox")
        prev.set_child_visible(False)
        self.focus_is_active = True
        self.event_change_mode(None, 3, 0)

        # Show Help or Edit_meta
        helpbutton = self.gui.get_object("helpbutton")
        helpbutton.set_visible(True)
        editbutton = self.gui.get_object("editbutton")
        editbutton.set_visible(False)

        # Start Preview
        self.dispatcher.emit("start-preview")

 
    def close(self, signal):
        """Handles the area closure, stopping threads, mediapackage and preview"""
        if self.status in [GC_RECORDING]:
            self.close_recording() 
        self.scheduler_thread_id = None
        self.clock_thread_id = None
        self.start_thread_id = None
        if self.status in [GC_PREVIEW]:
            self.recorder.stop_preview()        
        return True