Example #1
0
class Recorder:

    def __init__(self):
        logger.debug('Recorder.__init__()')
        # Disable this plugin if not loaded by record_server.
        if string.find(sys.argv[0], 'recordserver') == -1:
            return

        logger.info('ACTIVATING GENERIC RECORD PLUGIN')

        self.fc = FreevoChannels()
        self.thread = Record_Thread()
        self.thread.setDaemon(1)
        self.thread.mode = 'idle'
        self.thread.start()


    def Record(self, rec_prog):
        logger.debug('Record(rec_prog=%r)', rec_prog)
        vg = self.fc.getVideoGroup(rec_prog.tunerid, False)

        frequency = self.fc.chanSet(str(rec_prog.tunerid), False, 'record plugin')

        rec_prog.filename = tv_util.getProgFilename(rec_prog)

        cl_options = { 'channel'  : rec_prog.tunerid,
                       'frequency' : frequency,
                       'frequencyMHz' : float(frequency) / 1000,
                       'filename' : rec_prog.filename,
                       'base_filename' : os.path.basename(rec_prog.filename),
                       'title' : rec_prog.title,
                       'sub-title' : rec_prog.sub_title,
                       'seconds'  : rec_prog.rec_duration,
                       'start'  : rec_prog.start,
                       'pdc-start'  : rec_prog.pdc_start,
                       'group-type' : vg.group_type
        }

        if isinstance(config.VCR_CMD, str) or isinstance(config.VCR_CMD, unicode):
            self.rec_command = config.VCR_CMD % cl_options
        elif isinstance(config.VCR_CMD, list) or isinstance(config.VCR_CMD, tuple):
            self.rec_command = []
            for arg in config.VCR_CMD:
                self.rec_command.append(arg % cl_options)

        self.thread.mode     = 'record'
        self.thread.prog     = rec_prog
        self.thread.command  = self.rec_command
        self.thread.autokill = float(rec_prog.rec_duration + 10)
        self.thread.mode_flag.set()

        logger.debug('Recorder::Record: %s', self.rec_command)


    def Stop(self):
        logger.debug('Stop()')
        self.thread.mode = 'stop'
        self.thread.mode_flag.set()
Example #2
0
class Recorder:

    def __init__(self):
        logger.debug('Recorder.__init__()')
        # Disable this plugin if not loaded by record_server.
        if string.find(sys.argv[0], 'recordserver') == -1:
            return

        logger.info('ACTIVATING GENERIC RECORD PLUGIN')

        self.fc = FreevoChannels()
        self.thread = Record_Thread()
        self.thread.setDaemon(1)
        self.thread.mode = 'idle'
        self.thread.start()


    def Record(self, rec_prog):
        logger.debug('Record(rec_prog=%r)', rec_prog)
        vg = self.fc.getVideoGroup(rec_prog.tunerid, False)

        frequency = self.fc.chanSet(str(rec_prog.tunerid), False, 'record plugin')

        rec_prog.filename = tv_util.getProgFilename(rec_prog)

        cl_options = { 'channel'  : rec_prog.tunerid,
                       'frequency' : frequency,
                       'frequencyMHz' : float(frequency) / 1000,
                       'filename' : rec_prog.filename,
                       'base_filename' : os.path.basename(rec_prog.filename),
                       'title' : rec_prog.title,
                       'sub-title' : rec_prog.sub_title,
                       'seconds'  : rec_prog.rec_duration,
                       'start'  : rec_prog.start,
                       'pdc-start'  : rec_prog.pdc_start,
                       'group-type' : vg.group_type
        }

        if isinstance(config.VCR_CMD, str) or isinstance(config.VCR_CMD, unicode):
            self.rec_command = config.VCR_CMD % cl_options
        elif isinstance(config.VCR_CMD, list) or isinstance(config.VCR_CMD, tuple):
            self.rec_command = []
            for arg in config.VCR_CMD:
                self.rec_command.append(arg % cl_options)

        self.thread.mode     = 'record'
        self.thread.prog     = rec_prog
        self.thread.command  = self.rec_command
        self.thread.autokill = float(rec_prog.rec_duration + 10)
        self.thread.mode_flag.set()

        logger.debug('Recorder::Record: %s', self.rec_command)


    def Stop(self):
        logger.debug('Stop()')
        self.thread.mode = 'stop'
        self.thread.mode_flag.set()
Example #3
0
    def run(self):
        while 1:
            if DEBUG: print('Record_Thread::run: mode=%s' % self.mode)
            if self.mode == 'idle':
                self.mode_flag.wait()
                self.mode_flag.clear()

            elif self.mode == 'record':
                rc.post_event(Event('RECORD_START', arg=self.prog))
                if DEBUG: print 'Record_Thread::run: started recording'

                fc = FreevoChannels()
                if DEBUG: print 'CHAN: %s' % fc.getChannel()

                (v_norm, v_input, v_clist, v_dev) = config.TV_SETTINGS.split()

                v = tv.ivtv.IVTV(v_dev)

                v.init_settings()
                vg = fc.getVideoGroup(self.prog.tunerid, False)

                if DEBUG: print 'Setting Input to %s' % vg.input_num
                v.setinput(vg.input_num)

                if DEBUG: print 'Setting Channel to %s' % self.prog.tunerid
                fc.chanSet(str(self.prog.tunerid), False)

                if DEBUG: v.print_settings()

                now = time.time()
                stop = now + self.prog.rec_duration

                time.sleep(2)

                v_in = open(v_dev, 'r')
                v_out = open(self.prog.filename, 'w')

                while time.time() < stop:
                    buf = v_in.read(CHUNKSIZE)
                    v_out.write(buf)
                    if self.mode == 'stop':
                        break

                v_in.close()
                v_out.close()
                v.close()
                v = None

                self.mode = 'idle'

                rc.post_event(Event('RECORD_STOP', arg=self.prog))
                if DEBUG: print('Record_Thread::run: finished recording')

            else:
                self.mode = 'idle'

            time.sleep(0.5)
Example #4
0
class Recorder:
    def __init__(self):
        logger.debug("Recorder.__init__()")
        # Disable this plugin if not loaded by record_server.
        if string.find(sys.argv[0], "recordserver") == -1:
            return

        logger.info("ACTIVATING GENERIC RECORD PLUGIN")

        self.fc = FreevoChannels()
        self.thread = Record_Thread()
        self.thread.setDaemon(1)
        self.thread.mode = "idle"
        self.thread.start()

    def Record(self, rec_prog):
        logger.debug("Record(rec_prog=%r)", rec_prog)
        vg = self.fc.getVideoGroup(rec_prog.tunerid, False)

        frequency = self.fc.chanSet(str(rec_prog.tunerid), False, "record plugin")

        rec_prog.filename = tv_util.getProgFilename(rec_prog)

        cl_options = {
            "channel": rec_prog.tunerid,
            "frequency": frequency,
            "frequencyMHz": float(frequency) / 1000,
            "filename": rec_prog.filename,
            "base_filename": os.path.basename(rec_prog.filename),
            "title": rec_prog.title,
            "sub-title": rec_prog.sub_title,
            "seconds": rec_prog.rec_duration,
            "start": rec_prog.start,
            "pdc-start": rec_prog.pdc_start,
            "group-type": vg.group_type,
        }

        if isinstance(config.VCR_CMD, str) or isinstance(config.VCR_CMD, unicode):
            self.rec_command = config.VCR_CMD % cl_options
        elif isinstance(config.VCR_CMD, list) or isinstance(config.VCR_CMD, tuple):
            self.rec_command = []
            for arg in config.VCR_CMD:
                self.rec_command.append(arg % cl_options)

        self.thread.mode = "record"
        self.thread.prog = rec_prog
        self.thread.command = self.rec_command
        self.thread.autokill = float(rec_prog.rec_duration + 10)
        self.thread.mode_flag.set()

        logger.debug("Recorder::Record: %s", self.rec_command)

    def Stop(self):
        logger.debug("Stop()")
        self.thread.mode = "stop"
        self.thread.mode_flag.set()
Example #5
0
class Record_Thread(threading.Thread):
    """
    Thread class that actually does the recording.
    """

    def __init__(self, manager):
        """
        Initialise the recording thread passing in the DVBStreamerControl object to use to
        control instances of dvbstreamer.
        """
        threading.Thread.__init__(self)
        self.fc = FreevoChannels()
        self.manager = manager
        self.mode = 'idle'
        self.mode_flag = threading.Event()
        self.prog = None
        self.app = None


    def run(self):
        """
        Thread loop.
        """
        while 1:
            if DEBUG: print('Record_Thread::run: mode=%s' % self.mode)
            if self.mode == 'idle':
                self.mode_flag.wait()
                self.mode_flag.clear()

            elif self.mode == 'record':
                rc.post_event(Event('RECORD_START', arg=self.prog))
                if DEBUG: print('Record_Thread::run: started recording')

                prog = self.prog
                filename = tv_util.getProgFilename(prog)
                vg = self.fc.getVideoGroup(prog.tunerid, False)
                adapter = vg.vdev
                seconds = prog.rec_duration
                # Select the channel and start streaming to the file.
                self.manager.select(adapter, prog.tunerid)
                self.manager.enable_file_output(adapter,filename)

                while (self.mode == 'record') and (seconds > 0):
                    seconds -= 0.5
                    time.sleep(0.5)

                # Close the file
                self.manager.disable_output(adapter)

                rc.post_event(Event('RECORD_STOP', arg=self.prog))
                if DEBUG: print('Record_Thread::run: finished recording')

                self.mode = 'idle'
            else:
                self.mode = 'idle'
            time.sleep(0.5)
Example #6
0
class Record_Thread(threading.Thread):
    """
    Thread class that actually does the recording.
    """
    def __init__(self, manager):
        """
        Initialise the recording thread passing in the DVBStreamerControl object to use to
        control instances of dvbstreamer.
        """
        threading.Thread.__init__(self)
        self.fc = FreevoChannels()
        self.manager = manager
        self.mode = 'idle'
        self.mode_flag = threading.Event()
        self.prog = None
        self.app = None

    def run(self):
        """
        Thread loop.
        """
        while 1:
            if DEBUG: print('Record_Thread::run: mode=%s' % self.mode)
            if self.mode == 'idle':
                self.mode_flag.wait()
                self.mode_flag.clear()

            elif self.mode == 'record':
                rc.post_event(Event('RECORD_START', arg=self.prog))
                if DEBUG: print('Record_Thread::run: started recording')

                prog = self.prog
                filename = tv_util.getProgFilename(prog)
                vg = self.fc.getVideoGroup(prog.channel_id, False)
                adapter = int(vg.vdev)
                seconds = prog.rec_duration
                # Select the channel and start streaming to the file.
                self.manager.select(adapter, prog.tunerid)
                self.manager.enable_file_output(adapter, filename)

                while (self.mode == 'record') and (seconds > 0):
                    seconds -= 0.5
                    time.sleep(0.5)

                # Close the file
                self.manager.disable_output(adapter)

                rc.post_event(Event('RECORD_STOP', arg=self.prog))
                if DEBUG: print('Record_Thread::run: finished recording')

                self.mode = 'idle'
            else:
                self.mode = 'idle'
            time.sleep(0.5)
    def run(self):
        while 1:
            if DEBUG: print('Record_Thread::run: mode=%s' % self.mode)
            if self.mode == 'idle':
                self.mode_flag.wait()
                self.mode_flag.clear()

            elif self.mode == 'record':
                rc.post_event(Event('RECORD_START', arg=self.prog))
                if DEBUG: print('Record_Thread::run: cmd=%s' % self.command)

                fc = FreevoChannels()
                if DEBUG: print 'CHAN: %s' % fc.getChannel()

                (v_norm, v_input, v_clist, v_dev) = config.TV_SETTINGS.split()

                v = tv.ivtv.IVTV(v_dev)

                v.init_settings()
                self.vg = fc.getVideoGroup(self.prog.tunerid, False)

                if DEBUG: print 'Using video device %s' % self.vg.vdev
                if DEBUG: print 'Setting Input to %s' % self.vg.input_num
                v.setinput(self.vg.input_num)

                if DEBUG: print 'Setting Channel to %s' % self.prog.tunerid
                fc.chanSet(str(self.prog.tunerid), False)

                if DEBUG: v.print_settings()

                self.app = RecordApp(self.command)

                while self.mode == 'record' and self.app.isAlive():
                    self.autokill -= 0.5
                    time.sleep(0.5)
                    if self.autokill <= 0:
                        if DEBUG:
                            print 'autokill timeout, stopping recording'
                        self.mode = 'stop'

                if self.app.isAlive():
                    # might not want to do this is PDC is valid, programme may be delayed
                    if DEBUG: print('Record_Thread::run: past wait!!')
                    rc.post_event(
                        Event(OS_EVENT_KILL, (self.app.child.pid, 15)))
                    self.app.kill()

                rc.post_event(Event('RECORD_STOP', arg=self.prog))
                if DEBUG: print('Record_Thread::run: finished recording')

                self.mode = 'idle'
            else:
                self.mode = 'idle'
            time.sleep(0.5)
    def run(self):
        _debug_('Record_Thread.run()', 2)
        while 1:
            _debug_('mode=%s' % self.mode)
            if self.mode == 'idle':
                self.mode_flag.wait()
                self.mode_flag.clear()

            elif self.mode == 'record':
                rc.post_event(Event('RECORD_START', arg=self.prog))

                fc = FreevoChannels()
                _debug_('channel %s' % fc.getChannel())

                self.vg = fc.getVideoGroup(self.prog.tunerid, False)

                v = tv.ivtv.IVTV(self.vg.vdev)

                v.init_settings()

                _debug_('Using video device=%r' % self.vg.vdev)

                _debug_('Setting Channel to %r' % self.prog.tunerid)
                fc.chanSet(str(self.prog.tunerid), False)

                _debug_('command %r' % self.command)
                self.app = RecordApp(self.command)
                _debug_('app child pid: %s' % self.app.child.pid)

                while self.mode == 'record' and self.app.isAlive():
                    self.autokill -= 0.5
                    time.sleep(0.5)
                    if self.autokill <= 0:
                        _debug_('autokill timeout, stopping recording')
                        self.mode = 'stop'

                if self.app.isAlive():
                    # might not want to do this is PDC is valid, programme may be delayed
                    _debug_('past wait!!')
                    rc.post_event(
                        Event(OS_EVENT_KILL, (self.app.child.pid, 15)))
                    self.app.kill()

                rc.post_event(Event('RECORD_STOP', arg=self.prog))
                _debug_('finished recording')

                self.mode = 'idle'
            else:
                self.mode = 'idle'
            time.sleep(0.5)
Example #9
0
    def run(self):
        logger.log( 9, 'Record_Thread.run()')
        while 1:
            logger.debug('mode=%s', self.mode)
            if self.mode == 'idle':
                self.mode_flag.wait()
                self.mode_flag.clear()

            elif self.mode == 'record':
                rc.post_event(Event('RECORD_START', arg=self.prog))

                fc = FreevoChannels()
                logger.debug('channel %s', fc.getChannel())

                self.vg = fc.getVideoGroup(self.prog.tunerid, False)

                v = tv.ivtv.IVTV(self.vg.vdev)

                v.init_settings()

                logger.debug('Using video device=%r', self.vg.vdev)

                logger.debug('Setting Channel to %r', self.prog.tunerid)
                fc.chanSet(str(self.prog.tunerid), False)

                logger.debug('command %r', self.command)
                self.app = RecordApp(self.command)
                logger.debug('command pid: %s', self.app.child.pid)

                while self.mode == 'record' and self.app.isAlive():
                    self.autokill -= 0.5
                    time.sleep(0.5)
                    if self.autokill <= 0:
                        logger.debug('autokill timeout, stopping recording')
                        self.mode = 'stop'

                if self.app.isAlive():
                    # might not want to do this is PDC is valid, programme may be delayed
                    logger.debug('past wait!!')
                    self.app.kill()

                rc.post_event(Event('RECORD_STOP', arg=self.prog))
                logger.debug('finished recording')

                self.mode = 'idle'
            else:
                self.mode = 'idle'
            time.sleep(0.5)
Example #10
0
 def play(self, arg=None, menuw=None):
     """ Start watching TV """
     logger.log(9, 'play(arg=%r, menuw=%r)', arg, menuw)
     # watching TV should only be possible from the guide
     if not self.context == 'guide':
         rc.post_event(MENU_SELECT)
         return
     now = time.time()
     if menuw: menuw.delete_submenu()
     # Check if the selected program is >7 min in the future
     if self.prog.start > now + (7 * 60):
         if menuw: menuw.show()
         # this program is in the future
         if self.scheduled:
             msgtext = _(
                 'Do you want to remove the Program from the record schedule?'
             )
             confirmbtn = _('Remove')
         else:
             msgtext = _(
                 'This Program is in the future. Do you want to record it?')
             confirmbtn = _('Record')
         dialog.show_confirmation(msgtext,
                                  lambda: self.toggle_rec(menuw=menuw),
                                  proceed_text=confirmbtn)
         return
     else:
         # check if the device is free
         fc = FreevoChannels()
         # for that we need the name of the lock file
         suffix = fc.getVideoGroup(self.prog.channel_id, True,
                                   CHANNEL_ID).vdev
         suffix = suffix.split('/')[-1]
         tvlockfile = config.FREEVO_CACHEDIR + '/record.' + suffix
         if os.path.exists(tvlockfile):
             if menuw: menuw.show()
             # XXX: In the future add the options to watch what we are
             #      recording or cancel it and watch TV.
             msgtext = _('Sorry, you cannot watch TV while recording. ')
             msgtext += _('If this is not true then remove ')
             msgtext += tvlockfile + '.'
             dialog.show_alert(msgtext)
         else:
             # everything is ok, we can start watching!
             self.parent.hide()
             self.parent.player('tv', self.prog.channel_id)
Example #11
0
 def writeTvtimeXML(self):
     tvtimexml = os.path.join(os.environ['HOME'], '.tvtime', 'tvtime.xml')
     configcmd = os.path.join(os.path.dirname(config.TVTIME_CMD), "tvtime-configure")
     #cf_norm, cf_input, cf_clist, cf_device = config.TV_SETTINGS.split()
     fc = FreevoChannels()
     vg = fc.getVideoGroup(config.TV_CHANNELS[0][2], True)
     cf_norm = vg.tuner_norm
     cf_input = vg.input_num
     cf_device = vg.vdev
     s_norm = cf_norm.upper()
     daoptions = ''
     if os.path.isfile(tvtimexml):
         daoptions = ' -F ' + tvtimexml
     if self.xmltv_supported:
         daoptions += ' -d %s -n %s -t %s' % (cf_device, s_norm, config.XMLTV_FILE)
     else:
         daoptions += ' -d %s -n %s' % (cf_device, s_norm)
     if hasattr(config, "TV_TVTIME_SETUP_OPTS") and config.TV_TVTIME_SETUP_OPTS:
         daoptions += ' %s' % config.TV_TVTIME_SETUP_OPTS
     os.system(configcmd+daoptions)
Example #12
0
 def writeTvtimeXML(self):
     tvtimexml = os.path.join(os.environ['HOME'], '.tvtime', 'tvtime.xml')
     configcmd = os.path.join(os.path.dirname(config.TVTIME_CMD), "tvtime-configure")
     #cf_norm, cf_input, cf_clist, cf_device = config.TV_SETTINGS.split()
     fc = FreevoChannels()
     vg = fc.getVideoGroup(config.TV_CHANNELS[0][2], True)
     cf_norm = vg.tuner_norm
     cf_input = vg.input_num
     cf_device = vg.vdev
     s_norm = cf_norm.upper()
     daoptions = ''
     if os.path.isfile(tvtimexml):
         daoptions = ' -F ' + tvtimexml
     if self.xmltv_supported:
         daoptions += ' -d %s -n %s -t %s' % (cf_device, s_norm, config.XMLTV_FILE)
     else:
         daoptions += ' -d %s -n %s' % (cf_device, s_norm)
     if hasattr(config, "TV_TVTIME_SETUP_OPTS") and config.TV_TVTIME_SETUP_OPTS:
         daoptions += ' %s' % config.TV_TVTIME_SETUP_OPTS
     os.system(configcmd+daoptions)
Example #13
0
 def play(self, arg=None, menuw=None):
     """ Start watching TV """
     logger.log( 9, 'play(arg=%r, menuw=%r)', arg, menuw)
     # watching TV should only be possible from the guide
     if not self.context == 'guide':
         rc.post_event(MENU_SELECT)
         return
     now = time.time()
     if menuw: menuw.delete_submenu()
     # Check if the selected program is >7 min in the future
     if self.prog.start > now + (7*60):
         if menuw: menuw.show()
         # this program is in the future
         if self.scheduled:
             msgtext= _('Do you want to remove the Program from the record schedule?')
             confirmbtn = _('Remove')
         else:
             msgtext = _('This Program is in the future. Do you want to record it?')
             confirmbtn = _('Record')
         dialog.show_confirmation(msgtext, lambda: self.toggle_rec(menuw=menuw), proceed_text=confirmbtn)
         return
     else:
         # check if the device is free
         fc = FreevoChannels()
         # for that we need the name of the lock file
         suffix = fc.getVideoGroup(self.prog.channel_id, True, CHANNEL_ID).vdev
         suffix = suffix.split('/')[-1]
         tvlockfile = config.FREEVO_CACHEDIR + '/record.'+suffix
         if os.path.exists(tvlockfile):
             if menuw: menuw.show()
             # XXX: In the future add the options to watch what we are
             #      recording or cancel it and watch TV.
             msgtext = _('Sorry, you cannot watch TV while recording. ')
             msgtext += _('If this is not true then remove ')
             msgtext += tvlockfile + '.'
             dialog.show_alert(msgtext)
         else:
             # everything is ok, we can start watching!
             self.parent.hide()
             self.parent.player('tv', self.prog.channel_id)
Example #14
0
        kaa.main.run()

    elif function == 'findnextprogram':

        def handler(result):
            print 'findnextprogram=%r' % (result, )
            print result.__dict__
            raise SystemExit

        server.findNextProgram(handler)
        kaa.main.run()

    elif function == 'isplayerrunning':

        def handler(result):
            print 'isplayerrunning=%r' % (result, )
            raise SystemExit

        server.isPlayerRunning(handler)
        kaa.main.run()

    else:
        fc = FreevoChannels()
        vg = fc.getVideoGroup('K10', False)
        print 'vg=%s' % vg
        print 'dir(%s)' % dir(vg)
        for it in dir(vg):
            print '   %s:%s' % (it, eval('vg.' + it))
        vdev = vg.vdev
        print 'vdev=%s' % vdev
Example #15
0
class PluginInterface(plugin.DaemonPlugin):
    """
    plugin to monitor if a recording is about to start and shut down the
    player if the video device is in use

    To activate this plugin, just put the following line at the end of your
    local_conf.py file:

    | plugin.activate('tv.upsoon')
    """
    __author__ = 'Duncan Webb'
    __author_email__ = '*****@*****.**'
    __maintainer__ = __author__
    __maintainer_email__ = __author_email__
    __version__ = '$Revision: 10559 $'

    def __init__(self, standalone=False):
        """
        init the upsoon plugin
        """
        _debug_('upsoon.PluginInterface.__init__()', 2)
        plugin.DaemonPlugin.__init__(self)
        plugin.register(self, 'upsoon')
        self.standalone = standalone
        self.lock = thread.allocate_lock()
        self.running = True
        self.timer = Timer(self.timer_handler).start(15)
        self.event = EventHandler(self.event_handler)
        #self.event.register(('VIDEO_START', 'VIDEO_END'))
        self.event.register()

        self.recordclient = RecordClient()

        self.fc = FreevoChannels()
        self.rdev = config.RADIO_DEVICE

        self.next_program = None
        self.seconds_before_announce = 120
        self.seconds_before_start = 60
        self.pending_lockfile = config.FREEVO_CACHEDIR + '/record.soon'
        self.tv_lockfile = None  # lockfile of recordserver
        self.stopped = None  # flag that tells upsoon what stopped

    def findNextProgramHandler(self, result):
        """ Handles the result from the findNextProgram call """
        _debug_('findNextProgramHandler(result=%r)' % (result, ), 2)
        (status, self.next_program) = result

        if not status:
            return

        now = time.time()
        _debug_(
            'now=%s next=%s ' %
            (time.strftime('%T', time.localtime(now)), self.next_program), 2)

        self.vdev = self.getVideoForChannel(self.next_program.channel_id)

        self.tv_lockfile = os.path.join(config.FREEVO_CACHEDIR,
                                        'record.' + self.vdev.split('/')[-1])

        self.seconds_to_next = self.next_program.start - config.TV_RECORD_PADDING_PRE - int(
            now + 0.5)
        _debug_('next recording in %s secs' % (self.seconds_to_next), 2)

        # announce 120 seconds before recording is due to start
        # stop the player 60 seconds before recording is due to start

        if (self.seconds_to_next > self.seconds_before_announce):
            return
        if (self.seconds_to_next <= self.seconds_before_start):
            if not os.path.exists(self.pending_lockfile):
                open(self.pending_lockfile, 'w').close()
                _debug_('%r lockfile created' % (self.pending_lockfile))

        _debug_('stopping video or radio player')
        self.stopVideoInUse(self.vdev)
        self.stopRadioInUse(self.rdev)
        return

    def getVideoForChannel(self, channel_id):
        """ get the video device given a channel id """
        _debug_('getVideoForChannel(channel_id=%r)' % (channel_id), 2)
        return self.fc.getVideoGroup(channel_id, False).vdev

    def stopVideoInUse(self, vdev):
        """ stop the video device if being used """
        _debug_('stopVideoInUse(vdev=%r)' % (vdev), 2)
        if vdev:
            try:
                dev_fh = os.open(vdev, os.O_TRUNC)
                try:
                    os.read(dev_fh, 1)
                except:
                    if (self.seconds_to_next > self.seconds_before_start):
                        # just announce
                        rc.post_event(
                            Event(
                                OSD_MESSAGE,
                                arg=_('A recording will start in a few minutes'
                                      )))
                    else:
                        # stop the tv
                        rc.post_event(STOP)
                        self.stopped = _('TV')
                os.close(dev_fh)
            except Exception, e:
                print '%r: %s' % (vdev, e)
                _debug_('cannot check video device \"%s\"' % (vdev), DINFO)
Example #16
0
class Xawtv:

    __muted    = 0
    __igainvol = 0

    def __init__(self, app, remote):
        self.tuner_chidx = 0    # Current channel, index into config.TV_CHANNELS
        self.event_context = 'tv'
        self.fc = FreevoChannels()
        self.current_vg = None
        self.xawtv_prog = app
        self.remote_prog = remote

    def TunerSetChannel(self, tuner_channel):
        for pos in range(len(config.TV_CHANNELS)):
            channel = config.TV_CHANNELS[pos]
            if channel[2] == tuner_channel:
                self.tuner_chidx = pos
                return
        print 'ERROR: Cannot find tuner channel "%s" in the TV channel listing' % tuner_channel
        self.tuner_chidx = 0


    def TunerGetChannelInfo(self):
        '''Get program info for the current channel'''

        tuner_id = config.TV_CHANNELS[self.tuner_chidx][2]
        chan_name = config.TV_CHANNELS[self.tuner_chidx][1]
        chan_id = config.TV_CHANNELS[self.tuner_chidx][0]

        channels = epg.get_guide().get_programs(time.time(), time.time(), chan_id)

        if channels and channels[0] and channels[0].programs:
            start_s = time.strftime(config.TV_TIME_FORMAT, time.localtime(channels[0].programs[0].start))
            stop_s = time.strftime(config.TV_TIME_FORMAT, time.localtime(channels[0].programs[0].stop))
            ts = '(%s-%s)' % (start_s, stop_s)
            prog_info = '%s %s' % (ts, channels[0].programs[0].title)
        else:
            prog_info = 'No info'

        return tuner_id, chan_name, prog_info


    def TunerGetChannel(self):
        return config.TV_CHANNELS[self.tuner_chidx][2]


    def TunerNextChannel(self):
        self.tuner_chidx = (self.tuner_chidx+1) % len(config.TV_CHANNELS)


    def TunerPrevChannel(self):
        self.tuner_chidx = (self.tuner_chidx-1) % len(config.TV_CHANNELS)


    def Play(self, mode, tuner_channel=None, channel_change=0):

        if tuner_channel != None:
            try:
                self.TunerSetChannel(tuner_channel)
            except ValueError:
                pass
        if not tuner_channel:
            tuner_channel = self.fc.getChannel()
        vg = self.current_vg = self.fc.getVideoGroup(tuner_channel, True)

        if not vg.group_type == 'normal':
            print 'Xawtv only supports normal. "%s" is not implemented' % vg.group_type
            return

        if mode == 'tv' or mode == 'vcr':

            w, h = config.TV_VIEW_SIZE
            cf_norm = vg.tuner_norm
            cf_input = vg.input_num
            cf_device = vg.vdev

            s_norm = cf_norm.upper()

            if mode == 'vcr':
                cf_input = '1'
                if hasattr(config, "TV_VCR_INPUT_NUM") and config.TV_VCR_INPUT_NUM:
                    cf_input = config.TV_VCR_INPUT_NUM

            if hasattr(config, "TV_XAWTV_OPTS") and config.TV_XAWTV_OPTS:
                daoptions = config.TV_XAWTV_OPTS
            else:
                daoptions = '-xv -f'

            command = '%s %s -device %s ' % (self.xawtv_prog,
                                             daoptions,
                                             cf_device)

        else:
            print 'Mode "%s" is not implemented' % mode  # BUG ui.message()
            return

        self.mode = mode

        mixer = plugin.getbyname('MIXER')

        # BUG Mixer manipulation code.
        # TV is on line in
        # VCR is mic in
        # btaudio (different dsp device) will be added later
        if mixer and config.MIXER_MAJOR_CTRL == 'VOL':
            mixer_vol = mixer.getMainVolume()
            mixer.setMainVolume(0)
        elif mixer and config.MIXER_MAJOR_CTRL == 'PCM':
            mixer_vol = mixer.getPcmVolume()
            mixer.setPcmVolume(0)

        # Start up the TV task
        self.app=XawtvApp(command, self.remote_prog)

        if tuner_channel:
            time.sleep(0.5)
            self.app.sendcmd('setstation %s' % tuner_channel)
        #XXX use remote to change the input we want

        rc.add_app(self)

        # Suppress annoying audio clicks
        time.sleep(0.4)
        # BUG Hm.. This is hardcoded and very unflexible.
        if mixer and mode == 'vcr':
            mixer.setMicVolume(config.MIXER_VOLUME_VCR_IN)
        elif mixer:
            mixer.setLineinVolume(config.MIXER_VOLUME_TV_IN)
            mixer.setIgainVolume(config.MIXER_VOLUME_TV_IN)

        if mixer and config.MIXER_MAJOR_CTRL == 'VOL':
            mixer.setMainVolume(mixer_vol)
        elif mixer and config.MIXER_MAJOR_CTRL == 'PCM':
            mixer.setPcmVolume(mixer_vol)

        logger.debug('%s: started %s app', time.time(), self.mode)


    def Stop(self, channel_change=0):
        mixer = plugin.getbyname('MIXER')
        if mixer and not channel_change:
            mixer.setLineinVolume(0)
            mixer.setMicVolume(0)
            mixer.setIgainVolume(0) # Input on emu10k cards.

        self.app.stop()
        rc.remove_app(self)

    def eventhandler(self, event, menuw=None):
        logger.debug('%s: %s app got %s event', time.time(), self.mode, event)
        if event == em.STOP or event == em.PLAY_END:
            self.app.sendcmd('quit')
            time.sleep(1)
            self.Stop()
            rc.post_event(em.PLAY_END)
            return True

        elif event == em.TV_CHANNEL_UP or event == em.TV_CHANNEL_DOWN:
            if self.mode == 'vcr':
                return

            if event == em.TV_CHANNEL_UP:
                self.TunerPrevChannel()
                self.app.sendcmd('setstation next')
            else:
                self.TunerNextChannel()
                self.app.sendcmd('setstation prev')

            return True

        elif event == em.TOGGLE_OSD:
            #try to send channel name
            self.app.sendcmd('msg \'%s\'' % self.TunerGetChannel())
            return True

        elif event == em.OSD_MESSAGE:
            self.app.sendcmd('msg \'%s\'' % event.arg)
            return True

        elif event in em.INPUT_ALL_NUMBERS:
            self.app.sendcmd('keypad %s' % event.arg)

        elif event == em.BUTTON:
            if event.arg == 'PREV_CH':
                self.app.sendcmd('setstation back')
                return True


        return False
Example #17
0
class Vlc:
    """
    the main class to control vlc
    """
    def __init__(self, manager, path, size):
        self.name      = 'vlc'
        self.app_mode  = 'tv'
        self.app       = None
        self.adapter_in_use = -1
        self.fc = FreevoChannels()
        self.path = path
        self.size = size
        self.buffer = ring_buffer.RingBuffer(size, path)
        self.last_channel = None
        self.subtitles = False
        self.paused = False
        self.stop_time = 0
        self.state = STATE_IDLE
        self.manager = manager
        self.udp_receiver = UDPReceiver(self.buffer, WAIT_FOR_DATA_TIMEOUT)
        self.slave_server = SlaveServer(self.buffer, self)
        self.fill = 0
        self.cur_audio      = None
        self.cur_sub        = None
        self.cur_audiodev   = None
        self.lastchan       = None

        self.timer = kaa.Timer(self.__update_data_from_vlc)
        self.timer_start = kaa.OneShotTimer( self.__update_data_from_vlc)
        self.timer_disablebuffering = kaa.OneShotTimer( self.disable_buffering)

        if hasattr(config, 'LIVE_PAUSE_BUFFER_TIMEOUT'):
            self. buffering_timeout=config.LIVE_PAUSE_BUFFER_TIMEOUT
        else: # Disable after 5min if not LIVE_PAUSE_BUFFERING_TIMEOUT
            self.buffering_timeout= 5 * 60

        # Create the command used to start vlc.
        # NOTE: We add the slave server MRL twice so that we can toggle between
        # them, this allows use to effectively reset vlc rendering pipeline and
        # make it possible to seek quickly.
        self.command = [ '--prio=%s' % config.MPLAYER_NICE ] + \
                       config.VLC_COMMAND.split(' ')  + \
                       [ '--intf', 'rc' ] + \
                       ['--no-interact','--rc-fake-tty'] + \
                       [ '--sub-filter' ,'marq' ] + \
                       [ '--marq-marquee' ,'Playing' ] + \
                       [ '--marq-position','4'] + \
                       [ '--fullscreen', self.slave_server.get_vlc_mrl(),
                                         self.slave_server.get_vlc_mrl()]

        if not rc.PYLIRC and '--no-lirc' in self.command:
            self.command.remove('--no-lirc')

        self.udp_receiver.start()
        self.slave_server.start()


    def Play(self, mode, tuner_channel=None):
        """
        play with vlc
        """
        if not tuner_channel:
            tuner_channel = self.fc.getChannel()

        rc.app(self)

        same_channel = self.last_channel == tuner_channel

        # If it's the same channel as last time and we have come back to it after
        # more than 2 minutes start at the end of the buffer, otherwise jump
        # straight back in where we left off.
        if same_channel:
            if (time.time() - self.stop_time) > 120.0:
                start_at_end = True
            else:
                start_at_end = False
        else:
            self.fc.chanSet(tuner_channel, True, app=self.app)
            self.change_channel(tuner_channel)
            start_at_end = True

        if start_at_end:
            self.start_slave_server_at_end = True
            if same_channel:

                self.__change_state(STATE_PLAYING)
        else:
            self.__change_state(STATE_PLAYING)

        return None


    def stop(self, channel_change=False):
        """
        Stop vlc
        """
        if self.app:
            self.app.stop('quit\n')
            self.app = None

            if not channel_change:
                self.stop_time = time.time()
                _debug_('Shutting Down Buffering in %d secs' % self.buffering_timeout )
                self.timer_disablebuffering.start(self.buffering_timeout)
                self.__change_state(STATE_IDLE)

    def disable_buffering(self):
        """
        Stop buffering the current channel.
        """
        if self.adapter_in_use != -1:
            self.time = 0
            self.last_channel = None
            try:
                self.manager.disable_output(self.adapter_in_use)
            except:
                _debug_('Failed to disable output! ' + traceback.format_exc())
            self.adapter_in_use = -1

    def pause(self):
        """
        Pause Playback.
        """
        if self.app and not self.paused:
            _debug_('Pausing')
            self.app.write('pause\n')
            self.__osd_write('PAUSED')
            self.paused = True


    def resume(self):
        """
        Resume Playback.
        """
        if self.app and self.paused:
            _debug_('Resuming')
            self.app.write('pause\n')
            self.paused = False


    def shutdown(self):
        """
        Stop the UDP receiver and slave server.
        """
        if self.udp_receiver:
            self.udp_receiver.stop()
            self.udp_receiver = None

        if self.slave_server:
            self.slave_server.stop()
            self.slave_server = None

    def change_channel(self, channel):
        """
        Select the correct dvbstreamer instance, change the channel
        and set the primary mrl.
        """

        if self.last_channel == channel:
            # Already tune to this channel so nothing to do!
            return

        adapter = eval(self.fc.getVideoGroup(channel, True).vdev)

        if (self.adapter_in_use != -1) and (self.adapter_in_use != adapter):
            try:
                self.manager.disable_output(self.adapter_in_use)
            except:
                _debug_('Failed to disable output! ' + traceback.format_exc())

        # We are tuning to a different channel so stop receiving packets and
        # reset the ring buffer
        self.udp_receiver.pause = True
        self.buffer.rwlock.acquire_write()
        self.buffer.reset()

        self.manager.select(adapter, channel)

        if self.adapter_in_use != adapter:
            self.adapter_in_use = adapter
            try:
                self.manager.enable_udp_output(self.adapter_in_use)
            except:
                _debug_('Failed to enable output! ' + traceback.format_exc())

        # Start receiving packets and remember the channel we've just tuned to.
        self.udp_receiver.reset()
        self.udp_receiver.send_events = True
        self.udp_receiver.pause = False
        self.buffer.rwlock.release()
        self.last_channel = channel

        self.__change_state(STATE_TUNING)


    def eventhandler(self, event, menuw=None):
        """
        Eventhandler for vlc control. If an event is not bound in this
        function it will be passed over to the items eventhandler
        """
        event_consumed = False

        if self.state == STATE_IDLE:
            event_consumed = self.__eventhandler_idle(event, menuw)
        elif self.state == STATE_TUNING:
            event_consumed = self.__eventhandler_tuning(event, menuw)
        elif self.state == STATE_BUFFERING:
            event_consumed = self.__eventhandler_buffering(event, menuw)
        elif self.state == STATE_PLAYING:
            event_consumed = self.__eventhandler_playing(event, menuw)

        if not event_consumed:
            _debug_('Unused event %s in state %s' % (event.name, self.state))

        return event_consumed


    def __eventhandler_idle(self, event, menuw):
        """
        Internal event handler when in Idle state.
        """
        return False


    def __eventhandler_tuning(self, event, menuw):
        """
        Internal event handler when in Tuning state.
        """
        if event == EVENT_DATA_STARTED:
            self.__change_state(STATE_BUFFERING)
            return True

        if event == EVENT_DATA_TIMEDOUT:
            # Timeout while waiting for data!
            # We could display a searching for signal graphic or something here
            self.__change_state(STATE_IDLE)
            return True

        return False

    def __eventhandler_buffering(self, event, menuw):
        """
        Internal event handler when in Buffering state.
        """
        if event == EVENT_DATA_ACQUIRED:
            self.wait_for_data_count -= 1
            self.__draw_state_screen()
            if self.wait_for_data_count <= 0:
                self.__change_state(STATE_PLAYING)
            return True

        if event == EVENT_DATA_TIMEDOUT:
            # Timeout while waiting for data!
            # We could display a searching for signal graphic or something here
            self.__change_state(STATE_IDLE)
            return True

        return False


    def __eventhandler_playing(self, event, menuw):
        """
        Internal event handler when in Playing state.
        """
        if event == PAUSE or event == PLAY:
            if self.paused:
                self.resume()
            else:
                self.pause()
            return True

        if event in ( PLAY_END, USER_END, STOP ):
            self.timer.stop()
            self.stop()
            return True

        if event in [ TV_CHANNEL_UP, TV_CHANNEL_DOWN, TV_CHANNEL_LAST ] or (str(event).startswith('INPUT_') and str(event)[6:].isdigit()):
            _debug_('Event: %s' % str(event))
            if event == TV_CHANNEL_UP:
                self.lastchan = self.fc.getChannel()
                nextchan = self.fc.getNextChannel()
            elif event == TV_CHANNEL_DOWN:
                self.lastchan = self.fc.getChannel()
                nextchan = self.fc.getPrevChannel()
            elif event == TV_CHANNEL_LAST:
                if not self.lastchan:
                    return True
                nextchan = self.lastchan
                self.lastchan = self.fc.getChannel()
            else:
                self.lastchan = self.fc.getChannel()
                nextchan = self.fc.getManChannel(int(event.arg))

            self.fc.chanSet(nextchan, True, app=self.app)

            self.stop(True)

            self.change_channel(nextchan) # Moves to the Tuning state
            return True

        if event == OSD_MESSAGE:
            self.__osd_write( event.arg)
            return True

        if event == TOGGLE_OSD:
            # Write percent through ringbuffer to OSD
            channel = self.__get_display_channel()
            percent = self.slave_server.get_percent()
            now = time.strftime(config.TV_TIME_FORMAT)
            self.__osd_write('%s - %d%% - %s' % (channel, percent, now) )
            return True

        if event == SEEK:
            steps = int(event.arg)
            self.buffer.rwlock.acquire_write()
            bytes_per_sec =  self.udp_receiver.average_pps * 188
            if steps > 0:
                can_seek = self.slave_server.reader.available_forward() >= ((steps + 1) * bytes_per_sec)
            else:
                can_seek = self.slave_server.reader.available_backward() > 0

            if can_seek:
                self.slave_server.reader.seek(steps * bytes_per_sec)
                if self.mrl_index == 0:
                    self.mrl_index = 1
                    self.app.write('next\n')
                else:
                    self.mrl_index = 0
                    self.app.write('prev\n')

            self.buffer.rwlock.release()
            return True

        if event == TV_GOTO_LIVE_PLAY:
            self.buffer.rwlock.acquire_write()
            self.slave_server.reader.seek(self.slave_server.reader.available_forward())
            if self.mrl_index == 0:
                self.mrl_index = 1
                self.app.write('next\n')
            else:
                self.mrl_index = 0
                self.app.write('prev\n')
            self.buffer.rwlock.release()
            return True

        if event == EVENT_READER_OVERTAKEN:
            if self.paused:
                self.resume()
            return True

        if event == VIDEO_NEXT_FILLMODE:
            self.__set_next_fill()
            return True

        if event == VIDEO_NEXT_AUDIOLANG:
            self.__set_next_audio_track()
            return True

        if event == VIDEO_NEXT_SUBTITLE:
            self.__set_next_sub_track()
            return True

        if event == VIDEO_NEXT_AUDIOMODE:
            self.__set_next_audio_mode()
            return True

        # Consume UDP Receiver events.
        if event in (EVENT_DATA_ACQUIRED, EVENT_DATA_TIMEDOUT):
            return True

        return False


    def __change_state(self, new_state):
        """
        Internal function to move to a new state.
        If new_state is different to the current state, set self.state to
        new_state and perform any state initialisation for the new state.
        """
        if self.state == new_state:
            # No change in state nothing todo!
            return

        _debug_('Changing state from %s to %s' % (self.state, new_state))
        self.state = new_state

        # State Initialisation code

        if self.state == STATE_IDLE:
            rc.app(None)
            rc.post_event(PLAY_END)
            self.udp_receiver.send_events = False

        elif self.state == STATE_TUNING:
            self.start_slave_server_at_end = True

        elif self.state == STATE_BUFFERING:
            self.wait_for_data_count = WAIT_FOR_DATA_COUNT

        elif self.state == STATE_PLAYING:
            self.slave_server.reader_at_end = self.start_slave_server_at_end
            self.slave_server.end_offset = self.udp_receiver.average_pps * WAIT_FOR_DATA_COUNT * 188
            self.mrl_index = 0
            self.app = VlcApp(self.command, self)

            self.timer.start(60)      # Call every 60 seconds and
            self.timer_start.start(3) # at startup
            _debug_('self.timer_disablebuffering.get_interval %s' % self.timer_disablebuffering.get_interval())
            if self.timer_disablebuffering.get_interval() != None:
                self.timer_disablebuffering.stop()
            self.start_slave_server_at_end = False

        self.__draw_state_screen()


    def __osd_write(self, text):
        if self.app:
            self.app.write('marq-marquee %s\n' % text)

    def __draw_state_screen(self):
        osd_obj = osd.get_singleton()
        percent = 0.0

        channel = self.__get_display_channel()

        if self.state == STATE_IDLE:
            state_string = None

        elif self.state == STATE_TUNING:
            state_string = _('Tuning to %s' % self.__get_display_channel())

        elif self.state == STATE_BUFFERING:
            state_string = _('Buffering %s' % self.__get_display_channel())
            percent = float(WAIT_FOR_DATA_COUNT - self.wait_for_data_count) / float(WAIT_FOR_DATA_COUNT)

        elif self.state == STATE_PLAYING:
            state_string = _('Playing %s' % self.__get_display_channel())
            percent = 1.0

        osd_obj.clearscreen(color=osd_obj.COL_BLACK)
        if state_string:
            y = (config.CONF.height / 2) - config.OSD_DEFAULT_FONTSIZE
            h = -1
            font = osd_obj.getfont(config.OSD_DEFAULT_FONTNAME, config.OSD_DEFAULT_FONTSIZE)
            osd_obj.drawstringframed(state_string, 0, y, config.CONF.width, h, font,
                fgcolor=osd_obj.COL_ORANGE, align_h='center')
            x = config.CONF.width / 4
            w = x * 2
            y = (config.CONF.height / 2) + config.OSD_DEFAULT_FONTSIZE
            h = int(20.0 * ( float(config.CONF.height) /  600.0 ))
            osd_obj.drawbox(x - 2,y - 2,x + w + 2, y + h + 2 , color=osd_obj.COL_ORANGE)
            w = int(float(w) * percent)
            osd_obj.drawbox(x,y,x + w, y +h , color=osd_obj.COL_ORANGE, fill=1)

        osd_obj.update()

    def __update_data_from_vlc(self):
        if self.app != None:
            self.app.write('atrack\n')
            self.app.write('adev\n')
            self.app.write('strack\n')

    def __set_next_audio_track(self):
        list = self.app.audio_tracks
        if len(list) > 0:
            if self.cur_audio == None:
                if len(list) > 1:
                    self.cur_audio = 1
                else:
                    self.cur_audio = 0

            self.cur_audio = self.__get_next_list(self.cur_audio,list)
            self.app.write('atrack %s\n' % list[self.cur_audio])
            if list[self.cur_audio] == '-1':
                self.__osd_write('Audio Track Disabled')
            else:
                self.__osd_write('Audio Track %d' % (self.cur_audio ) )
        else:
            self.__osd_write('audio track none')
        return True

    def __set_next_audio_mode(self):
        list = self.app.audio_chans
        if len(list) > 0:
            if self.cur_audiodev == None:
                if len(list) > 1: # STEREO
                    self.cur_audiodev = 2
                else:   # MONO
                    self.cur_audiodev = 1

            self.cur_audiodev = self.__get_next_list(self.cur_audiodev,list)
            self.app.write('adev %s\n' % list[self.cur_audiodev ])

            if list[self.cur_audiodev ] == '1':
                self.__osd_write('Audio Out: Mono' )
            if list[self.cur_audiodev ] == '2':
                self.__osd_write('Audio Out: Stereo' )
            if list[self.cur_audiodev ] == '4':
                self.__osd_write('Audio Out: 2 Front 2 Rear' )
            if list[self.cur_audiodev ] == '6':
                self.__osd_write('Audio Out: 5.1 channel' )
            if list[self.cur_audiodev ]  == '10':
                self.__osd_write('Audio Out: A/52 over S/PDIF' )
        else:
            self.__osd_write('Audio Out: unknown')
        return True

    def __get_next_list(self,current,list):
        for i in range (len(list)):
            if i == current:
                if i+1 < len(list):
                    return i+1
                else:
                    return 0
                break

    def __set_next_sub_track(self):
        # should work but untested , Maybe vlc doesn't understand mpeg-ts subs
        list = self.app.sub_tracks
        if len(list) > 0 :
            if self.cur_sub == None:
                if len(list) >1:
                    self.cur_sub = 1
                elif self.cur_sub == None:
                    self.cur_sub = 0

            self.cur_sub = self.__get_next_list(self.cur_sub,list)
            self.app.write('strack %s\n' % list[self.cur_sub])
            if list[self.cur_audio] == '-1':
                self.__osd_write('Subtitle Track Off' )
            else:
                self.__osd_write('Subtitle Track %d' % self.cur_sub )
        else:
            self.__osd_write('Subtitle Track none')
        return True

    def __set_next_fill(self):
        cmdlist = ['Default','vcrop 16:10','vcrop 16:9','vcrop 4:3','vratio 16:10','vratio 16:9','vratio 4:3']
        textlist = ['Default','Crop 16:10','Crop 16:9','Crop 4:3','Ratio 16:10','Ratio 16:9','Ratio 4:3']
        self.fill=self.__get_next_list(self.fill,cmdlist)
        self.app.write('vcrop Default\n')
        self.app.write('vratio Default\n')
        self.app.write('%s\n' % cmdlist[self.fill])
        self.__osd_write('Video Fill %s' % textlist[self.fill] )

    def __get_display_channel(self):
        channel = self.last_channel

        for tv_channel_id, tv_display_name, tv_tuner_id in config.TV_CHANNELS:
            if self.last_channel == tv_tuner_id:
                channel = tv_display_name

        return channel
Example #18
0
class Recorder:
    """
    """
    def __init__(self):
        logger.log(9, 'Recorder.__init__()')
        # Disable this plugin if not loaded by record_server.
        if string.find(sys.argv[0], 'recordserver') == -1:
            return

        logger.info('ACTIVATING VBI2SRT RECORD PLUGIN')

        self.vg = None
        self.fc = FreevoChannels()
        self.tuner_chidx = 0  # Current channel, index into config.TV_CHANNELS
        self.thread = Record_Thread()
        self.thread.setDaemon(1)
        self.thread.mode = 'idle'
        self.thread.start()

    def Record(self, rec_prog):
        logger.log(9, 'Record(rec_prog=%r)', rec_prog)
        frequency = self.fc.chanSet(str(rec_prog.tunerid), False,
                                    'record plugin')

        rec_prog.filename = tv_util.getProgFilename(rec_prog)
        rec_prog.filename = os.path.splitext(
            tv_util.getProgFilename(rec_prog))[0] + '.mpeg'
        logger.debug('filename=%r', rec_prog.filename)

        self.vg = self.fc.getVideoGroup(rec_prog.tunerid, False)

        cl_options = {
            'channel': rec_prog.tunerid,
            'frequency': frequency,
            'frequencyMHz': float(frequency) / 1000,
            'filename': rec_prog.filename,
            'base_filename': os.path.basename(rec_prog.filename),
            'title': rec_prog.title,
            'sub-title': rec_prog.sub_title,
            'seconds': rec_prog.rec_duration,
            'start': rec_prog.start,
            'pdc-start': rec_prog.pdc_start,
        }

        logger.debug('cl_options=%r', cl_options)
        logger.debug('chan_index=%r', self.fc.chan_index)
        logger.debug('vg.vdev=%r', self.vg.vdev)
        logger.debug('vg.vvbi=%r', self.vg.vvbi)
        pagenum = None
        try:
            pagenum = int(config.TV_CHANNELS[self.fc.chan_index][5])
        except:
            pagenum = None
        logger.debug('pagenum=%r', pagenum)

        if pagenum:
            # there is a bug in vbi2srt that causes out of sync subtitles when VPS is used
            self.rec_command = \
                'vbi2srt --verbose --video-in=%s --video-out=%s --vbi-device=%s --seconds=%s --vps=%s --page=%s' % \
                (self.vg.vdev, rec_prog.filename, self.vg.vvbi, rec_prog.rec_duration, rec_prog.pdc_start, pagenum)
        else:
            self.rec_command = \
                'vbi2srt --verbose --video-in=%s --video-out=%s --vbi-device=%s --seconds=%s --vps=%s' % \
                (self.vg.vdev, rec_prog.filename, self.vg.vvbi, rec_prog.rec_duration, rec_prog.pdc_start)
        logger.debug('rec_command=%r', self.rec_command)

        self.thread.mode = 'record'
        self.thread.prog = rec_prog
        self.thread.command = self.rec_command
        self.thread.autokill = float(rec_prog.rec_duration + 10)
        self.thread.mode_flag.set()

    def Stop(self):
        logger.log(9, 'Stop()')
        self.thread.mode = 'stop'
        self.thread.mode_flag.set()
Example #19
0
    # test code, run with freevo execute /path/to/upsoon.py
    config.DEBUG = 2
    function = None
    if len(sys.argv) > 1:
        function = sys.argv[1].lower()
        server = RecordClient()

    if function == 'run':
        #import rc as rctrl
        #rc = rctrl.get_singleton(False)
        pi = PluginInterface()
        kaa.main.run()

    elif function == 'findnextprogram':
        def handler(result):
            print 'findnextprogram=%r' % (result,)
            print result.__dict__
            raise SystemExit
        server.findNextProgram(handler)
        kaa.main.run()

    else:
        fc = FreevoChannels()
        vg=fc.getVideoGroup('K10', False)
        print 'vg=%s' % vg
        print 'dir(%s)' % dir(vg)
        for it in dir(vg):
            print '   %s:%s' % (it, eval('vg.'+it))
        vdev=vg.vdev
        print 'vdev=%s' % vdev
Example #20
0
class TVGuide(Item):
    def __init__(self, start_time, player, menuw):
        Item.__init__(self)

        self.n_items, hours_per_page = skin.items_per_page(('tv', self))
        stop_time = start_time + hours_per_page * 60 * 60

        msgtext = _('Preparing the program guide')
        guide = epg_xmltv.get_guide(PopupBox(text=msgtext))
        channels = guide.GetPrograms(start=start_time + 1, stop=stop_time - 1)
        if not channels:
            AlertBox(text=_('TV Guide is corrupt!')).show()
            return

        selected = None
        for chan in channels:
            if chan.programs:
                selected = chan.programs[0]
                break

        self.col_time = 30  # each col represents 30 minutes
        self.n_cols = (stop_time - start_time) / 60 / self.col_time
        self.player = player

        self.type = 'tv'
        self.menuw = menuw
        self.visible = True
        self.select_time = start_time
        self.last_update = 0

        self.lastinput_value = None
        self.lastinput_time = None

        self.update_schedules(force=True)
        self.fc = FreevoChannels()

        self.rebuild(start_time, stop_time, guide.chan_list[0].id, selected)
        self.event_context = 'tvmenu'
        menuw.pushmenu(self)

    def update_schedules(self, force=False):
        if not force and self.last_update + 60 > time.time():
            return

        # less than one second? Do not belive the force update
        if self.last_update + 1 > time.time():
            return

        upsoon = '%s/upsoon' % (config.FREEVO_CACHEDIR)
        if os.path.isfile(upsoon):
            os.unlink(upsoon)

        _debug_('update schedule', 2)
        self.last_update = time.time()
        self.scheduled_programs = []
        self.overlap_programs = []
        (got_schedule, schedule) = ri.getScheduledRecordings()

        util.misc.comingup(None, (got_schedule, schedule))

        if got_schedule:
            progs = schedule.getProgramList()
            for k in progs:
                prog = progs[k]
                self.scheduled_programs.append(prog.str2utf())
                if prog.overlap:
                    self.overlap_programs.append(prog.str2utf())

### event handler

    def eventhandler(self, event, menuw=None):
        """ Handles events in the tv guide

        Events handled by this are:
        MENU_CHANGE_STYLE: ?
        MENU_UP: Move one channel up in the guide
        MENU_DOWN: Move one channel down in the guide
        MENU_LEFT: Move to the next program on this channel
        MENU_RIGHT: Move to previous programm on this channel
        MENU_PAGEUP: Moves to the first of the currently displayed channels
        MENU_PAGEDOWN: Move to the last of the currently displayed channels
        MENU_SUBMENU: Open a submenu for the selected program
        MENU_SELECT: Open a submenu for the selected program
        TV_START_RECORDING: Start to record this or put it on schedule
        PLAY: Start to watch the selected channel (if it is possible)
        PLAY_END: Show the guide again
        numerical INPUTs: Jump to a specific channel number
        """

        _debug_('TVGUIDE EVENT is %s' % event, 0)

        ## MENU_CHANGE_STYLE
        if event == MENU_CHANGE_STYLE:
            if skin.toggle_display_style('tv'):
                start_time = self.start_time
                stop_time = self.stop_time
                start_channel = self.start_channel
                selected = self.selected

                self.n_items, hours_per_page = skin.items_per_page(
                    ('tv', self))

                before = -1
                after = -1
                for c in self.guide.chan_list:
                    if before >= 0 and after == -1:
                        before += 1
                    if after >= 0:
                        after += 1
                    if c.id == start_channel:
                        before = 0
                    if c.id == selected.channel_id:
                        after = 0

                if self.n_items <= before:
                    start_channel = selected.channel_id

                if after < self.n_items:
                    up = min(self.n_items - after, len(
                        self.guide.chan_list)) - 1
                    for i in range(len(self.guide.chan_list) - up):
                        if self.guide.chan_list[i + up].id == start_channel:
                            start_channel = self.guide.chan_list[i].id
                            break

                stop_time = start_time + hours_per_page * 60 * 60

                self.n_cols = (stop_time - start_time) / 60 / self.col_time
                self.rebuild(start_time, stop_time, start_channel, selected)

        ## MENU_UP: Move one channel up in the guide
        if event == MENU_UP:
            self.event_change_channel(-1)

        ## MENU_DOWN: Move one channel down in the guide
        elif event == MENU_DOWN:
            self.event_change_channel(1)

        ## MENU_LEFT: Move to the next program on this channel
        elif event == MENU_LEFT:
            self.event_change_program(-1)

        ## MENU_RIGHT: Move to previous programm on this channel
        elif event == MENU_RIGHT:
            self.event_change_program(1)

        ## MENU_PAGEUP: Moves to the first of the currently displayed channels
        elif event == MENU_PAGEUP:
            self.event_change_channel(-self.n_items)

        ## MENU_PAGEDOWN: Move to the last of the currently displayed channels
        elif event == MENU_PAGEDOWN:
            self.event_change_channel(self.n_items)

        ## MENU_SUBMENU: Open a submenu for the selected program
        elif event == MENU_SUBMENU:
            self.event_submenu()

        ## MENU_SELECT: Open a submenu for the selected program
        elif event == MENU_SELECT:
            self.event_submenu()

        ## TV_START_RECORDING: Start to record this or put it on schedule
        elif event == TV_START_RECORDING:
            self.event_record()

        ## PLAY: Start to watch the selected channel (if it is possible)
        elif event == PLAY:
            suffix = self.fc.getVideoGroup(self.selected.channel_id, True).vdev
            suffix = suffix.split('/')[-1]
            tvlockfile = config.FREEVO_CACHEDIR + '/record.' + suffix

            # Check if the selected program is >7 min in the future
            # if so, bring up the record dialog
            now = time.time() + (7 * 60)
            if self.selected.start > now:
                self.event_submenu()
            elif os.path.exists(tvlockfile):
                # XXX: In the future add the options to watch what we are
                #      recording or cancel it and watch TV.
                AlertBox(text=_('Sorry, you cannot watch TV while recording. ')+ \
                              _('If this is not true then remove ') + \
                              tvlockfile + '.', height=200).show()
                return TRUE
            else:
                self.hide()
                self.player('tv', self.selected.channel_id)

        ## PLAY_END: Show the guide again
        elif event == PLAY_END:
            self.show()

        ## numerical INPUT: Jump to a specific channel number
        if str(event).startswith("INPUT_"):
            # tune explicit channel
            eventInput = str(event)[6]
            isNumeric = TRUE
            try:
                newinput_value = int(eventInput)
            except:
                #Protected against INPUT_UP, INPUT_DOWN, etc
                isNumeric = FALSE
            if isNumeric:
                newinput_time = int(time.time())
                if (self.lastinput_value != None):
                    # allow 1 seconds delay for multiple digit channels
                    if (newinput_time - self.lastinput_time < 1):
                        # this enables multiple (max 3) digit channel selection
                        if (self.lastinput_value >= 100):
                            self.lastinput_value = (self.lastinput_value % 100)
                        newinput_value += self.lastinput_value * 10
                self.lastinput_value = newinput_value
                self.lastinput_time = newinput_time

                channel_no = int(newinput_value) - 1
                if channel_no < len(self.guide.chan_list):
                    self.start_channel = self.guide.chan_list[channel_no].id
                else:
                    self.lastinput_value = None

                self.rebuild(self.start_time, self.stop_time,
                             self.start_channel, self.selected)

        ## unknown event
        else:
            return FALSE

        return TRUE

    ### actions

    def show(self):
        """ show the guide"""
        if not self.visible:
            self.visible = 1
            self.refresh()

    def hide(self):
        """ hide the guide"""
        if self.visible:
            self.visible = 0
            skin.clear()

    def refresh(self):
        """refresh the guide

        This function is called automatically by freevo whenever this menu is
        opened or reopened.
        """
        _debug_('Refresh', 2)
        if not self.menuw.children:
            rc.set_context(self.event_context)
            self.menuw.refresh()
        self.update(force=True)

    def update(self, force=False):
        """ update the tv guide

        This function updates the scheduled and overlap flags for
        all currently displayed programs.
        """
        _debug_('Update', 2)
        self.update_schedules(force)
        if self.table:
            for t in self.table:
                try:
                    for p in t.programs:
                        if p in self.scheduled_programs:
                            p.scheduled = TRUE
                            # DO NOT change this to 'True' Twisted
                            # does not support boolean objects and
                            # it will break under Python 2.3
                        else:
                            p.scheduled = FALSE
                            # Same as above; leave as 'FALSE' until
                            # Twisted includes Boolean
                        if p in self.overlap_programs:
                            p.overlap = TRUE
                        else:
                            p.overlap = FALSE
                except:
                    pass

        self.menuw.refresh()

    def rebuild(self, start_time, stop_time, start_channel, selected):
        """ rebuild the guide

        This is neccessary we change the set of programs that have to be
        displayed, this is the case when the user moves around in the menu.
        """
        _debug_('Reload', 2)
        self.guide = epg_xmltv.get_guide()
        channels = self.guide.GetPrograms(start=start_time + 1,
                                          stop=stop_time - 1)

        table = []

        self.start_time = start_time
        self.stop_time = stop_time
        self.start_channel = start_channel
        self.selected = selected

        self.display_up_arrow = FALSE
        self.display_down_arrow = FALSE

        # table header
        table += [['Chan']]
        for i in range(int(self.n_cols)):
            table[0] += [start_time + self.col_time * i * 60]

        table += [self.selected]  # the selected program

        found_1stchannel = 0
        if stop_time == None:
            found_1stchannel = 1

        flag_selected = 0

        n = 0
        for chan in channels:
            if n >= self.n_items:
                self.display_down_arrow = TRUE
                break

            if start_channel != None and chan.id == start_channel:
                found_1stchannel = 1

            if not found_1stchannel:
                self.display_up_arrow = TRUE

            if found_1stchannel:
                if not chan.programs:
                    prg = epg_types.TvProgram()
                    prg.channel_id = chan.id
                    prg.start = 0
                    prg.stop = 2147483647  # Year 2038
                    prg.title = CHAN_NO_DATA
                    prg.desc = ''
                    chan.programs = [prg]

                for i in range(len(chan.programs)):
                    if selected:
                        if chan.programs[i] == selected:
                            flag_selected = 1

                table += [chan]
                n += 1

        if flag_selected == 0:
            for i in range(2, len(table)):
                if flag_selected == 1:
                    break
                else:
                    if table[i].programs:
                        for j in range(len(table[i].programs)):
                            if table[i].programs[j].stop > start_time:
                                self.selected = table[i].programs[j]
                                table[1] = table[i].programs[j]
                                flag_selected = 1
                                break

        self.table = table
        # then we can refresh the display with this programs
        self.update()

    def event_record(self):
        """ Add to schedule or remove from schedule

        This function adds or removes the selected program to schedule,
        if the user presses REC inside of TVGuide.
        This is a kind of a short cut, which directly manipulates the schedule
        without opening the submenu for ProgramItems.
        """
        if self.selected.scheduled:
            # remove this program from schedule it it is already scheduled
            pi = ProgramItem(self, prog=self.selected).remove_program()
        else:
            # otherwise add it to schedule without more questions
            pi = ProgramItem(self, prog=self.selected).schedule_program()
        self.refresh()

    def event_submenu(self):
        """ Opens the submenu for ProgramItems

        The user can choose from this submenu what to do with the selected
        program, e.g. schedule a program for recording or search for more of
        that program.
        """
        # create a ProgramItem for the selected program
        pi = ProgramItem(self, prog=self.selected)
        # and show its submenu
        pi.display_program(menuw=self.menuw)

    def event_change_program(self, value, full_scan=False):

        start_time = self.start_time
        stop_time = self.stop_time
        start_channel = self.start_channel
        last_prg = self.selected

        channel = self.guide.chan_dict[last_prg.channel_id]
        if full_scan:
            all_programs = self.guide.GetPrograms(start_time - 24 * 60 * 60,
                                                  stop_time + 24 * 60 * 60,
                                                  [channel.id])
        else:
            all_programs = self.guide.GetPrograms(start_time + 1,
                                                  stop_time - 1, [channel.id])

        # Current channel programs
        programs = all_programs[0].programs
        if programs:
            for i in range(len(programs)):
                if programs[i].title == last_prg.title and \
                   programs[i].start == last_prg.start and \
                   programs[i].stop == last_prg.stop and \
                   programs[i].channel_id == last_prg.channel_id:
                    break

            prg = None

            if value > 0:
                if i + value < len(programs):
                    prg = programs[i + value]
                elif full_scan:
                    prg = programs[-1]
                else:
                    return self.event_change_program(value, True)
            else:
                if i + value >= 0:
                    prg = programs[i + value]
                elif full_scan:
                    prg = programs[0]
                else:
                    return self.event_change_program(value, True)

            if prg.sub_title:
                procdesc = '"' + prg.sub_title + '"\n' + prg.desc
            else:
                procdesc = prg.desc
            to_info = (prg.title, procdesc)
            self.select_time = prg.start

            # set new (better) start / stop times
            extra_space = 0
            if prg.stop - prg.start > self.col_time * 60:
                extra_space = self.col_time * 60

            while prg.start + extra_space >= stop_time:
                start_time += (self.col_time * 60)
                stop_time += (self.col_time * 60)

            while prg.start + extra_space <= start_time:
                start_time -= (self.col_time * 60)
                stop_time -= (self.col_time * 60)

        else:
            prg = epg_types.TvProgram()
            prg.channel_id = channel.id
            prg.start = 0
            prg.stop = 2147483647  # Year 2038
            prg.title = CHAN_NO_DATA
            prg.desc = ''
            to_info = CHAN_NO_DATA

        self.rebuild(start_time, stop_time, start_channel, prg)

    def event_change_channel(self, value):
        start_time = self.start_time
        stop_time = self.stop_time
        start_channel = self.start_channel
        last_prg = self.selected

        for i in range(len(self.guide.chan_list)):
            if self.guide.chan_list[i].id == start_channel:
                start_pos = i
                end_pos = i + self.n_items
            if self.guide.chan_list[i].id == last_prg.channel_id:
                break

        channel_pos = min(len(self.guide.chan_list) - 1, max(0, i + value))

        # calc real changed value
        value = channel_pos - i

        if value < 0 and channel_pos and channel_pos <= start_pos:
            # move start channel up
            start_channel = self.guide.chan_list[start_pos + value].id

        if value > 0 and channel_pos < len(self.guide.chan_list)-1 and \
               channel_pos + 1 >= end_pos:
            # move start channel down
            start_channel = self.guide.chan_list[start_pos + value].id

        channel = self.guide.chan_list[channel_pos]

        programs = self.guide.GetPrograms(start_time + 1, stop_time - 1,
                                          [channel.id])
        programs = programs[0].programs

        prg = None
        if programs and len(programs) > 0:
            for i in range(len(programs)):
                if programs[i].stop > self.select_time and programs[
                        i].stop > start_time:
                    break

            prg = programs[i]
            if prg.sub_title:
                procdesc = '"' + prg.sub_title + '"\n' + prg.desc
            else:
                procdesc = prg.desc

            to_info = (prg.title, procdesc)
        else:
            prg = epg_types.TvProgram()
            prg.channel_id = channel.id
            prg.start = 0
            prg.stop = 2147483647  # Year 2038
            prg.title = CHAN_NO_DATA
            prg.desc = ''
            to_info = CHAN_NO_DATA

        self.rebuild(start_time, stop_time, start_channel, prg)
Example #21
0
class LocalBackend(Backend):
    """
    Class used to control tuning and the ringbuffer locally.
    """
    def __init__(self):
        super(LocalBackend, self).__init__()
        self.fc = FreevoChannels()

        self.livepause_app = None

        self.controller = None
        self.device_in_use = None
        self.last_channel = None

        self.mode = 'raw'
        self.events_enabled = False

    def get_server_address(self):
        return 'localhost'

    def set_mode(self, mode):
        if self.livepause_app:
            self.livepause_app.set_mode(mode)
        self.mode = mode

    def get_buffer_info(self):
        if self.livepause_app:
            return self.livepause_app.info()
        return (0.0,0,0,0)

    def set_events_enabled(self, enable):
        if self.livepause_app:
            self.livepause_app.events_enabled = enable
        self.events_enabled = enable

    def seekto(self, to_time):
        if self.livepause_app:
            self.livepause_app.seekto(to_time)

    def seek(self, time_delta, now=False):
        if self.livepause_app:
            self.livepause_app.seek(time_delta, now)

    def disable_buffering(self):
        if self.device_in_use:
            self.last_channel = None
            self.controller.stop_filling()
            self.controller = None
            self.device_in_use = None
            self.livepause_app.quit()
            self.livepause_app = None
            logger.debug('Buffering disabled.')


    def change_channel(self, channel):
        if self.last_channel == channel:
            # Already tune to this channel so nothing to do!
            return

        if self.device_in_use:
            self.controller.stop_filling()
            self.controller = None
            self.device_in_use = None

        if self.livepause_app is None:
            self.livepause_app = LivePauseApp(config.CONF.livepause,
                                              config.LIVE_PAUSE2_BUFFER_PATH,
                                              config.LIVE_PAUSE2_BUFFER_SIZE,
                                              config.LIVE_PAUSE2_PORT,
                                              self.send_event)
            self.livepause_app.set_mode(self.mode)
            self.livepause_app.events_enabled = self.events_enabled

        # Find the controller for this VideoGroup type
        vg = self.fc.getVideoGroup(channel, True)
        self.controller = controllers.get_controller(vg.group_type)
        if not self.controller:
            logger.debug('Failed to find controller for device')
            return

        self.fc.chanSet(channel, True)

        self.livepause_app.reset()
        self.livepause_app.events_enabled = True
        self.controller.start_filling(self.livepause_app, vg, channel, WAIT_FOR_DATA_TIMEOUT)
        self.device_in_use = vg
        self.last_channel = channel

    def save(self, filename, time_start, time_end):
        if self.livepause_app:
            self.livepause_app.save(filename, time_start, time_end)

    def cancelsave(self):
        if self.livepause_app:
            self.livepause_app.cancel_save()

    def send_event(self, to_send):
        to_send.post()
Example #22
0
class TunerControl:
    """
    Class that controls the tuner device
    """
    def __init__(self, xine):
        """ TunerControl constructor """
        self.xine = xine
        self.ivtv_init = False
        self.fc = FreevoChannels()
        self.curr_channel = None
        self.embed = None
        self.stack = []
        self.timer = OneShotTimer(self.timer_handler)

    def _kill_(self):
        """ TunerControl destructor """
        if self.embed:
            ivtv_dev.setvbiembed(self.embed)

    def program_timer(self):
        """ program the timer to start of next show on the current channel """
        _debug_('TunerControl: Program timer')
        # set timer to mark the next program
        start_t, stop_t, prog_s = self.GetInfo()
        if stop_t > 0:
            stop_t = stop_t - time.time()
            self.timer.start(stop_t)
            _debug_(
                'TunerControl: Timer set to mark next program in: %s seconds' %
                stop_t)
        else:
            _debug_('TunerControl: Timer not set, stop_t not available')
        self.ShowInfo()

    def timer_handler(self):
        """ handle timer event """
        _debug_('TunerControl: Timer event, mark new show')
        self.xine.SetMark()
        self.program_timer()

    def Stop(self):
        """ stop """
        self.ivtv_init = False

    def GetName(self):
        """ get channel name """
        tuner_id, chan_name, prog_info = self.fc.getChannelInfo(showtime=True)
        return prog_info

    def GetInfo(self):
        """ get channel info """
        tuner_id, chan_id, chan_name, start_t, stop_t, prog_s = self.fc.getChannelInfoRaw(
        )
        return (start_t, stop_t, prog_s)

    def ShowInfo(self):
        """ show channel info """
        if self.curr_channel != None:
            # show channel info
            #vg = self.fc.getVideoGroup(self.curr_channel, True)
            tuner_id, chan_name, prog_info = self.fc.getChannelInfo(
                showtime=False)
            self.xine.ShowMessage(msg='%s: %s' % (chan_name, prog_info))

    def PushChannel(self):
        """ push the current channel on the channel stack """
        if self.curr_channel != None:
            self.stack.append(self.curr_channel)
            _debug_('TunerControl: Pushed channel %s' % self.curr_channel)
        _debug_('TunerControl: Channel stack = %s' % self.stack)

    def UnpushChannel(self):
        """ remove the top channel fromthe channel stack """
        if len(self.stack) == 0:
            _debug_('TunerControl: Channel stack is empty')
        else:
            channel = self.stack.pop()
            _debug_('TunerControl: Unpushed channel %s' % channel)
        _debug_('TunerControl: Channel stack = %s' % self.stack)

    def PopChannel(self):
        """ pop the top channel from the channel stack and switch channel """
        if len(self.stack) == 0:
            _debug_('TunerControl: Channel stack is empty')
        else:
            channel = self.stack.pop()
            _debug_('TunerControl: Popped channel %s' % channel)
            self.SetVideoGroup(channel)
        _debug_('TunerControl: Channel stack = %s' % self.stack)

    def SetChannelByName(self, channel=None, clearstack=False):
        """ tune to a new channel by name """
        last_channel = self.curr_channel
        next_channel = None
        channel_index = -1

        if clearstack == True:
            self.stack = []
            self.curr_channel = None

        if channel == None:
            # get a channel
            next_channel = self.fc.getChannel()

        try:
            # lookup the channel name in TV_CHANNELS
            for pos in range(len(config.TV_CHANNELS)):
                entry = config.TV_CHANNELS[pos]
                if str(channel) == str(entry[2]):
                    channel_index = pos
                    next_channel = channel
                    break
        except ValueError:
            pass

        if (next_channel == None):
            _debug_(
                'TunerControl: Cannot find tuner channel %r in the TV channel listing'
                % channel, DWARNING)
        else:
            self.SetChannelByIndex(channel_index + 1)

    def SetChannelByIndex(self, channel):
        """ tune to a channel by index from the TV_CHANNELS list """
        # tune channel by index
        next_channel = self.fc.getManChannel(channel)
        _debug_('TunerControl: Explicit channel selection by index = %r' %
                next_channel)
        self.PushChannel()
        self.SetVideoGroup(next_channel)

    def SetChannelByNumber(self, channel):
        """ tune to a channel by actual channel number """
        # tune channel by number
        _debug_('TunerControl: Explicit channel selection by number = %r' %
                channel)
        self.PushChannel()
        self.SetVideoGroup(channel)

    def NextChannel(self):
        """ jump to the next channel in the TV_CHANNELS list """
        next_channel = self.fc.getNextChannel()
        _debug_('TunerControl: Next channel selection = %r' % next_channel)
        self.PushChannel()
        self.SetVideoGroup(next_channel)

    def PrevChannel(self):
        """ jump to the previous channel in the TV_CHANNELS list """
        prev_channel = self.fc.getPrevChannel()
        _debug_('TunerControl: Previous channel selection = %r' % prev_channel)
        self.PushChannel()
        self.SetVideoGroup(prev_channel)

    def SetVideoGroup(self, channel):
        """ select a channel's video group and tune to that channel """
        _debug_('TunerControl: Channel: %r' % channel)
        new_vg = self.fc.getVideoGroup(channel, True)
        _debug_('TunerControl: Group: type=%r, desc=%r' %
                (new_vg.group_type, new_vg.desc))
        _debug_('TunerControl: Input: type=%r, num=%r' %
                (new_vg.input_type, new_vg.input_num))

        if (new_vg.group_type != 'ivtv'):
            _debug_(
                'TunerControl: Video group %r is not supported' %
                new_vg.group_type, DERROR)
            pop = AlertBox(
                text=_('This plugin only supports the ivtv video group!'))
            pop.show()
            return

        # check if videogroup switch is needed
        switch_vg = (self.ivtv_init == False) or \
                    (self.curr_channel == None) or \
                    (new_vg != self.fc.getVideoGroup(self.curr_channel, True))

        if switch_vg == True:
            # switch to a different video group
            _debug_('TunerControl: Set video group: %s' % new_vg.vdev, DINFO)
            ivtv_dev = ivtv.IVTV(new_vg.vdev)
            ivtv_dev.init_settings()
            self.xine.SetInput(new_vg.input_num)

            # disable embedded vbi data
            self.embed = ivtv_dev.getvbiembed()
            ivtv_dev.setvbiembed(0)

        if self.ivtv_init == False:
            # set channel directly on v4l device
            self.ivtv_init = True
            self.fc.chanSet(channel, True)
            self.curr_channel = channel

            if config.XINE_TV_LIVE_RECORD:
                # video stream is marked implicitly
                # start timer to mark next show
                self.program_timer()
            else:
                self.ShowInfo()
        else:
            # set channel through xine process

            # get channel frequency
            freq = self.fc.chanSet(channel, True, 'ivtv_xine_tv', None)

            if freq != 0:
                # channel has frequency
                _debug_('TunerControl: Set frequency: %s' % freq)
                self.xine.SetFrequency(freq)
            else:
                # channel has no frequency
                _debug_('TunerControl: Channel has no frequency')

            self.curr_channel = channel

            if config.XINE_TV_LIVE_RECORD:
                # explicitly mark video stream
                self.xine.SetMark()
                # start timer to mark next show
                self.program_timer()
            else:
                self.xine.SeekEnd()
                self.ShowInfo()
Example #23
0
class Recorder:
    def __init__(self):
        # Disable this plugin if not loaded by record_server.
        if string.find(sys.argv[0], 'recordserver') == -1:
            return

        if DEBUG: print 'ACTIVATING VBI2SRT RECORD PLUGIN'

        self.vg = None
        self.fc = FreevoChannels()
        self.tuner_chidx = 0  # Current channel, index into config.TV_CHANNELS
        self.thread = Record_Thread()
        self.thread.setDaemon(1)
        self.thread.mode = 'idle'
        self.thread.start()

    def Record(self, rec_prog):
        frequency = self.fc.chanSet(str(rec_prog.tunerid), False,
                                    'record plugin')

        rec_prog.filename = tv_util.getProgFilename(rec_prog)
        rec_prog.filename = os.path.splitext(
            tv_util.getProgFilename(rec_prog))[0] + '.mpeg'
        if DEBUG: print('Recorder::Record:filename %s' % rec_prog.filename)

        cl_options = {
            'channel': rec_prog.tunerid,
            'frequency': frequency,
            'filename': rec_prog.filename,
            'base_filename': os.path.basename(rec_prog.filename),
            'title': rec_prog.title,
            'sub-title': rec_prog.sub_title,
            'seconds': rec_prog.rec_duration,
            'start': rec_prog.start,
            'pdc-start': rec_prog.pdc_start,
        }

        self.vg = self.fc.getVideoGroup(rec_prog.tunerid, False)
        if DEBUG: print('Recorder::Record:cl_options %s' % cl_options)
        if DEBUG: print('Recorder::Record:chan_index %s' % self.fc.chan_index)
        if DEBUG: print('Recorder::Record:vg.vdev %s' % self.vg.vdev)
        if DEBUG: print('Recorder::Record:vg.vvbi %s' % self.vg.vvbi)
        pagenum = None
        try:
            pagenum = int(config.TV_CHANNELS[self.fc.chan_index][5])
        except:
            pagenum = None
        if DEBUG: print('Recorder::Record:pagenum "%s"' % pagenum)
        self.rec_command = config.VCR_CMD % cl_options
        if pagenum == None:
            self.rec_command = 'vbi2srt --verbose --video-in=%s --video-out=%s --vbi-device=%s --seconds=%s --vps=%s' % \
                (self.vg.vdev, rec_prog.filename, self.vg.vvbi, rec_prog.rec_duration, rec_prog.pdc_start)
        else:
            # there is a bug in vbi2srt that causes out of sync subtitles when VPS is used
            self.rec_command = 'vbi2srt --verbose --video-in=%s --video-out=%s --vbi-device=%s --seconds=%s --vps=%s --page=%s' % \
                (self.vg.vdev, rec_prog.filename, self.vg.vvbi, rec_prog.rec_duration, rec_prog.pdc_start, pagenum)

        self.thread.mode = 'record'
        self.thread.prog = rec_prog
        self.thread.command = self.rec_command
        self.thread.autokill = float(rec_prog.rec_duration + 10)
        self.thread.mode_flag.set()

        if DEBUG: print('Recorder::Record: %s' % self.rec_command)

    def Stop(self):
        self.thread.mode = 'stop'
        self.thread.mode_flag.set()
Example #24
0
class MPlayer:

    __muted = 0
    __igainvol = 0

    def __init__(self):
        self.tuner_chidx = 0  # Current channel, index into config.TV_CHANNELS
        self.app_mode = 'tv'
        self.fc = FreevoChannels()
        self.current_vg = None

    def Play(self, mode, tuner_channel=None):

        if not tuner_channel:
            tuner_channel = self.fc.getChannel()

        vg = self.current_vg = self.fc.getVideoGroup(tuner_channel, True)

        # Convert to MPlayer TV setting strings
        norm = 'norm=%s' % vg.tuner_norm
        input = 'input=%s' % vg.input_num
        device = 'device=%s' % vg.vdev

        w, h = config.TV_VIEW_SIZE
        outfmt = 'outfmt=%s' % config.TV_VIEW_OUTFMT

        # Build the MPlayer command
        args = (config.MPLAYER_NICE, config.MPLAYER_CMD, config.MPLAYER_VO_DEV,
                config.MPLAYER_VO_DEV_OPTS, config.MPLAYER_AO_DEV,
                config.MPLAYER_ARGS_DEF)

        if mode == 'tv':
            if vg.group_type == 'ivtv':
                ivtv_dev = ivtv.IVTV(vg.vdev)
                ivtv_dev.init_settings()
                ivtv_dev.setinput(vg.input_num)
                #ivtv_dev.print_settings()
                ivtv_dev.close()
                self.fc.chanSet(tuner_channel, True)

                tvcmd = vg.vdev

                if config.MPLAYER_ARGS.has_key('ivtv'):
                    args += (config.MPLAYER_ARGS['ivtv'], )

            elif vg.group_type == 'webcam':
                self.fc.chanSet(tuner_channel, True, app='mplayer')
                tvcmd = ''

                if config.MPLAYER_ARGS.has_key('webcam'):
                    args += (config.MPLAYER_ARGS['webcam'], )

            elif vg.group_type == 'dvb':
                self.fc.chanSet(tuner_channel, True, app='mplayer')
                tvcmd = ''
                args += ('"dvb://%s" %s' %
                         (tuner_channel, config.MPLAYER_ARGS['dvb']), )

            elif vg.group_type == 'tvalsa':
                freq_khz = self.fc.chanSet(tuner_channel, True, app='mplayer')
                tuner_freq = '%1.3f' % (freq_khz / 1000.0)

                tvcmd = ('tv:// -tv driver=%s:%s:freq=%s:%s:%s:'
                         '%s:width=%s:height=%s:%s %s' %
                         (config.TV_DRIVER, vg.adev, tuner_freq, device, input,
                          norm, w, h, outfmt, config.TV_OPTS))

                if config.MPLAYER_ARGS.has_key('tv'):
                    args += (config.MPLAYER_ARGS['tv'], )

            else:  # group_type == 'normal'
                freq_khz = self.fc.chanSet(tuner_channel, True, app='mplayer')
                tuner_freq = '%1.3f' % (freq_khz / 1000.0)

                tvcmd = ('tv:// -tv driver=%s:freq=%s:%s:%s:'
                         '%s:width=%s:height=%s:%s %s' %
                         (config.TV_DRIVER, tuner_freq, device, input, norm, w,
                          h, outfmt, config.TV_OPTS))

                if config.MPLAYER_ARGS.has_key('tv'):
                    args += (config.MPLAYER_ARGS['tv'], )

        elif mode == 'vcr':
            tvcmd = ('tv:// -tv driver=%s:%s:%s:'
                     '%s:width=%s:height=%s:%s %s' %
                     (config.TV_DRIVER, device, input, norm, w, h, outfmt,
                      config.TV_OPTS))

            if config.MPLAYER_ARGS.has_key('tv'):
                args += (config.MPLAYER_ARGS['tv'], )

        else:
            print 'Mode "%s" is not implemented' % mode  # XXX ui.message()
            return

        args += (tvcmd, )

        mpl = '--prio=%s %s -vo %s %s -ao %s %s -slave %s %s' % args

        command = mpl
        _debug_('command=\"%s\"', (command))
        self.mode = mode

        # XXX Mixer manipulation code.
        # TV is on line in
        # VCR is mic in
        # btaudio (different dsp device) will be added later
        mixer = plugin.getbyname('MIXER')

        if mixer and config.MAJOR_AUDIO_CTRL == 'VOL':
            mixer_vol = mixer.getMainVolume()
            mixer.setMainVolume(0)
        elif mixer and config.MAJOR_AUDIO_CTRL == 'PCM':
            mixer_vol = mixer.getPcmVolume()
            mixer.setPcmVolume(0)

        # Start up the TV task
        self.app = childapp.ChildApp2(command)

        self.prev_app = rc.app()
        rc.app(self)

        if osd.focused_app():
            osd.focused_app().hide()

        # Suppress annoying audio clicks
        time.sleep(0.4)
        # XXX Hm.. This is hardcoded and very unflexible.
        if mixer and mode == 'vcr':
            mixer.setMicVolume(config.VCR_IN_VOLUME)
        elif mixer:
            mixer.setLineinVolume(config.TV_IN_VOLUME)
            mixer.setIgainVolume(config.TV_IN_VOLUME)

        if mixer and config.MAJOR_AUDIO_CTRL == 'VOL':
            mixer.setMainVolume(mixer_vol)
        elif mixer and config.MAJOR_AUDIO_CTRL == 'PCM':
            mixer.setPcmVolume(mixer_vol)

        if DEBUG: print '%s: started %s app' % (time.time(), self.mode)

    def Stop(self, channel_change=0):
        mixer = plugin.getbyname('MIXER')
        if mixer and not channel_change:
            mixer.setLineinVolume(0)
            mixer.setMicVolume(0)
            mixer.setIgainVolume(0)  # Input on emu10k cards.

        self.app.stop('quit\n')

        rc.app(self.prev_app)
        if osd.focused_app() and not channel_change:
            osd.focused_app().show()

        if os.path.exists('/tmp/freevo.wid'): os.unlink('/tmp/freevo.wid')

    def eventhandler(self, event, menuw=None):
        s_event = '%s' % event

        if event == em.STOP or event == em.PLAY_END:
            self.Stop()
            rc.post_event(em.PLAY_END)
            return TRUE

        elif event == em.PAUSE or event == em.PLAY:
            self.app.write('pause\n')
            if DEBUG: print '%s: sending pause to mplayer' % (time.time())
            return TRUE

        elif event in [em.TV_CHANNEL_UP, em.TV_CHANNEL_DOWN
                       ] or s_event.startswith('INPUT_'):
            chan = None
            if event == em.TV_CHANNEL_UP:
                nextchan = self.fc.getNextChannel()
                nextchannum = self.fc.getNextChannelNum()
            elif event == em.TV_CHANNEL_DOWN:
                nextchan = self.fc.getPrevChannel()
                nextchannum = self.fc.getPrevChannelNum()
            else:
                chan = int(s_event[6])
                nextchan = self.fc.getManChannel(chan)
                nextchannum = self.fc.getManChannelNum(chan)

            nextvg = self.fc.getVideoGroup(nextchan, True)
            _debug_('chan=%s, nextchannum=%s, nextchan=%s nextvg=%s' %
                    (chan, nextchannum, nextchan, nextvg))

            if self.current_vg != nextvg:
                self.Stop(channel_change=1)
                self.Play('tv', nextchan)
                return TRUE

            if self.mode == 'vcr':
                return

            elif self.current_vg.group_type == 'dvb':
                card = 0  # May be this should come from video groups or TV_CHANNELS
                if em.TV_CHANNEL_UP:
                    self.app.write('dvb_set_channel %s %s\n' %
                                   (nextchannum, card))
                elif em.TV_CHANNEL_DOWN:
                    self.app.write('dvb_set_channel %s %s\n' %
                                   (nextchannum, card))
                return TRUE

            elif self.current_vg.group_type == 'ivtv':
                self.fc.chanSet(nextchan, True)
                self.app.write('seek 999999 0\n')

            else:
                freq_khz = self.fc.chanSet(nextchan, True, app=self.app)
                new_freq = '%1.3f' % (freq_khz / 1000.0)
                self.app.write('tv_set_freq %s\n' % new_freq)

            self.current_vg = self.fc.getVideoGroup(self.fc.getChannel(), True)

            # Display a channel changed message
            tuner_id, chan_name, prog_info = self.fc.getChannelInfo()
            now = time.strftime('%H:%M')
            msg = '%s %s (%s): %s' % (now, chan_name, tuner_id, prog_info)
            cmd = 'osd_show_text "%s"\n' % msg
            self.app.write(cmd)
            return TRUE

        elif event == em.TOGGLE_OSD:
            # Display the channel info message
            tuner_id, chan_name, prog_info = self.fc.getChannelInfo()
            now = time.strftime('%H:%M')
            msg = '%s %s (%s): %s' % (now, chan_name, tuner_id, prog_info)
            cmd = 'osd_show_text "%s"\n' % msg
            self.app.write(cmd)
            return FALSE

        return FALSE
Example #25
0
class Xawtv:

    __muted = 0
    __igainvol = 0

    def __init__(self, app, remote):
        self.tuner_chidx = 0  # Current channel, index into config.TV_CHANNELS
        self.app_mode = 'tv'
        self.fc = FreevoChannels()
        self.current_vg = None
        self.xawtv_prog = app
        self.remote_prog = remote

    def TunerSetChannel(self, tuner_channel):
        for pos in range(len(config.TV_CHANNELS)):
            channel = config.TV_CHANNELS[pos]
            if channel[2] == tuner_channel:
                self.tuner_chidx = pos
                return
        print 'ERROR: Cannot find tuner channel "%s" in the TV channel listing' % tuner_channel
        self.tuner_chidx = 0

    def TunerGetChannelInfo(self):
        '''Get program info for the current channel'''

        tuner_id = config.TV_CHANNELS[self.tuner_chidx][2]
        chan_name = config.TV_CHANNELS[self.tuner_chidx][1]
        chan_id = config.TV_CHANNELS[self.tuner_chidx][0]

        channels = epg.get_guide().get_programs(time.time(), time.time(),
                                                chan_id)

        if channels and channels[0] and channels[0].programs:
            start_s = time.strftime(
                config.TV_TIME_FORMAT,
                time.localtime(channels[0].programs[0].start))
            stop_s = time.strftime(
                config.TV_TIME_FORMAT,
                time.localtime(channels[0].programs[0].stop))
            ts = '(%s-%s)' % (start_s, stop_s)
            prog_info = '%s %s' % (ts, channels[0].programs[0].title)
        else:
            prog_info = 'No info'

        return tuner_id, chan_name, prog_info

    def TunerGetChannel(self):
        return config.TV_CHANNELS[self.tuner_chidx][2]

    def TunerNextChannel(self):
        self.tuner_chidx = (self.tuner_chidx + 1) % len(config.TV_CHANNELS)

    def TunerPrevChannel(self):
        self.tuner_chidx = (self.tuner_chidx - 1) % len(config.TV_CHANNELS)

    def Play(self, mode, tuner_channel=None, channel_change=0):

        if tuner_channel != None:
            try:
                self.TunerSetChannel(tuner_channel)
            except ValueError:
                pass
        if not tuner_channel:
            tuner_channel = self.fc.getChannel()
        vg = self.current_vg = self.fc.getVideoGroup(tuner_channel, True)

        if not vg.group_type == 'normal':
            print 'Xawtv only supports normal. "%s" is not implemented' % vg.group_type
            return

        if mode == 'tv' or mode == 'vcr':

            w, h = config.TV_VIEW_SIZE
            cf_norm = vg.tuner_norm
            cf_input = vg.input_num
            cf_device = vg.vdev

            s_norm = cf_norm.upper()

            if mode == 'vcr':
                cf_input = '1'
                if hasattr(config,
                           "TV_VCR_INPUT_NUM") and config.TV_VCR_INPUT_NUM:
                    cf_input = config.TV_VCR_INPUT_NUM

            if hasattr(config, "TV_XAWTV_OPTS") and config.TV_XAWTV_OPTS:
                daoptions = config.TV_XAWTV_OPTS
            else:
                daoptions = '-xv -f'

            command = '%s %s -device %s ' % (self.xawtv_prog, daoptions,
                                             cf_device)

        else:
            print 'Mode "%s" is not implemented' % mode  # BUG ui.message()
            return

        self.mode = mode

        mixer = plugin.getbyname('MIXER')

        # BUG Mixer manipulation code.
        # TV is on line in
        # VCR is mic in
        # btaudio (different dsp device) will be added later
        if mixer and config.MIXER_MAJOR_CTRL == 'VOL':
            mixer_vol = mixer.getMainVolume()
            mixer.setMainVolume(0)
        elif mixer and config.MIXER_MAJOR_CTRL == 'PCM':
            mixer_vol = mixer.getPcmVolume()
            mixer.setPcmVolume(0)

        # Start up the TV task
        self.app = XawtvApp(command, self.remote_prog)

        if tuner_channel:
            time.sleep(0.5)
            self.app.sendcmd('setstation %s' % tuner_channel)
        #XXX use remote to change the input we want

        self.prev_app = rc.app()
        rc.app(self)

        # Suppress annoying audio clicks
        time.sleep(0.4)
        # BUG Hm.. This is hardcoded and very unflexible.
        if mixer and mode == 'vcr':
            mixer.setMicVolume(config.MIXER_VOLUME_VCR_IN)
        elif mixer:
            mixer.setLineinVolume(config.MIXER_VOLUME_TV_IN)
            mixer.setIgainVolume(config.MIXER_VOLUME_TV_IN)

        if mixer and config.MIXER_MAJOR_CTRL == 'VOL':
            mixer.setMainVolume(mixer_vol)
        elif mixer and config.MIXER_MAJOR_CTRL == 'PCM':
            mixer.setPcmVolume(mixer_vol)

        _debug_('%s: started %s app' % (time.time(), self.mode))

    def Stop(self, channel_change=0):
        mixer = plugin.getbyname('MIXER')
        if mixer and not channel_change:
            mixer.setLineinVolume(0)
            mixer.setMicVolume(0)
            mixer.setIgainVolume(0)  # Input on emu10k cards.

        self.app.stop()
        rc.app(self.prev_app)

    def eventhandler(self, event, menuw=None):
        _debug_('%s: %s app got %s event' % (time.time(), self.mode, event))
        if event == em.STOP or event == em.PLAY_END:
            self.app.sendcmd('quit')
            time.sleep(1)
            self.Stop()
            rc.post_event(em.PLAY_END)
            return True

        elif event == em.TV_CHANNEL_UP or event == em.TV_CHANNEL_DOWN:
            if self.mode == 'vcr':
                return

            if event == em.TV_CHANNEL_UP:
                self.TunerPrevChannel()
                self.app.sendcmd('setstation next')
            else:
                self.TunerNextChannel()
                self.app.sendcmd('setstation prev')

            return True

        elif event == em.TOGGLE_OSD:
            #try to send channel name
            self.app.sendcmd('msg \'%s\'' % self.TunerGetChannel())
            return True

        elif event == em.OSD_MESSAGE:
            self.app.sendcmd('msg \'%s\'' % event.arg)
            return True

        elif event in em.INPUT_ALL_NUMBERS:
            self.app.sendcmd('keypad %s' % event.arg)

        elif event == em.BUTTON:
            if event.arg == 'PREV_CH':
                self.app.sendcmd('setstation back')
                return True

        return False
Example #26
0
class PluginInterface(plugin.DaemonPlugin):
    """
    plugin to monitor if a recording is about to start and shut down the
    player if the video device is in use

    To activate this plugin, just put the following line at the end of your
    local_conf.py file:

    | plugin.activate('tv.upsoon')
    """
    __author__           = 'Duncan Webb'
    __author_email__     = '*****@*****.**'
    __maintainer__       = __author__
    __maintainer_email__ = __author_email__
    __version__          = '$Revision$'


    def __init__(self, standalone=False):
        """
        init the upsoon plugin
        """
        logger.log( 9, 'upsoon.PluginInterface.__init__()')
        plugin.DaemonPlugin.__init__(self)
        plugin.register(self, 'upsoon')
        self.standalone = standalone
        self.lock = thread.allocate_lock()
        self.running = True
        self.timer = Timer(self.timer_handler).start(15)
        self.event = EventHandler(self.event_handler)
        #self.event.register(('VIDEO_START', 'VIDEO_END'))
        self.event.register()

        self.recordclient = RecordClient()

        self.fc = FreevoChannels()
        self.rdev = config.RADIO_DEVICE

        self.next_program = None
        self.announced = False
        self.seconds_before_announce = config.TV_UPSOON_ANNOUNCE
        self.seconds_before_start = config.TV_UPSOON_BEFORE_START
        self.pending_lockfile = config.FREEVO_CACHEDIR + '/record.soon'
        self.tv_lockfile = None # lockfile of recordserver
        self.stopped = None     # flag that tells upsoon what stopped
        if os.path.exists(self.pending_lockfile):
            os.remove(self.pending_lockfile)
            logger.debug('%r lockfile removed', self.pending_lockfile)


    def config(self):
        return [
            ('TV_UPSOON_BEFORE_START', 1*60, 'Number of seconds before start of recording to stop player'),
            ('TV_UPSOON_ANNOUNCE', 1*60+60, 'Number of seconds before start of recording to announce starting'),
        ]


    def getVideoForChannel(self, channel_id):
        """ get the video device given a channel id """
        logger.log( 9, 'getVideoForChannel(channel_id=%r)', channel_id)
        return self.fc.getVideoGroup(channel_id, False, CHANNEL_ID).vdev


    def stopVideoInUse(self, vdev):
        """ stop the video device if being used """
        logger.log( 9, 'stopVideoInUse(vdev=%r)', vdev)
        if vdev:
            try:
                dev_fh = os.open(vdev, os.O_TRUNC)
                try:
                    os.read(dev_fh, 1)
                except:
                    if (self.seconds_to_next > self.seconds_before_start):
                        # just announce
                        rc.post_event(Event(OSD_MESSAGE, arg=_('A recording will start in a few minutes')))
                    else:
                        # stop the tv
                        rc.post_event(STOP)
                        self.stopped = _('TV')
                os.close(dev_fh)
            except Exception, why:
                logger.warning('cannot check video device %r: %s', vdev, why)
Example #27
0
class MPlayer:
    __muted    = 0
    __igainvol = 0

    def __init__(self):
        self.tuner_chidx = 0    # Current channel, index into config.TV_CHANNELS
        self.event_context = 'tv'
        self.fc = FreevoChannels()
        self.current_vg = None


    def Play(self, mode, tuner_channel=None):
        """ """
        logger.log( 9, 'MPlayer.Play(mode=%r, tuner_channel=%r)', mode, tuner_channel)
        # Try to see if the channel is not tunable
        try:
            channel = int(tuner_channel)
        except ValueError:
            channel = 0

        vg = self.current_vg = self.fc.getVideoGroup(tuner_channel, True)

        if not tuner_channel:
            tuner_channel = self.fc.getChannel()

        # Convert to MPlayer TV setting strings
        device = 'device=%s' % vg.vdev
        input = 'input=%s' % vg.input_num
        norm = 'norm=%s' % vg.tuner_norm

        w, h = config.TV_VIEW_SIZE
        outfmt = 'outfmt=%s' % config.TV_VIEW_OUTFMT

        # Build the MPlayer command line
        args = {
            'nice': config.MPLAYER_NICE,
            'cmd': config.MPLAYER_CMD,
            'vo': '-vo %s' % config.MPLAYER_VO_DEV,
            'vo_opts': config.MPLAYER_VO_DEV_OPTS,
            'vc': '',
            'ao': '-ao %s' % config.MPLAYER_AO_DEV,
            'ao_opts': config.MPLAYER_AO_DEV_OPTS,
            'default_args': config.MPLAYER_ARGS_DEF.split(),
            'mode_args': config.MPLAYER_ARGS.has_key(mode) and config.MPLAYER_ARGS[mode].split() or [],
            'geometry': (config.CONF.x or config.CONF.y) and '-geometry %d:%d' % (config.CONF.x, config.CONF.y) or '',
            'verbose': '',
            'dvd-device': '',
            'cdrom-device': '',
            'alang': '',
            'aid': '',
            'slang': '',
            'sid': '',
            'playlist': '',
            'field-dominance': '',
            'edl': '',
            'mc': '',
            'delay': '',
            'sub': '',
            'audiofile': '',
            'af': [],
            'vf': [],
            'tv': '',
            'url': '',
            'disable_osd': False,
        }

        if dialog.overlay_display_supports_dialogs:
            # Disable the mplayer OSD if we have a better option.
            args['disable_osd'] = True

        if mode == 'tv':
            if vg.group_type == 'ivtv':
                ivtv_dev = ivtv.IVTV(vg.vdev)
                ivtv_dev.init_settings()
                ivtv_dev.setinputbyname(vg.input_type)
                cur_std = ivtv_dev.getstd()
                import tv.v4l2
                try:
                    new_std = tv.v4l2.NORMS.get(vg.tuner_norm)
                    if cur_std != new_std:
                        ivtv_dev.setstd(new_std)
                except:
                    logger.error('Error! Videogroup norm value "%s" not from NORMS: %s', vg.tuner_norm, tv.v4l2.NORMS.keys())

                ivtv_dev.close()

                # Do not set the channel if negative
                if channel >= 0:
                    self.fc.chanSet(tuner_channel, True)

                args['url'] = vg.vdev

                if config.MPLAYER_ARGS.has_key('ivtv'):
                    args['mode_args'] = config.MPLAYER_ARGS['ivtv'].split()

            elif vg.group_type == 'webcam':
                self.fc.chanSet(tuner_channel, True, app='mplayer')
                args['url'] = ''

                if config.MPLAYER_ARGS.has_key('webcam'):
                    args['mode_args'] = config.MPLAYER_ARGS['webcam'].split()

            elif vg.group_type == 'dvb':
                self.fc.chanSet(tuner_channel, True, app='mplayer')
                args['url'] = ('dvb://%s' % (tuner_channel,))
                args['mode_args'] = config.MPLAYER_ARGS['dvb'].split()

            elif vg.group_type == 'tvalsa':
                freq_khz = self.fc.chanSet(tuner_channel, True, app='mplayer')
                tuner_freq = '%1.3f' % (freq_khz / 1000.0)

                args['tv'] = '-tv driver=%s:%s:freq=%s:%s:%s:%s:width=%s:height=%s:%s %s' % \
                    (config.TV_DRIVER, vg.adev, tuner_freq, device, input, norm, w, h, outfmt, config.TV_OPTS)
                args['url'] = 'tv://'

                if config.MPLAYER_ARGS.has_key('tv'):
                    args['mode_args'] = config.MPLAYER_ARGS['tv'].split()

            else: # group_type == 'normal'
                freq_khz = self.fc.chanSet(tuner_channel, True, app='mplayer')
                tuner_freq = '%1.3f' % (freq_khz / 1000.0)

                args['tv'] = '-tv driver=%s:freq=%s:%s:%s:%s:width=%s:height=%s:%s %s' % \
                    (config.TV_DRIVER, tuner_freq, device, input, norm, w, h, outfmt, config.TV_OPTS)
                args['url'] = 'tv://'

                if config.MPLAYER_ARGS.has_key('tv'):
                    args['mode_args'] = config.MPLAYER_ARGS['tv'].split()

        elif mode == 'vcr':
            args['tv'] = '-tv driver=%s:%s:%s:%s:width=%s:height=%s:%s %s' % \
                (config.TV_DRIVER, device, input, norm, w, h, outfmt, config.TV_OPTS)
            args['url'] = 'tv://'

            if config.MPLAYER_ARGS.has_key('tv'):
                args['mode_args'] = config.MPLAYER_ARGS['tv'].split()

        else:
            logger.error('Mode "%s" is not implemented', mode)
            return

        logger.debug('mplayer args = %r', args)

        vo = ['%(vo)s' % args, '%(vo_opts)s' % args]
        vo = filter(len, vo)
        vo = ':'.join(vo)

        ao = ['%(ao)s' % args, '%(ao_opts)s' % args]
        ao = filter(len, ao)
        ao = ':'.join(ao)

        command = ['--prio=%(nice)s' % args]
        command += ['%(cmd)s' % args]
        command += ['-slave']
        command += str('%(verbose)s' % args).split()
        command += str('%(geometry)s' % args).split()
        command += vo.split()
        command += str('%(vc)s' % args).split()
        command += ao.split()
        command += args['default_args']
        command += args['mode_args']
        command += str('%(dvd-device)s' % args).split()
        command += str('%(cdrom-device)s' % args).split()
        command += str('%(alang)s' % args).split()
        command += str('%(aid)s' % args).split()
        command += str('%(audiofile)s' % args).split()
        command += str('%(slang)s' % args).split()
        command += str('%(sid)s' % args).split()
        command += str('%(sub)s' % args).split()
        command += str('%(field-dominance)s' % args).split()
        command += str('%(edl)s' % args).split()
        command += str('%(mc)s' % args).split()
        command += str('%(delay)s' % args).split()
        if args['af']:
            command += ['-af', '%s' % ','.join(args['af'])]
        if args['vf']:
            command += ['-vf', '%s' % ','.join(args['vf'])]
        command += str('%(tv)s' % args).split()
	command += args['disable_osd'] and ['-osdlevel', '0'] or []
        
        if config.OSD_SINGLE_WINDOW:
            command += ['-wid', str(osd.video_window.id)]
            osd.video_window.show()

        # use software scaler?
        if '-nosws' in command:
            command.remove('-nosws')
        elif '-framedrop' not in command:
            command += config.MPLAYER_SOFTWARE_SCALER.split()

        #if options:
        #    command += options

        command = filter(len, command)

        #command = self.sort_filter(command)

        url = '%(url)s' % args
        command += [url]

        logger.debug('%r', command)

        self.mode = mode


        # XXX Mixer manipulation code.
        # TV is on line in
        # VCR is mic in
        # btaudio (different dsp device) will be added later
        mixer = plugin.getbyname('MIXER')

        if mixer and config.MIXER_MAJOR_CTRL == 'VOL':
            mixer_vol = mixer.getMainVolume()
            mixer.setMainVolume(0)
        elif mixer and config.MIXER_MAJOR_CTRL == 'PCM':
            mixer_vol = mixer.getPcmVolume()
            mixer.setPcmVolume(0)

        # Start up the TV task
        self.app = childapp.ChildApp2(command)

        rc.add_app(self)

        # Suppress annoying audio clicks
        time.sleep(0.4)
        # XXX Hm.. This is hardcoded and very unflexible.
        if mixer and mode == 'vcr':
            mixer.setMicVolume(config.MIXER_VOLUME_VCR_IN)
        elif mixer:
            mixer.setLineinVolume(config.MIXER_VOLUME_TV_IN)
            mixer.setIgainVolume(config.MIXER_VOLUME_TV_IN)

        if mixer and config.MIXER_MAJOR_CTRL == 'VOL':
            mixer.setMainVolume(mixer_vol)
        elif mixer and config.MIXER_MAJOR_CTRL == 'PCM':
            mixer.setPcmVolume(mixer_vol)

        dialog.enable_overlay_display(AppTextDisplay(self.show_message))
        logger.debug('%s: started %s app', time.time(), self.mode)



    def Stop(self, channel_change=0):
        mixer = plugin.getbyname('MIXER')
        if mixer and not channel_change:
            mixer.setLineinVolume(0)
            mixer.setMicVolume(0)
            mixer.setIgainVolume(0) # Input on emu10k cards.

        if config.OSD_SINGLE_WINDOW:
            osd.video_window.hide()
            
        self.app.stop('quit\n')

        rc.remove_app(self)

        if os.path.exists('/tmp/freevo.wid'): os.unlink('/tmp/freevo.wid')

        if config.MPLAYER_OLDTVCHANNELCHANGE:
            lastchanfile = os.path.join(config.FREEVO_CACHEDIR, 'lastchan')
            lcfp = open(lastchanfile, "w")
            lastchan = self.fc.getChannel()
            lastchannum = self.fc.getChannelNum()
            lcfp.write(str(lastchan))
            lcfp.write('\n')
            lcfp.write(str(lastchannum))
            lcfp.write('\n')
            lcfp.close()

        dialog.disable_overlay_display()


    def eventhandler(self, event, menuw=None):
        s_event = '%s' % event

        if event == em.STOP or event == em.PLAY_END:
            self.Stop()
            rc.post_event(em.PLAY_END)
            return True

        elif event == em.PAUSE or event == em.PLAY:
            self.app.write('pause\n')
            logger.debug('%s: sending pause to mplayer', time.time())
            return True

        elif event in [ em.TV_CHANNEL_UP, em.TV_CHANNEL_DOWN, em.TV_CHANNEL_LAST ] or s_event.startswith('INPUT_'):
            chan = None
            if event == em.TV_CHANNEL_UP:
                nextchan = self.fc.getNextChannel()
                nextchannum = self.fc.getNextChannelNum()
            elif event == em.TV_CHANNEL_DOWN:
                nextchan = self.fc.getPrevChannel()
                nextchannum = self.fc.getPrevChannelNum()
            elif event == em.TV_CHANNEL_LAST:
                if config.MPLAYER_OLDTVCHANNELCHANGE:
                    if os.path.isfile(os.path.join(config.FREEVO_CACHEDIR, 'lastchan')):
                        lastchanfile = os.path.join(config.FREEVO_CACHEDIR, 'lastchan')
                        lcfp = open(lastchanfile, "r")
                        nextchan = lcfp.readline()
                        nextchan = nextchan.strip()
                        nextchannum = lcfp.readline()
                        nextchannum = nextchannum.strip()
                        nextchannum = int(nextchannum)
                        lcfp.close()
                    else:
                        nextchan = self.fc.getChannel()
                        nextchannum = self.fc.getChannelNum()
                else:
                    return True
            else:
                chan = int(s_event[6])
                nextchan = self.fc.getManChannel(chan)
                nextchannum = self.fc.getManChannelNum(chan)

            nextvg = self.fc.getVideoGroup(nextchan, True)
            logger.debug('chan=%s, nextchannum=%s, nextchan=%s nextvg=%s', chan, nextchannum, nextchan, nextvg)

            if self.current_vg != nextvg:
                self.Stop(channel_change=1)
                self.Play('tv', nextchan)
                return True

            if self.mode == 'vcr':
                return

            elif self.current_vg.group_type == 'dvb':
                if not config.MPLAYER_OLDTVCHANNELCHANGE:
                    card = 0 # May be this should come from video groups or TV_CHANNELS
                    if em.TV_CHANNEL_UP:
                        self.app.write('dvb_set_channel %s %s\n' % (nextchannum, card))
                        self.fc.chanSet(nextchan, True)
                    elif em.TV_CHANNEL_DOWN:
                        self.app.write('dvb_set_channel %s %s\n' % (nextchannum, card))
                        self.fc.chanSet(nextchan, True)
                else:
                    self.Stop(channel_change=1)
                    self.Play('tv', nextchan)
                return True

            elif self.current_vg.group_type == 'ivtv':
                self.fc.chanSet(nextchan, True)
                self.app.write('seek 999999 0\n')

            else:
                freq_khz = self.fc.chanSet(nextchan, True, app=self.app)
                new_freq = '%1.3f' % (freq_khz / 1000.0)
                self.app.write('tv_set_freq %s\n' % new_freq)

            self.current_vg = self.fc.getVideoGroup(self.fc.getChannel(), True)

            # Display a channel changed message
            tuner_id, chan_name, prog_info = self.fc.getChannelInfo()
            now = time.strftime(config.TV_TIME_FORMAT)
            msg = '%s %s (%s): %s' % (now, chan_name, tuner_id, prog_info)
            cmd = 'osd_show_text "%s"\n' % msg
            self.app.write(cmd)
            return True

        elif event == em.TOGGLE_OSD:
	    if dialog.is_dialog_supported():
                dialog.show_play_state(dialog.PLAY_STATE_INFO, self.fc)
            else:
            # Display the channel info message
                tuner_id, chan_name, prog_info = self.fc.getChannelInfo()
                now = time.strftime(config.TV_TIME_FORMAT)
                msg = '%s %s (%s): %s' % (now, chan_name, tuner_id, prog_info)
                cmd = 'osd_show_text "%s"\n' % msg
                self.app.write(cmd)
                return False

        elif event == em.OSD_MESSAGE:
            self.app.write('osd_show_text "%s"\n' % event.arg);
            return True

        elif event == em.TV_SEND_MPLAYER_CMD:
            self.app.write('%s\n' % event.arg);
            return True

        return False

    def show_message(self, message):
        self.app.write('osd_show_text "%s"\n' % message)
Example #28
0
class Recorder:
    """
    """
    def __init__(self):
        logger.log( 9, 'Recorder.__init__()')
        # Disable this plugin if not loaded by record_server.
        if string.find(sys.argv[0], 'recordserver') == -1:
            return

        logger.info('ACTIVATING VBI2SRT RECORD PLUGIN')

        self.vg = None
        self.fc = FreevoChannels()
        self.tuner_chidx = 0    # Current channel, index into config.TV_CHANNELS
        self.thread = Record_Thread()
        self.thread.setDaemon(1)
        self.thread.mode = 'idle'
        self.thread.start()


    def Record(self, rec_prog):
        logger.log( 9, 'Record(rec_prog=%r)', rec_prog)
        frequency = self.fc.chanSet(str(rec_prog.tunerid), False, 'record plugin')

        rec_prog.filename = tv_util.getProgFilename(rec_prog)
        rec_prog.filename = os.path.splitext(tv_util.getProgFilename(rec_prog))[0] + '.mpeg'
        logger.debug('filename=%r', rec_prog.filename)

        self.vg = self.fc.getVideoGroup(rec_prog.tunerid, False)

        cl_options = { 'channel'  : rec_prog.tunerid,
                       'frequency' : frequency,
                       'frequencyMHz' : float(frequency) / 1000,
                       'filename' : rec_prog.filename,
                       'base_filename' : os.path.basename(rec_prog.filename),
                       'title' : rec_prog.title,
                       'sub-title' : rec_prog.sub_title,
                       'seconds'  : rec_prog.rec_duration,
                       'start'  : rec_prog.start,
                       'pdc-start'  : rec_prog.pdc_start,
        }

        logger.debug('cl_options=%r', cl_options)
        logger.debug('chan_index=%r', self.fc.chan_index)
        logger.debug('vg.vdev=%r', self.vg.vdev)
        logger.debug('vg.vvbi=%r', self.vg.vvbi)
        pagenum = None;
        try:
            pagenum = int(config.TV_CHANNELS[self.fc.chan_index][5])
        except:
            pagenum = None;
        logger.debug('pagenum=%r', pagenum)

        if pagenum:
            # there is a bug in vbi2srt that causes out of sync subtitles when VPS is used
            self.rec_command = \
                'vbi2srt --verbose --video-in=%s --video-out=%s --vbi-device=%s --seconds=%s --vps=%s --page=%s' % \
                (self.vg.vdev, rec_prog.filename, self.vg.vvbi, rec_prog.rec_duration, rec_prog.pdc_start, pagenum)
        else:
            self.rec_command = \
                'vbi2srt --verbose --video-in=%s --video-out=%s --vbi-device=%s --seconds=%s --vps=%s' % \
                (self.vg.vdev, rec_prog.filename, self.vg.vvbi, rec_prog.rec_duration, rec_prog.pdc_start)
        logger.debug('rec_command=%r', self.rec_command)

        self.thread.mode     = 'record'
        self.thread.prog     = rec_prog
        self.thread.command  = self.rec_command
        self.thread.autokill = float(rec_prog.rec_duration + 10)
        self.thread.mode_flag.set()


    def Stop(self):
        logger.log( 9, 'Stop()')
        self.thread.mode = 'stop'
        self.thread.mode_flag.set()
Example #29
0
    def run(self):
        _debug_('Record_Thread.run()', 2)
        while 1:
            _debug_('Record_Thread::run: mode=%s' % self.mode)
            if self.mode == 'idle':
                self.mode_flag.wait()
                self.mode_flag.clear()

            elif self.mode == 'record':
                try:
                    _debug_('Record_Thread::run: started recording', DINFO)

                    fc = FreevoChannels()
                    _debug_('Channel: %s' % (fc.getChannel()))

                    vg = fc.getVideoGroup(self.prog.tunerid, False)

                    _debug_('Opening device %r' % (vg.vdev))
                    v = tv.ivtv.IVTV(vg.vdev)

                    v.init_settings()

                    _debug_('Setting input to %r' % (vg.input_type))
                    v.setinputbyname(vg.input_type)

                    cur_std = v.getstd()
                    try:
                        new_std = V4L2.NORMS.get(vg.tuner_norm)
                        if cur_std != new_std:
                            _debug_('Setting standard to %s' % (new_std))
                            v.setstd(new_std)
                    except:
                        _debug_("Videogroup norm value '%s' not from NORMS: %s" % \
                            (vg.tuner_norm, V4L2.NORMS.keys()), DERROR)

                    _debug_('Setting channel to %r' % self.prog.tunerid)
                    fc.chanSet(str(self.prog.tunerid), False)

                    if vg.cmd != None:
                        _debug_("Running command %r" % vg.cmd)
                        retcode = os.system(vg.cmd)
                        _debug_("exit code: %g" % retcode)

                    now = time.time()
                    stop = now + self.prog.rec_duration

                    rc.post_event(Event('RECORD_START', arg=self.prog))
                    time.sleep(2)

                    v_in = open(vg.vdev, 'r')
                    v_out = open(self.prog.filename, 'w')

                    _debug_('Recording from %r to %r in %s byte chunks' %
                            (vg.vdev, self.prog.filename, CHUNKSIZE))
                    while time.time() < stop:
                        buf = v_in.read(CHUNKSIZE)
                        v_out.write(buf)
                        if self.mode == 'stop':
                            _debug_('Recording stopped', DINFO)
                            break

                    v_in.close()
                    v_out.close()
                    v.close()
                    v = None

                    self.mode = 'idle'

                    rc.post_event(Event('RECORD_STOP', arg=self.prog))
                    _debug_('Record_Thread::run: finished recording', DINFO)
                except Exception, why:
                    _debug_('%s' % (why), DCRITICAL)
                    return

            else:
                self.mode = 'idle'

            time.sleep(0.5)
Example #30
0
class TVTime:

    __muted    = 0
    __igainvol = 0

    def __init__(self):
        self.event_context = 'tv'
        self.fc = FreevoChannels()
        self.current_vg = None
        self.optionD_supported = False
        self.xmltv_supported = False

    def TunerSetChannel(self, tuner_channel):
        for pos in range(len(config.TV_CHANNELS)):
            channel = config.TV_CHANNELS[pos]
            if channel[2] == tuner_channel:
                return pos
        print 'ERROR: Cannot find tuner channel "%s" in the TV channel listing' % tuner_channel
        return 0

    def TunerGetChannelInfo(self):
        return self.fc.getChannelInfo()

    def TunerGetChannel(self):
        return self.fc.getChannel()

    def Play(self, mode, tuner_channel=None, channel_change=0):

        if not tuner_channel:
            tuner_channel = self.fc.getChannel()
        vg = self.current_vg = self.fc.getVideoGroup(tuner_channel, True)

        if not vg.group_type == 'normal':
            print 'Tvtime only supports normal. "%s" is not implemented' % vg.group_type
            return

        if mode == 'tv' or mode == 'vcr':

            w, h = config.TV_VIEW_SIZE
            cf_norm = vg.tuner_norm
            cf_input = vg.input_num
            cf_device = vg.vdev

            s_norm = cf_norm.upper()

            outputplugin = ''
            if plugin.getbyname(plugin.TV).optionD_supported:
                if config.CONF.display == 'x11':
                    outputplugin = 'Xv'
                elif config.CONF.display == 'mga':
                    outputplugin = 'mga'
                elif config.CONF.display in ( 'directfb', 'dfbmga' ):
                    outputplugin = 'directfb'
                else:
                    outputplugin = config.CONF.display
                outputplugin = '-D %s' % outputplugin

            if mode == 'vcr':
                cf_input = '1'
            if hasattr(config, "TV_VCR_INPUT_NUM") and config.TV_VCR_INPUT_NUM:
                cf_input = config.TV_VCR_INPUT_NUM

            self.fc.chan_index = self.TunerSetChannel(tuner_channel)

            if hasattr(config, 'TV_PAD_CHAN_NUMBERS') and config.TV_PAD_CHAN_NUMBERS:
                mychan = tuner_channel
            else:
                mychan = self.fc.chan_index

            logger.debug('starting channel is %s', mychan)

            command = '%s %s -k -I %s -n %s -d %s -f %s -c %s -i %s' % \
                (config.TVTIME_CMD, outputplugin, w, s_norm, cf_device, 'freevo', mychan, cf_input)

            if osd.get_fullscreen() == 1:
                command += ' -m'
            else:
                command += ' -M'


        else:
            print 'Mode "%s" is not implemented' % mode  # BUG ui.message()
            return

        self.mode = mode

        mixer = plugin.getbyname('MIXER')

        # BUG Mixer manipulation code.
        # TV is on line in
        # VCR is mic in
        # btaudio (different dsp device) will be added later
        if mixer and config.MIXER_MAJOR_CTRL == 'VOL':
            mixer_vol = mixer.getMainVolume()
            mixer.setMainVolume(0)
        elif mixer and config.MIXER_MAJOR_CTRL == 'PCM':
            mixer_vol = mixer.getPcmVolume()
            mixer.setPcmVolume(0)

        # Start up the TV task
        self.app=TVTimeApp(command)

        rc.add_app(self)

        # Suppress annoying audio clicks
        time.sleep(0.4)
        # BUG Hm.. This is hardcoded and very unflexible.
        if mixer and mode == 'vcr':
            mixer.setMicVolume(config.MIXER_VOLUME_VCR_IN)
        elif mixer:
            mixer.setLineinVolume(config.MIXER_VOLUME_TV_IN)
            mixer.setIgainVolume(config.MIXER_VOLUME_TV_IN)

        if mixer and config.MIXER_MAJOR_CTRL == 'VOL':
            mixer.setMainVolume(mixer_vol)
        elif mixer and config.MIXER_MAJOR_CTRL == 'PCM':
            mixer.setPcmVolume(mixer_vol)

        logger.debug('%s: started %s app', time.time(), self.mode)


    def Stop(self, channel_change=0):
        mixer = plugin.getbyname('MIXER')
        if mixer and not channel_change:
            mixer.setLineinVolume(0)
            mixer.setMicVolume(0)
            mixer.setIgainVolume(0) # Input on emu10k cards.

        self.app.stop('quit\n')
        rc.remove_app(self)

    def eventhandler(self, event, menuw=None):
        logger.debug('%s: %s app got %s event', time.time(), self.mode, event)
        if event == em.STOP or event == em.PLAY_END:
            self.Stop()
            rc.post_event(em.PLAY_END)
            return True

        elif event == em.TV_CHANNEL_UP or event == em.TV_CHANNEL_DOWN:
            if self.mode == 'vcr':
                return

            if event == em.TV_CHANNEL_UP:
                nextchan = self.fc.getNextChannel()
            elif event == em.TV_CHANNEL_DOWN:
                nextchan = self.fc.getPrevChannel()
            nextvg = self.fc.getVideoGroup(nextchan, True)
            logger.debug("nextchan is %s", nextchan)

            # XXX hazardous to your health. don't use tvtime with anything
            # other than one normal video_group.
            # we lose track of the channel index at some points and
            # chaos ensues
            #if self.current_vg != nextvg:
            #    self.Stop(channel_change=1)
            #    self.Play('tv', nextchan)
            #    return TRUE

            self.fc.chanSet(nextchan, True, app=self.app)
            #self.current_vg = self.fc.getVideoGroup(self.fc.getChannel(), True)

            # Go to the prev/next channel in the list
            if event == em.TV_CHANNEL_UP:
                self.app.write('CHANNEL_UP\n')
            else:
                self.app.write('CHANNEL_DOWN\n')

            return True

        elif event == em.TOGGLE_OSD:
            self.app.write('DISPLAY_INFO\n')
            return True

        elif event == em.OSD_MESSAGE:
            # XXX this doesn't work
            #self.app.write('display_message %s\n' % event.arg)
            #this does
            os.system('tvtime-command display_message \'%s\'' % event.arg)
            return True

        elif event == em.TV_SEND_TVTIME_CMD:
            os.system('tvtime-command %s' % event.arg)
            return True

        elif event in em.INPUT_ALL_NUMBERS:
            self.app.write('CHANNEL_%s\n' % event.arg)

        elif event == em.BUTTON:
            if event.arg == 'PREV_CH':
                self.app.write('CHANNEL_PREV\n')
                return True


        return False
Example #31
0
class TunerControl:
    """
    Class that controls the tuner device
    """
    def __init__(self, xine):
        """ TunerControl constructor """
        self.xine = xine
        self.ivtv_init = False
        self.fc = FreevoChannels()
        self.curr_channel = None
        self.embed = None
        self.stack = [ ]

    def _kill_(self):
        """ TunerControl destructor """
        if self.embed:
            ivtv_dev.setvbiembed(self.embed)

    def Stop(self):
        """ stop """
        self.ivtv_init = False

    def GetChannelName(self):
        """ get channel info """
        tuner_id, chan_name, prog_info = self.fc.getChannelInfo(showtime=False)
        return (chan_name)

    def GetProgramName(self):
        """ get channel name """
        tuner_id, chan_name, prog_info = self.fc.getChannelInfo(showtime=True)
        return prog_info

    def GetInfo(self):
        """ get channel info """
        tuner_id, chan_id, chan_name, start_t, stop_t, prog_s = self.fc.getChannelInfoRaw()
        return (start_t, stop_t, prog_s)

    def ShowInfo(self):
        """ show channel info """
        if self.curr_channel is not None:
            tuner_id, chan_name, prog_info = self.fc.getChannelInfo(showtime=False)
            self.xine.ShowMessage(msg = '%s: %s' % (chan_name, prog_info))

    def PushChannel(self):
        """ push the current channel on the channel stack """
        if self.curr_channel is not None:
            self.stack.append(self.curr_channel)
            logger.debug('TunerControl: Pushed channel %s', self.curr_channel)
        logger.debug('TunerControl: Channel stack = %s', self.stack)

    def UnpushChannel(self):
        """ remove the top channel from the channel stack """
        if len(self.stack) == 0:
            logger.debug('TunerControl: Channel stack is empty')
        else:
            channel = self.stack.pop()
            logger.debug('TunerControl: Unpushed channel %s', channel)
        logger.debug('TunerControl: Channel stack = %s', self.stack)

    def PopChannel(self):
        """ pop the top channel from the channel stack and switch channel """
        if len(self.stack) == 0:
            logger.debug('TunerControl: Channel stack is empty')
        else:
            channel = self.stack.pop()
            logger.debug('TunerControl: Popped channel %s', channel)
            self.SetVideoGroup(channel)
        logger.debug('TunerControl: Channel stack = %s', self.stack)

    def SwapChannel(self):
        """swap the current display channel and the top of the stack channel """
        if self.curr_channel is not None:
            toswap = self.curr_channel
            if len(self.stack) == 0:
                logger.debug('TunerControl: Channel stack is empty')
            else:
                channel = self.stack.pop()
                logger.debug('TunerControl: Popped channel %s', channel)
                self.SetVideoGroup(channel)
                self.stack.append(toswap)
                logger.debug('TunerControl: Pushed channel %s', toswap)
        logger.debug('TunerControl: Channel stack = %s', self.stack)


    def SetChannelByName(self, channel=None, clearstack=False):
        """ tune to a new channel by name """
        last_channel = self.curr_channel
        next_channel = None
        channel_index = -1

        if clearstack:
            self.stack = [ ]
            self.curr_channel = None

        if channel is None:
            # get a channel
            next_channel = self.fc.getChannel()

        try:
            # lookup the channel name in TV_CHANNELS
            for pos in range(len(config.TV_CHANNELS)):
                entry = config.TV_CHANNELS[pos]
                if str(channel) == str(entry[2]):
                    channel_index = pos
                    next_channel = channel
                    break
        except ValueError:
            pass

        if next_channel is None:
            logger.warning('TunerControl: Cannot find tuner channel %r in the TV channel listing', channel)
        else:
            self.SetChannelByIndex(channel_index + 1)

    def SetChannelByIndex(self, channel, tvlike=0):
        """ tune to a channel by index from the TV_CHANNELS list """
        next_channel = self.fc.getManChannel(channel, tvlike)
        logger.debug('TunerControl: Explicit channel selection by index = %r', next_channel)
        self.PushChannel()
        self.SetVideoGroup(next_channel)

    def SetChannelByNumber(self, channel):
        """ tune to a channel by actual channel number """
        logger.debug('TunerControl: Explicit channel selection by number = %r', channel)
        self.PushChannel()
        self.SetVideoGroup(channel)

    def NextChannel(self):
        """ jump to the next channel in the TV_CHANNELS list """
        next_channel = self.fc.getNextChannel()
        logger.debug('TunerControl: Next channel selection = %r', next_channel)
        self.PushChannel()
        self.SetVideoGroup(next_channel)

    def PrevChannel(self):
        """ jump to the previous channel in the TV_CHANNELS list """
        prev_channel = self.fc.getPrevChannel()
        logger.debug('TunerControl: Previous channel selection = %r', prev_channel)
        self.PushChannel()
        self.SetVideoGroup(prev_channel)

    def SetVideoGroup(self, channel):
        """ select a channel's video group and tune to that channel """
        try:
            channel_num = int(channel)
        except ValueError:
            channel_num = 0
        logger.debug('TunerControl: Channel: %r', channel)
        new_vg = self.fc.getVideoGroup(channel, True)
        logger.debug('TunerControl: Group: type=%r, desc=%r', new_vg.group_type, new_vg.desc)
        logger.debug('TunerControl: Input: type=%r, num=%r', new_vg.input_type, new_vg.input_num)

        if new_vg.group_type != 'ivtv':
            logger.error('TunerControl: VideoGroup %s is not supported', new_vg)
            pop = AlertBox(text=_('This plugin only supports the ivtv video group!'))
            pop.show()
            return

        # check if videogroup switch is needed
        switch_vg = not self.ivtv_init or self.curr_channel is None or \
                    new_vg != self.fc.getVideoGroup(self.curr_channel, True)

        if switch_vg:
            # switch to a different video group
            logger.info('TunerControl: Set VideoGroup: %s', new_vg)
            ivtv_dev = ivtv.IVTV(new_vg.vdev)
            ivtv_dev.init_settings()
            self.xine.SetInput(new_vg.input_num)
            # disable embedded vbi data
            self.embed = ivtv_dev.getvbiembed()
            ivtv_dev.setvbiembed(0)

        if not self.ivtv_init:
            # set channel directly on v4l device, if channel is not negative
            if channel_num >= 0:
                self.fc.chanSet(channel, True)
            self.curr_channel = channel
            self.ivtv_init = True
        else:
            # set channel through xine process
            freq = self.fc.chanSet(channel, True, 'ivtv_xine_tv', None)

            if freq != 0:
                # channel has frequency
                logger.debug('TunerControl: Set frequency: %s', freq)
                self.xine.SetFrequency(freq)
            else:
                # channel has no frequency
                logger.debug('TunerControl: Channel has no frequency')

            self.curr_channel = channel
            self.xine.SeekEnd()
            self.ShowInfo()

        self.SetAudioByChannel(channel)

    def SetAudioByChannel(self, channel=-1):
        """
        Set the PVR sound level
        This is a mix : The base volume is set by the avol
        option in each TV_VIDEO_GROUP. The value is hardware dependant.
        seems bo be between 0 and 65535.
        If this value is missing in the tv_video_group, that sub does nothing
        If the value is present, the actual audio value is this value
        time the 6th field in TV_CHANNELS (expressed in % )
        """
        try:
            # lookup the channel name in TV_CHANNELS
            for pos in range(len(config.TV_CHANNELS)):
                entry = config.TV_CHANNELS[pos]
                if str(channel) == str(entry[2]):
                    channel_index = pos
                    break
        except ValueError:
            pass

        logger.debug('SetAudioByChannel: Channel: %r TV_CHANNEL pos(%d)', channel, channel_index)
        vg = self.fc.getVideoGroup(channel, True)
        try:
            ivtv_avol = vg.avol
        except AttributeError:
            ivtv_avol = 0
        if ivtv_avol <= 0:
            logger.debug('SetAudioByChannel: The tv_video group for %r doesn\'t set the volume', channel)
        else:
            # Is there a specific volume level in TV_CHANNELS_VOLUME
            ivtv_dev = ivtv.IVTV(vg.vdev)
            avol_percent = 100
            try:
                # lookup the channel name in TV_CHANNELS
                for pos in range(len(config.TV_CHANNELS_VOLUME)):
                    if config.TV_CHANNELS_VOLUME[pos][0] == config.TV_CHANNELS[channel_index][0]:
                        avol_percent = config.TV_CHANNELS_VOLUME[pos][1]
                        break
            except:
                pass

            try:
                avol_percent = int(avol_percent)
            except ValueError:
                avol_percent = 100

            avol = int(ivtv_avol * avol_percent / 100)
            if avol > 65535:
                avol = 65535
            if avol < 0:
                avol = 0
            logger.debug('SetAudioByChannel: Current PVR Sound level is : %s', ivtv_dev.getctrl(0x00980905))
            logger.debug('SetAudioByChannel: Set the PVR Sound Level to : %s (%s * %s)', avol, ivtv_avol, avol_percent)
            ivtv_dev.setctrl(0x00980905, avol)
            logger.debug('SetAudioByChannel: New PVR Sound level is : %s', ivtv_dev.getctrl(0x00980905))
Example #32
0
class Xine:
    """
    the main class to control xine
    """
    def __init__(self, type, version, manager, path, size):
        self.name = 'xine'
        self.app_mode = 'tv'
        self.xine_type = type
        self.version = version
        self.app = None
        self.adapter_in_use = -1
        self.fc = FreevoChannels()
        self.path = path
        self.size = size
        self.buffer = ring_buffer.RingBuffer(size, path)
        self.last_channel = None
        self.subtitles = False
        self.paused = False
        self.stop_time = 0
        self.state = STATE_IDLE
        self.manager = manager
        self.udp_receiver = UDPReceiver(self.buffer, WAIT_FOR_DATA_TIMEOUT)
        self.slave_server = SlaveServer(self.buffer, self)

        # Create the command used to start xine.
        # NOTE: We add the slave server MRL twice so that we can toggle between
        # them, this allows use to effectively reset Xine rendering pipeline and
        # make it possible to seek quickly.
        self.command = [ '--prio=%s' % config.MPLAYER_NICE ] + \
                       config.XINE_COMMAND.split(' ') + \
                       [ '--stdctl',
                         '-V', config.XINE_VO_DEV,
                         '-A', config.XINE_AO_DEV ] + \
                       config.XINE_ARGS_DEF.split(' ') + \
                       [self.slave_server.get_xine_mrl(),
                        self.slave_server.get_xine_mrl()]

        if not rc.PYLIRC and '--no-lirc' in self.command:
            self.command.remove('--no-lirc')

        self.udp_receiver.start()
        self.slave_server.start()

    def Play(self, mode, tuner_channel=None):
        """
        play with xine
        """
        if not tuner_channel:
            tuner_channel = self.fc.getChannel()

        if plugin.getbyname('MIXER'):
            plugin.getbyname('MIXER').reset()

        rc.app(self)

        same_channel = self.last_channel == tuner_channel

        # If it's the same channel as last time and we have come back to it after
        # more than 2 minutes start at the end of the buffer, otherwise jump
        # straight back in where we left off.
        if same_channel:
            if (time.time() - self.stop_time) > 120.0:
                start_at_end = True
            else:
                start_at_end = False
        else:
            self.change_channel(tuner_channel)
            start_at_end = True

        if start_at_end:
            self.start_slave_server_at_end = True
            if same_channel:

                self.__change_state(STATE_PLAYING)
        else:
            self.__change_state(STATE_PLAYING)

        return None

    def stop(self, channel_change=False):
        """
        Stop xine
        """
        if self.app:
            self.app.stop('quit\n')
            self.app = None

            if not channel_change:
                self.stop_time = time.time()
                self.__change_state(STATE_IDLE)

    def disable_buffering(self):
        """
        Stop buffering the current channel.
        """
        if self.adapter_in_use != -1:
            self.time = 0
            self.last_channel = None
            try:
                self.manager.disable_output(self.adapter_in_use)
            except:
                _debug_('Failed to disable output! ' + traceback.format_exc())
            self.adapter_in_use = -1

    def pause(self):
        """
        Pause Playback.
        """
        if self.app and not self.paused:
            _debug_('Pausing')
            self.app.write('pause\n')
            self.paused = True

    def resume(self):
        """
        Resume Playback.
        """
        if self.app and self.paused:
            _debug_('Resuming')
            self.app.write('pause\n')
            self.paused = False

    def shutdown(self):
        """
        Stop the UDP receiver and slave server.
        """
        if self.udp_receiver:
            self.udp_receiver.stop()
            self.udp_receiver = None

        if self.slave_server:
            self.slave_server.stop()
            self.slave_server = None

    def change_channel(self, channel):
        """
        Select the correct dvbstreamer instance, change the channel
        and set the primary mrl.
        """

        if self.last_channel == channel:
            # Already tune to this channel so nothing to do!
            return

        adapter = eval(self.fc.getVideoGroup(channel, True).vdev)

        if (self.adapter_in_use != -1) and (self.adapter_in_use != adapter):
            try:
                self.manager.disable_output(self.adapter_in_use)
            except:
                _debug_('Failed to disable output! ' + traceback.format_exc())

        # We are tuning to a different channel so stop receiving packets and
        # reset the ring buffer
        self.udp_receiver.pause = True
        self.buffer.rwlock.acquire_write()
        self.buffer.reset()

        self.manager.select(adapter, channel)

        if self.adapter_in_use != adapter:
            self.adapter_in_use = adapter
            try:
                if adapter.find(':') != -1:
                    my_ip = self.manager.controllers[adapter].my_ip
                else:
                    my_ip = 'localhost'

                self.manager.enable_udp_output(self.adapter_in_use, my_ip,
                                               1234)
            except:
                _debug_('Failed to enable output! ' + traceback.format_exc())

        # Start receiving packets and remember the channel we've just tuned to.
        self.udp_receiver.reset()
        self.udp_receiver.send_events = True
        self.udp_receiver.pause = False
        self.buffer.rwlock.release()
        self.last_channel = channel

        self.__change_state(STATE_TUNING)

    def eventhandler(self, event, menuw=None):
        """
        Eventhandler for xine control. If an event is not bound in this
        function it will be passed over to the items eventhandler
        """
        event_consumed = False

        if self.state == STATE_IDLE:
            event_consumed = self.__eventhandler_idle(event, menuw)
        elif self.state == STATE_TUNING:
            event_consumed = self.__eventhandler_tuning(event, menuw)
        elif self.state == STATE_BUFFERING:
            event_consumed = self.__eventhandler_buffering(event, menuw)
        elif self.state == STATE_PLAYING:
            event_consumed = self.__eventhandler_playing(event, menuw)

        if not event_consumed:
            _debug_('Unused event %s in state %s' % (event.name, self.state))

        return event_consumed

    def __eventhandler_idle(self, event, menuw):
        """
        Internal event handler when in Idle state.
        """
        return False

    def __eventhandler_tuning(self, event, menuw):
        """
        Internal event handler when in Tuning state.
        """
        if event == EVENT_DATA_STARTED:
            self.__change_state(STATE_BUFFERING)
            return True

        if event == EVENT_DATA_TIMEDOUT:
            # Timeout while waiting for data!
            # We could display a searching for signal graphic or something here
            self.__change_state(STATE_IDLE)
            return True

        return False

    def __eventhandler_buffering(self, event, menuw):
        """
        Internal event handler when in Buffering state.
        """
        if event == EVENT_DATA_ACQUIRED:
            self.wait_for_data_count -= 1
            self.__draw_state_screen()
            if self.wait_for_data_count <= 0:
                self.__change_state(STATE_PLAYING)
            return True

        if event == EVENT_DATA_TIMEDOUT:
            # Timeout while waiting for data!
            # We could display a searching for signal graphic or something here
            self.__change_state(STATE_IDLE)
            return True

        return False

    def __eventhandler_playing(self, event, menuw):
        """
        Internal event handler when in Playing state.
        """
        if event == PAUSE or event == PLAY:
            if self.paused:
                self.resume()
            else:
                self.pause()
            return True

        if event in (PLAY_END, USER_END, STOP):
            self.stop()
            return True

        if event in [
                TV_CHANNEL_UP, TV_CHANNEL_DOWN
        ] or (str(event).startswith('INPUT_') and str(event)[6:].isdigit()):
            _debug_('Event: %s' % str(event))
            if event == TV_CHANNEL_UP:
                nextchan = self.fc.getNextChannel()
            elif event == TV_CHANNEL_DOWN:
                nextchan = self.fc.getPrevChannel()
            else:
                nextchan = self.fc.getManChannel(int(event.arg))

            self.stop(True)

            self.change_channel(nextchan)  # Moves to the Tuning state
            return True

        if (event == BUTTON) and (event.arg == 'SUBTITLE'):
            # Enable/Disable subtitles
            if self.subtitles:
                cmd = 'SpuPrior\n'
            else:
                cmd = 'SpuNext\n'
            self.app.write(cmd)
            self.subtitles = not self.subtitles
            return True
        if event == OSD_MESSAGE:
            self.__osd_write(event.arg)
            return True
        if event == TOGGLE_OSD:
            # Write percent through ringbuffer to OSD
            channel = self.__get_display_channel()
            percent = self.slave_server.get_percent()

            self.__osd_write('%s - %d%%' % (channel, percent))

            return True

        if event == VIDEO_TOGGLE_INTERLACE:
            self.app.write('ToggleInterleave\n')
            return True

        if event == SEEK:
            steps = int(event.arg)
            self.buffer.rwlock.acquire_write()
            bytes_per_sec = self.udp_receiver.average_pps * 188
            if steps > 0:
                can_seek = self.slave_server.reader.available_forward() >= (
                    (steps + 1) * bytes_per_sec)
            else:
                can_seek = self.slave_server.reader.available_backward() > 0

            if can_seek:
                self.slave_server.reader.seek(steps * bytes_per_sec)
                if self.mrl_index == 0:
                    self.mrl_index = 1
                    self.app.write('NextMrl\n')
                else:
                    self.mrl_index = 0
                    self.app.write('PriorMrl\n')
            self.buffer.rwlock.release()
            return True

        if event == EVENT_READER_OVERTAKEN:
            if self.paused:
                self.resume()
            return True

        # Consume UDP Receiver events.
        if event in (EVENT_DATA_ACQUIRED, EVENT_DATA_TIMEDOUT):
            return True

        return False

    def __change_state(self, new_state):
        """
        Internal function to move to a new state.
        If new_state is different to the current state, set self.state to
        new_state and perform any state initialisation for the new state.
        """
        if self.state == new_state:
            # No change in state nothing todo!
            return

        _debug_('Changing state from %s to %s' % (self.state, new_state))
        self.state = new_state

        # State Initialisation code

        if self.state == STATE_IDLE:
            rc.app(None)
            rc.post_event(PLAY_END)
            self.udp_receiver.send_events = False

        elif self.state == STATE_TUNING:
            self.start_slave_server_at_end = True

        elif self.state == STATE_BUFFERING:
            self.wait_for_data_count = WAIT_FOR_DATA_COUNT

        elif self.state == STATE_PLAYING:
            self.slave_server.reader_at_end = self.start_slave_server_at_end
            self.slave_server.end_offset = self.udp_receiver.average_pps * WAIT_FOR_DATA_COUNT * 188
            self.mrl_index = 0
            self.app = childapp.ChildApp2(self.command)
            self.start_slave_server_at_end = False
        self.__draw_state_screen()

    def __osd_write(self, text):
        if self.app:
            self.app.write('OSDWriteText$    %s\n' % text)

    def __draw_state_screen(self):
        osd_obj = osd.get_singleton()
        percent = 0.0

        channel = self.__get_display_channel()

        if self.state == STATE_IDLE:
            state_string = None

        elif self.state == STATE_TUNING:
            state_string = _('Tuning to %s' % self.last_channel)

        elif self.state == STATE_BUFFERING:
            state_string = _('Buffering %s' % self.last_channel)
            percent = float(WAIT_FOR_DATA_COUNT - self.wait_for_data_count
                            ) / float(WAIT_FOR_DATA_COUNT)

        elif self.state == STATE_PLAYING:
            state_string = _('Playing %s' % self.last_channel)
            percent = 1.0

        osd_obj.clearscreen(color=osd_obj.COL_BLACK)
        if state_string:
            y = (config.CONF.height / 2) - config.OSD_DEFAULT_FONTSIZE
            h = -1
            font = osd_obj.getfont(config.OSD_DEFAULT_FONTNAME,
                                   config.OSD_DEFAULT_FONTSIZE)
            osd_obj.drawstringframed(state_string,
                                     0,
                                     y,
                                     config.CONF.width,
                                     h,
                                     font,
                                     fgcolor=osd_obj.COL_ORANGE,
                                     align_h='center')
            x = config.CONF.width / 4
            w = x * 2
            y = (config.CONF.height / 2) + config.OSD_DEFAULT_FONTSIZE
            h = int(20.0 * (float(config.CONF.height) / 600.0))
            osd_obj.drawbox(x - 2,
                            y - 2,
                            x + w + 2,
                            y + h + 2,
                            color=osd_obj.COL_ORANGE)
            w = int(float(w) * percent)
            osd_obj.drawbox(x,
                            y,
                            x + w,
                            y + h,
                            color=osd_obj.COL_ORANGE,
                            fill=1)

        osd_obj.update()

    def __get_display_channel(self):
        channel = self.last_channel

        for tv_channel_id, tv_display_name, tv_tuner_id in config.TV_CHANNELS:
            if self.last_channel == tv_tuner_id:
                channel = tv_display_name

        return channel
Example #33
0
class MPlayer:
    __muted = 0
    __igainvol = 0

    def __init__(self):
        self.tuner_chidx = 0  # Current channel, index into config.TV_CHANNELS
        self.event_context = 'tv'
        self.fc = FreevoChannels()
        self.current_vg = None

    def Play(self, mode, tuner_channel=None):
        """ """
        logger.log(9, 'MPlayer.Play(mode=%r, tuner_channel=%r)', mode,
                   tuner_channel)
        # Try to see if the channel is not tunable
        try:
            channel = int(tuner_channel)
        except ValueError:
            channel = 0

        vg = self.current_vg = self.fc.getVideoGroup(tuner_channel, True)

        if not tuner_channel:
            tuner_channel = self.fc.getChannel()

        # Convert to MPlayer TV setting strings
        device = 'device=%s' % vg.vdev
        input = 'input=%s' % vg.input_num
        norm = 'norm=%s' % vg.tuner_norm

        w, h = config.TV_VIEW_SIZE
        outfmt = 'outfmt=%s' % config.TV_VIEW_OUTFMT

        # Build the MPlayer command line
        args = {
            'nice':
            config.MPLAYER_NICE,
            'cmd':
            config.MPLAYER_CMD,
            'vo':
            '-vo %s' % config.MPLAYER_VO_DEV,
            'vo_opts':
            config.MPLAYER_VO_DEV_OPTS,
            'vc':
            '',
            'ao':
            '-ao %s' % config.MPLAYER_AO_DEV,
            'ao_opts':
            config.MPLAYER_AO_DEV_OPTS,
            'default_args':
            config.MPLAYER_ARGS_DEF.split(),
            'mode_args':
            config.MPLAYER_ARGS.has_key(mode)
            and config.MPLAYER_ARGS[mode].split() or [],
            'geometry':
            (config.CONF.x or config.CONF.y) and '-geometry %d:%d' %
            (config.CONF.x, config.CONF.y) or '',
            'verbose':
            '',
            'dvd-device':
            '',
            'cdrom-device':
            '',
            'alang':
            '',
            'aid':
            '',
            'slang':
            '',
            'sid':
            '',
            'playlist':
            '',
            'field-dominance':
            '',
            'edl':
            '',
            'mc':
            '',
            'delay':
            '',
            'sub':
            '',
            'audiofile':
            '',
            'af': [],
            'vf': [],
            'tv':
            '',
            'url':
            '',
            'disable_osd':
            False,
        }

        if dialog.overlay_display_supports_dialogs:
            # Disable the mplayer OSD if we have a better option.
            args['disable_osd'] = True

        if mode == 'tv':
            if vg.group_type == 'ivtv':
                ivtv_dev = ivtv.IVTV(vg.vdev)
                ivtv_dev.init_settings()
                ivtv_dev.setinputbyname(vg.input_type)
                cur_std = ivtv_dev.getstd()
                import tv.v4l2
                try:
                    new_std = tv.v4l2.NORMS.get(vg.tuner_norm)
                    if cur_std != new_std:
                        ivtv_dev.setstd(new_std)
                except:
                    logger.error(
                        'Error! Videogroup norm value "%s" not from NORMS: %s',
                        vg.tuner_norm, tv.v4l2.NORMS.keys())

                ivtv_dev.close()

                # Do not set the channel if negative
                if channel >= 0:
                    self.fc.chanSet(tuner_channel, True)

                args['url'] = vg.vdev

                if config.MPLAYER_ARGS.has_key('ivtv'):
                    args['mode_args'] = config.MPLAYER_ARGS['ivtv'].split()

            elif vg.group_type == 'webcam':
                self.fc.chanSet(tuner_channel, True, app='mplayer')
                args['url'] = ''

                if config.MPLAYER_ARGS.has_key('webcam'):
                    args['mode_args'] = config.MPLAYER_ARGS['webcam'].split()

            elif vg.group_type == 'dvb':
                self.fc.chanSet(tuner_channel, True, app='mplayer')
                args['url'] = ('dvb://%s' % (tuner_channel, ))
                args['mode_args'] = config.MPLAYER_ARGS['dvb'].split()

            elif vg.group_type == 'tvalsa':
                freq_khz = self.fc.chanSet(tuner_channel, True, app='mplayer')
                tuner_freq = '%1.3f' % (freq_khz / 1000.0)

                args['tv'] = '-tv driver=%s:%s:freq=%s:%s:%s:%s:width=%s:height=%s:%s %s' % \
                    (config.TV_DRIVER, vg.adev, tuner_freq, device, input, norm, w, h, outfmt, config.TV_OPTS)
                args['url'] = 'tv://'

                if config.MPLAYER_ARGS.has_key('tv'):
                    args['mode_args'] = config.MPLAYER_ARGS['tv'].split()

            else:  # group_type == 'normal'
                freq_khz = self.fc.chanSet(tuner_channel, True, app='mplayer')
                tuner_freq = '%1.3f' % (freq_khz / 1000.0)

                args['tv'] = '-tv driver=%s:freq=%s:%s:%s:%s:width=%s:height=%s:%s %s' % \
                    (config.TV_DRIVER, tuner_freq, device, input, norm, w, h, outfmt, config.TV_OPTS)
                args['url'] = 'tv://'

                if config.MPLAYER_ARGS.has_key('tv'):
                    args['mode_args'] = config.MPLAYER_ARGS['tv'].split()

        elif mode == 'vcr':
            args['tv'] = '-tv driver=%s:%s:%s:%s:width=%s:height=%s:%s %s' % \
                (config.TV_DRIVER, device, input, norm, w, h, outfmt, config.TV_OPTS)
            args['url'] = 'tv://'

            if config.MPLAYER_ARGS.has_key('tv'):
                args['mode_args'] = config.MPLAYER_ARGS['tv'].split()

        else:
            logger.error('Mode "%s" is not implemented', mode)
            return

        logger.debug('mplayer args = %r', args)

        vo = ['%(vo)s' % args, '%(vo_opts)s' % args]
        vo = filter(len, vo)
        vo = ':'.join(vo)

        ao = ['%(ao)s' % args, '%(ao_opts)s' % args]
        ao = filter(len, ao)
        ao = ':'.join(ao)

        command = ['--prio=%(nice)s' % args]
        command += ['%(cmd)s' % args]
        command += ['-slave']
        command += str('%(verbose)s' % args).split()
        command += str('%(geometry)s' % args).split()
        command += vo.split()
        command += str('%(vc)s' % args).split()
        command += ao.split()
        command += args['default_args']
        command += args['mode_args']
        command += str('%(dvd-device)s' % args).split()
        command += str('%(cdrom-device)s' % args).split()
        command += str('%(alang)s' % args).split()
        command += str('%(aid)s' % args).split()
        command += str('%(audiofile)s' % args).split()
        command += str('%(slang)s' % args).split()
        command += str('%(sid)s' % args).split()
        command += str('%(sub)s' % args).split()
        command += str('%(field-dominance)s' % args).split()
        command += str('%(edl)s' % args).split()
        command += str('%(mc)s' % args).split()
        command += str('%(delay)s' % args).split()
        if args['af']:
            command += ['-af', '%s' % ','.join(args['af'])]
        if args['vf']:
            command += ['-vf', '%s' % ','.join(args['vf'])]
        command += str('%(tv)s' % args).split()
        command += args['disable_osd'] and ['-osdlevel', '0'] or []

        if config.OSD_SINGLE_WINDOW:
            command += ['-wid', str(osd.video_window.id)]
            osd.video_window.show()

        # use software scaler?
        if '-nosws' in command:
            command.remove('-nosws')
        elif '-framedrop' not in command:
            command += config.MPLAYER_SOFTWARE_SCALER.split()

        #if options:
        #    command += options

        command = filter(len, command)

        #command = self.sort_filter(command)

        url = '%(url)s' % args
        command += [url]

        logger.debug('%r', command)

        self.mode = mode

        # XXX Mixer manipulation code.
        # TV is on line in
        # VCR is mic in
        # btaudio (different dsp device) will be added later
        mixer = plugin.getbyname('MIXER')

        if mixer and config.MIXER_MAJOR_CTRL == 'VOL':
            mixer_vol = mixer.getMainVolume()
            mixer.setMainVolume(0)
        elif mixer and config.MIXER_MAJOR_CTRL == 'PCM':
            mixer_vol = mixer.getPcmVolume()
            mixer.setPcmVolume(0)

        # Start up the TV task
        self.app = childapp.ChildApp2(command)

        rc.add_app(self)

        # Suppress annoying audio clicks
        time.sleep(0.4)
        # XXX Hm.. This is hardcoded and very unflexible.
        if mixer and mode == 'vcr':
            mixer.setMicVolume(config.MIXER_VOLUME_VCR_IN)
        elif mixer:
            mixer.setLineinVolume(config.MIXER_VOLUME_TV_IN)
            mixer.setIgainVolume(config.MIXER_VOLUME_TV_IN)

        if mixer and config.MIXER_MAJOR_CTRL == 'VOL':
            mixer.setMainVolume(mixer_vol)
        elif mixer and config.MIXER_MAJOR_CTRL == 'PCM':
            mixer.setPcmVolume(mixer_vol)

        dialog.enable_overlay_display(AppTextDisplay(self.show_message))
        logger.debug('%s: started %s app', time.time(), self.mode)

    def Stop(self, channel_change=0):
        mixer = plugin.getbyname('MIXER')
        if mixer and not channel_change:
            mixer.setLineinVolume(0)
            mixer.setMicVolume(0)
            mixer.setIgainVolume(0)  # Input on emu10k cards.

        if config.OSD_SINGLE_WINDOW:
            osd.video_window.hide()

        self.app.stop('quit\n')

        rc.remove_app(self)

        if os.path.exists('/tmp/freevo.wid'): os.unlink('/tmp/freevo.wid')

        if config.MPLAYER_OLDTVCHANNELCHANGE:
            lastchanfile = os.path.join(config.FREEVO_CACHEDIR, 'lastchan')
            lcfp = open(lastchanfile, "w")
            lastchan = self.fc.getChannel()
            lastchannum = self.fc.getChannelNum()
            lcfp.write(str(lastchan))
            lcfp.write('\n')
            lcfp.write(str(lastchannum))
            lcfp.write('\n')
            lcfp.close()

        dialog.disable_overlay_display()

    def eventhandler(self, event, menuw=None):
        s_event = '%s' % event

        if event == em.STOP or event == em.PLAY_END:
            self.Stop()
            rc.post_event(em.PLAY_END)
            return True

        elif event == em.PAUSE or event == em.PLAY:
            self.app.write('pause\n')
            logger.debug('%s: sending pause to mplayer', time.time())
            return True

        elif event in [
                em.TV_CHANNEL_UP, em.TV_CHANNEL_DOWN, em.TV_CHANNEL_LAST
        ] or s_event.startswith('INPUT_'):
            chan = None
            if event == em.TV_CHANNEL_UP:
                nextchan = self.fc.getNextChannel()
                nextchannum = self.fc.getNextChannelNum()
            elif event == em.TV_CHANNEL_DOWN:
                nextchan = self.fc.getPrevChannel()
                nextchannum = self.fc.getPrevChannelNum()
            elif event == em.TV_CHANNEL_LAST:
                if config.MPLAYER_OLDTVCHANNELCHANGE:
                    if os.path.isfile(
                            os.path.join(config.FREEVO_CACHEDIR, 'lastchan')):
                        lastchanfile = os.path.join(config.FREEVO_CACHEDIR,
                                                    'lastchan')
                        lcfp = open(lastchanfile, "r")
                        nextchan = lcfp.readline()
                        nextchan = nextchan.strip()
                        nextchannum = lcfp.readline()
                        nextchannum = nextchannum.strip()
                        nextchannum = int(nextchannum)
                        lcfp.close()
                    else:
                        nextchan = self.fc.getChannel()
                        nextchannum = self.fc.getChannelNum()
                else:
                    return True
            else:
                chan = int(s_event[6])
                nextchan = self.fc.getManChannel(chan)
                nextchannum = self.fc.getManChannelNum(chan)

            nextvg = self.fc.getVideoGroup(nextchan, True)
            logger.debug('chan=%s, nextchannum=%s, nextchan=%s nextvg=%s',
                         chan, nextchannum, nextchan, nextvg)

            if self.current_vg != nextvg:
                self.Stop(channel_change=1)
                self.Play('tv', nextchan)
                return True

            if self.mode == 'vcr':
                return

            elif self.current_vg.group_type == 'dvb':
                if not config.MPLAYER_OLDTVCHANNELCHANGE:
                    card = 0  # May be this should come from video groups or TV_CHANNELS
                    if em.TV_CHANNEL_UP:
                        self.app.write('dvb_set_channel %s %s\n' %
                                       (nextchannum, card))
                        self.fc.chanSet(nextchan, True)
                    elif em.TV_CHANNEL_DOWN:
                        self.app.write('dvb_set_channel %s %s\n' %
                                       (nextchannum, card))
                        self.fc.chanSet(nextchan, True)
                else:
                    self.Stop(channel_change=1)
                    self.Play('tv', nextchan)
                return True

            elif self.current_vg.group_type == 'ivtv':
                self.fc.chanSet(nextchan, True)
                self.app.write('seek 999999 0\n')

            else:
                freq_khz = self.fc.chanSet(nextchan, True, app=self.app)
                new_freq = '%1.3f' % (freq_khz / 1000.0)
                self.app.write('tv_set_freq %s\n' % new_freq)

            self.current_vg = self.fc.getVideoGroup(self.fc.getChannel(), True)

            # Display a channel changed message
            tuner_id, chan_name, prog_info = self.fc.getChannelInfo()
            now = time.strftime(config.TV_TIME_FORMAT)
            msg = '%s %s (%s): %s' % (now, chan_name, tuner_id, prog_info)
            cmd = 'osd_show_text "%s"\n' % msg
            self.app.write(cmd)
            return True

        elif event == em.TOGGLE_OSD:
            if dialog.is_dialog_supported():
                dialog.show_play_state(dialog.PLAY_STATE_INFO, self.fc)
            else:
                # Display the channel info message
                tuner_id, chan_name, prog_info = self.fc.getChannelInfo()
                now = time.strftime(config.TV_TIME_FORMAT)
                msg = '%s %s (%s): %s' % (now, chan_name, tuner_id, prog_info)
                cmd = 'osd_show_text "%s"\n' % msg
                self.app.write(cmd)
                return False

        elif event == em.OSD_MESSAGE:
            self.app.write('osd_show_text "%s"\n' % event.arg)
            return True

        elif event == em.TV_SEND_MPLAYER_CMD:
            self.app.write('%s\n' % event.arg)
            return True

        return False

    def show_message(self, message):
        self.app.write('osd_show_text "%s"\n' % message)
Example #34
0
class TunerControl:
    """
    Class that controls the tuner device
    """
    def __init__(self):

        self.ivtv_init = False
        self.fc = FreevoChannels()
        self.curr_channel = None
        self.embed = None
        self.stack = []

    def _kill_(self):

        if self.embed:

            ivtv_dev.setvbiembed(self.embed)

    def PushChannel(self):

        if self.curr_channel != None:

            self.stack.append(self.curr_channel)
            _debug_("TunerControl: Pushed channel %s" % self.curr_channel)

        _debug_("TunerControl: Channel stack = %s" % self.stack)

    def UnpushChannel(self):

        if len(self.stack) == 0:

            _debug_("TunerControl: Channel stack is empty")

        else:

            channel = self.stack.pop()
            _debug_("TunerControl: Unpushed channel %s" % channel)

        _debug_("TunerControl: Channel stack = %s" % self.stack)

    def PopChannel(self):

        if len(self.stack) == 0:

            _debug_("TunerControl: Channel stack is empty")

        else:

            channel = self.stack.pop()
            _debug_("TunerControl: Popped channel %s" % channel)

            self.SetVideoGroup(channel)

        _debug_("TunerControl: Channel stack = %s" % self.stack)

    def SetChannel(self, channel=None, clearstack=False):

        # set channel by name

        last_channel = self.curr_channel
        next_channel = None
        channel_index = -1

        if clearstack == True:

            self.stack = []
            self.curr_channel = None

        if channel == None:

            # get a channel
            next_channel = self.fc.getChannel()

        try:

            # lookup the channel name in TV_CHANNELS

            for pos in range(len(config.TV_CHANNELS)):

                entry = config.TV_CHANNELS[pos]

                if channel == entry[2]:

                    channel_index = pos
                    next_channel = channel

                    break

        except ValueError:

            pass

        if (next_channel == None):

            _debug_(
                "TunerControl: Cannot find tuner channel '%s' in the TV channel listing"
                % channel)

        else:

            self.TuneChannelByIndex(channel_index + 1)

    def TuneChannelByIndex(self, channel):

        # tune channel by index

        next_channel = self.fc.getManChannel(channel)
        _debug_("TunerControl: Explicit channel selection = '%s'" %
                next_channel)

        self.PushChannel()
        self.SetVideoGroup(next_channel)

    def TuneChannelByNumber(self, channel):

        # tune channel by number

        self.PushChannel()
        self.SetVideoGroup(str(channel))

    def NextChannel(self):

        next_channel = self.fc.getNextChannel()
        _debug_("TunerControl: Next channel selection = '%s'" % next_channel)

        self.PushChannel()
        self.SetVideoGroup(next_channel)

    def PrevChannel(self):

        prev_channel = self.fc.getPrevChannel()
        _debug_("TunerControl: Previous channel selection = '%s'" %
                prev_channel)

        self.PushChannel()
        self.SetVideoGroup(prev_channel)

    def SetVideoGroup(self, channel):

        _debug_("TunerControl: Play channel = '%s'" % channel)
        vg = self.fc.getVideoGroup(channel, True)
        _debug_("TunerControl: Play group = '%s'" % vg.desc)

        if (vg.group_type != "ivtv"):

            _debug_("TunerControl: Video group '%s' is not supported" %
                    vg.group_type)
            pop = AlertBox(text=_(
                "This plugin only supports the ivtv video group in tv mode!"))
            pop.show()
            return

        if self.ivtv_init == False:

            ivtv_dev = ivtv.IVTV(vg.vdev)
            ivtv_dev.init_settings()
            ivtv_dev.setinput(vg.input_num)
            ivtv_dev.print_settings()

            # disable embedded vbi data
            self.embed = ivtv_dev.getvbiembed()
            ivtv_dev.setvbiembed(0)

            self.ivtv_init = True

        self.fc.chanSet(channel, True)
        self.curr_channel = channel
Example #35
0
class TVTime:

    __muted = 0
    __igainvol = 0

    def __init__(self):
        self.event_context = 'tv'
        self.fc = FreevoChannels()
        self.current_vg = None
        self.optionD_supported = False
        self.xmltv_supported = False

    def TunerSetChannel(self, tuner_channel):
        for pos in range(len(config.TV_CHANNELS)):
            channel = config.TV_CHANNELS[pos]
            if channel[2] == tuner_channel:
                return pos
        print 'ERROR: Cannot find tuner channel "%s" in the TV channel listing' % tuner_channel
        return 0

    def TunerGetChannelInfo(self):
        return self.fc.getChannelInfo()

    def TunerGetChannel(self):
        return self.fc.getChannel()

    def Play(self, mode, tuner_channel=None, channel_change=0):

        if not tuner_channel:
            tuner_channel = self.fc.getChannel()
        vg = self.current_vg = self.fc.getVideoGroup(tuner_channel, True)

        if not vg.group_type == 'normal':
            print 'Tvtime only supports normal. "%s" is not implemented' % vg.group_type
            return

        if mode == 'tv' or mode == 'vcr':

            w, h = config.TV_VIEW_SIZE
            cf_norm = vg.tuner_norm
            cf_input = vg.input_num
            cf_device = vg.vdev

            s_norm = cf_norm.upper()

            outputplugin = ''
            if plugin.getbyname(plugin.TV).optionD_supported:
                if config.CONF.display == 'x11':
                    outputplugin = 'Xv'
                elif config.CONF.display == 'mga':
                    outputplugin = 'mga'
                elif config.CONF.display in ('directfb', 'dfbmga'):
                    outputplugin = 'directfb'
                else:
                    outputplugin = config.CONF.display
                outputplugin = '-D %s' % outputplugin

            if mode == 'vcr':
                cf_input = '1'
            if hasattr(config, "TV_VCR_INPUT_NUM") and config.TV_VCR_INPUT_NUM:
                cf_input = config.TV_VCR_INPUT_NUM

            self.fc.chan_index = self.TunerSetChannel(tuner_channel)

            if hasattr(config,
                       'TV_PAD_CHAN_NUMBERS') and config.TV_PAD_CHAN_NUMBERS:
                mychan = tuner_channel
            else:
                mychan = self.fc.chan_index

            logger.debug('starting channel is %s', mychan)

            command = '%s %s -k -I %s -n %s -d %s -f %s -c %s -i %s' % \
                (config.TVTIME_CMD, outputplugin, w, s_norm, cf_device, 'freevo', mychan, cf_input)

            if osd.get_fullscreen() == 1:
                command += ' -m'
            else:
                command += ' -M'

        else:
            print 'Mode "%s" is not implemented' % mode  # BUG ui.message()
            return

        self.mode = mode

        mixer = plugin.getbyname('MIXER')

        # BUG Mixer manipulation code.
        # TV is on line in
        # VCR is mic in
        # btaudio (different dsp device) will be added later
        if mixer and config.MIXER_MAJOR_CTRL == 'VOL':
            mixer_vol = mixer.getMainVolume()
            mixer.setMainVolume(0)
        elif mixer and config.MIXER_MAJOR_CTRL == 'PCM':
            mixer_vol = mixer.getPcmVolume()
            mixer.setPcmVolume(0)

        # Start up the TV task
        self.app = TVTimeApp(command)

        rc.add_app(self)

        # Suppress annoying audio clicks
        time.sleep(0.4)
        # BUG Hm.. This is hardcoded and very unflexible.
        if mixer and mode == 'vcr':
            mixer.setMicVolume(config.MIXER_VOLUME_VCR_IN)
        elif mixer:
            mixer.setLineinVolume(config.MIXER_VOLUME_TV_IN)
            mixer.setIgainVolume(config.MIXER_VOLUME_TV_IN)

        if mixer and config.MIXER_MAJOR_CTRL == 'VOL':
            mixer.setMainVolume(mixer_vol)
        elif mixer and config.MIXER_MAJOR_CTRL == 'PCM':
            mixer.setPcmVolume(mixer_vol)

        logger.debug('%s: started %s app', time.time(), self.mode)

    def Stop(self, channel_change=0):
        mixer = plugin.getbyname('MIXER')
        if mixer and not channel_change:
            mixer.setLineinVolume(0)
            mixer.setMicVolume(0)
            mixer.setIgainVolume(0)  # Input on emu10k cards.

        self.app.stop('quit\n')
        rc.remove_app(self)

    def eventhandler(self, event, menuw=None):
        logger.debug('%s: %s app got %s event', time.time(), self.mode, event)
        if event == em.STOP or event == em.PLAY_END:
            self.Stop()
            rc.post_event(em.PLAY_END)
            return True

        elif event == em.TV_CHANNEL_UP or event == em.TV_CHANNEL_DOWN:
            if self.mode == 'vcr':
                return

            if event == em.TV_CHANNEL_UP:
                nextchan = self.fc.getNextChannel()
            elif event == em.TV_CHANNEL_DOWN:
                nextchan = self.fc.getPrevChannel()
            nextvg = self.fc.getVideoGroup(nextchan, True)
            logger.debug("nextchan is %s", nextchan)

            # XXX hazardous to your health. don't use tvtime with anything
            # other than one normal video_group.
            # we lose track of the channel index at some points and
            # chaos ensues
            #if self.current_vg != nextvg:
            #    self.Stop(channel_change=1)
            #    self.Play('tv', nextchan)
            #    return TRUE

            self.fc.chanSet(nextchan, True, app=self.app)
            #self.current_vg = self.fc.getVideoGroup(self.fc.getChannel(), True)

            # Go to the prev/next channel in the list
            if event == em.TV_CHANNEL_UP:
                self.app.write('CHANNEL_UP\n')
            else:
                self.app.write('CHANNEL_DOWN\n')

            return True

        elif event == em.TOGGLE_OSD:
            self.app.write('DISPLAY_INFO\n')
            return True

        elif event == em.OSD_MESSAGE:
            # XXX this doesn't work
            #self.app.write('display_message %s\n' % event.arg)
            #this does
            os.system('tvtime-command display_message \'%s\'' % event.arg)
            return True

        elif event == em.TV_SEND_TVTIME_CMD:
            os.system('tvtime-command %s' % event.arg)
            return True

        elif event in em.INPUT_ALL_NUMBERS:
            self.app.write('CHANNEL_%s\n' % event.arg)

        elif event == em.BUTTON:
            if event.arg == 'PREV_CH':
                self.app.write('CHANNEL_PREV\n')
                return True

        return False
Example #36
0
class TunerControl:
    """
    Class that controls the tuner device
    """
    def __init__(self, xine):
        """ TunerControl constructor """
        self.xine = xine
        self.ivtv_init = False
        self.fc = FreevoChannels()
        self.curr_channel = None
        self.embed = None
        self.stack = []

    def _kill_(self):
        """ TunerControl destructor """
        if self.embed:
            ivtv_dev.setvbiembed(self.embed)

    def Stop(self):
        """ stop """
        self.ivtv_init = False

    def GetChannelName(self):
        """ get channel info """
        tuner_id, chan_name, prog_info = self.fc.getChannelInfo(showtime=False)
        return (chan_name)

    def GetProgramName(self):
        """ get channel name """
        tuner_id, chan_name, prog_info = self.fc.getChannelInfo(showtime=True)
        return prog_info

    def GetInfo(self):
        """ get channel info """
        tuner_id, chan_id, chan_name, start_t, stop_t, prog_s = self.fc.getChannelInfoRaw(
        )
        return (start_t, stop_t, prog_s)

    def ShowInfo(self):
        """ show channel info """
        if self.curr_channel is not None:
            tuner_id, chan_name, prog_info = self.fc.getChannelInfo(
                showtime=False)
            self.xine.ShowMessage(msg='%s: %s' % (chan_name, prog_info))

    def PushChannel(self):
        """ push the current channel on the channel stack """
        if self.curr_channel is not None:
            self.stack.append(self.curr_channel)
            logger.debug('TunerControl: Pushed channel %s', self.curr_channel)
        logger.debug('TunerControl: Channel stack = %s', self.stack)

    def UnpushChannel(self):
        """ remove the top channel from the channel stack """
        if len(self.stack) == 0:
            logger.debug('TunerControl: Channel stack is empty')
        else:
            channel = self.stack.pop()
            logger.debug('TunerControl: Unpushed channel %s', channel)
        logger.debug('TunerControl: Channel stack = %s', self.stack)

    def PopChannel(self):
        """ pop the top channel from the channel stack and switch channel """
        if len(self.stack) == 0:
            logger.debug('TunerControl: Channel stack is empty')
        else:
            channel = self.stack.pop()
            logger.debug('TunerControl: Popped channel %s', channel)
            self.SetVideoGroup(channel)
        logger.debug('TunerControl: Channel stack = %s', self.stack)

    def SwapChannel(self):
        """swap the current display channel and the top of the stack channel """
        if self.curr_channel is not None:
            toswap = self.curr_channel
            if len(self.stack) == 0:
                logger.debug('TunerControl: Channel stack is empty')
            else:
                channel = self.stack.pop()
                logger.debug('TunerControl: Popped channel %s', channel)
                self.SetVideoGroup(channel)
                self.stack.append(toswap)
                logger.debug('TunerControl: Pushed channel %s', toswap)
        logger.debug('TunerControl: Channel stack = %s', self.stack)

    def SetChannelByName(self, channel=None, clearstack=False):
        """ tune to a new channel by name """
        last_channel = self.curr_channel
        next_channel = None
        channel_index = -1

        if clearstack:
            self.stack = []
            self.curr_channel = None

        if channel is None:
            # get a channel
            next_channel = self.fc.getChannel()

        try:
            # lookup the channel name in TV_CHANNELS
            for pos in range(len(config.TV_CHANNELS)):
                entry = config.TV_CHANNELS[pos]
                if str(channel) == str(entry[2]):
                    channel_index = pos
                    next_channel = channel
                    break
        except ValueError:
            pass

        if next_channel is None:
            logger.warning(
                'TunerControl: Cannot find tuner channel %r in the TV channel listing',
                channel)
        else:
            self.SetChannelByIndex(channel_index + 1)

    def SetChannelByIndex(self, channel, tvlike=0):
        """ tune to a channel by index from the TV_CHANNELS list """
        next_channel = self.fc.getManChannel(channel, tvlike)
        logger.debug('TunerControl: Explicit channel selection by index = %r',
                     next_channel)
        self.PushChannel()
        self.SetVideoGroup(next_channel)

    def SetChannelByNumber(self, channel):
        """ tune to a channel by actual channel number """
        logger.debug('TunerControl: Explicit channel selection by number = %r',
                     channel)
        self.PushChannel()
        self.SetVideoGroup(channel)

    def NextChannel(self):
        """ jump to the next channel in the TV_CHANNELS list """
        next_channel = self.fc.getNextChannel()
        logger.debug('TunerControl: Next channel selection = %r', next_channel)
        self.PushChannel()
        self.SetVideoGroup(next_channel)

    def PrevChannel(self):
        """ jump to the previous channel in the TV_CHANNELS list """
        prev_channel = self.fc.getPrevChannel()
        logger.debug('TunerControl: Previous channel selection = %r',
                     prev_channel)
        self.PushChannel()
        self.SetVideoGroup(prev_channel)

    def SetVideoGroup(self, channel):
        """ select a channel's video group and tune to that channel """
        try:
            channel_num = int(channel)
        except ValueError:
            channel_num = 0
        logger.debug('TunerControl: Channel: %r', channel)
        new_vg = self.fc.getVideoGroup(channel, True)
        logger.debug('TunerControl: Group: type=%r, desc=%r',
                     new_vg.group_type, new_vg.desc)
        logger.debug('TunerControl: Input: type=%r, num=%r', new_vg.input_type,
                     new_vg.input_num)

        if new_vg.group_type != 'ivtv':
            logger.error('TunerControl: VideoGroup %s is not supported',
                         new_vg)
            pop = AlertBox(
                text=_('This plugin only supports the ivtv video group!'))
            pop.show()
            return

        # check if videogroup switch is needed
        switch_vg = not self.ivtv_init or self.curr_channel is None or \
                    new_vg != self.fc.getVideoGroup(self.curr_channel, True)

        if switch_vg:
            # switch to a different video group
            logger.info('TunerControl: Set VideoGroup: %s', new_vg)
            ivtv_dev = ivtv.IVTV(new_vg.vdev)
            ivtv_dev.init_settings()
            self.xine.SetInput(new_vg.input_num)
            # disable embedded vbi data
            self.embed = ivtv_dev.getvbiembed()
            ivtv_dev.setvbiembed(0)

        if not self.ivtv_init:
            # set channel directly on v4l device, if channel is not negative
            if channel_num >= 0:
                self.fc.chanSet(channel, True)
            self.curr_channel = channel
            self.ivtv_init = True
        else:
            # set channel through xine process
            freq = self.fc.chanSet(channel, True, 'ivtv_xine_tv', None)

            if freq != 0:
                # channel has frequency
                logger.debug('TunerControl: Set frequency: %s', freq)
                self.xine.SetFrequency(freq)
            else:
                # channel has no frequency
                logger.debug('TunerControl: Channel has no frequency')

            self.curr_channel = channel
            self.xine.SeekEnd()
            self.ShowInfo()

        self.SetAudioByChannel(channel)

    def SetAudioByChannel(self, channel=-1):
        """
        Set the PVR sound level
        This is a mix : The base volume is set by the avol
        option in each TV_VIDEO_GROUP. The value is hardware dependant.
        seems bo be between 0 and 65535.
        If this value is missing in the tv_video_group, that sub does nothing
        If the value is present, the actual audio value is this value
        time the 6th field in TV_CHANNELS (expressed in % )
        """
        try:
            # lookup the channel name in TV_CHANNELS
            for pos in range(len(config.TV_CHANNELS)):
                entry = config.TV_CHANNELS[pos]
                if str(channel) == str(entry[2]):
                    channel_index = pos
                    break
        except ValueError:
            pass

        logger.debug('SetAudioByChannel: Channel: %r TV_CHANNEL pos(%d)',
                     channel, channel_index)
        vg = self.fc.getVideoGroup(channel, True)
        try:
            ivtv_avol = vg.avol
        except AttributeError:
            ivtv_avol = 0
        if ivtv_avol <= 0:
            logger.debug(
                'SetAudioByChannel: The tv_video group for %r doesn\'t set the volume',
                channel)
        else:
            # Is there a specific volume level in TV_CHANNELS_VOLUME
            ivtv_dev = ivtv.IVTV(vg.vdev)
            avol_percent = 100
            try:
                # lookup the channel name in TV_CHANNELS
                for pos in range(len(config.TV_CHANNELS_VOLUME)):
                    if config.TV_CHANNELS_VOLUME[pos][0] == config.TV_CHANNELS[
                            channel_index][0]:
                        avol_percent = config.TV_CHANNELS_VOLUME[pos][1]
                        break
            except:
                pass

            try:
                avol_percent = int(avol_percent)
            except ValueError:
                avol_percent = 100

            avol = int(ivtv_avol * avol_percent / 100)
            if avol > 65535:
                avol = 65535
            if avol < 0:
                avol = 0
            logger.debug('SetAudioByChannel: Current PVR Sound level is : %s',
                         ivtv_dev.getctrl(0x00980905))
            logger.debug(
                'SetAudioByChannel: Set the PVR Sound Level to : %s (%s * %s)',
                avol, ivtv_avol, avol_percent)
            ivtv_dev.setctrl(0x00980905, avol)
            logger.debug('SetAudioByChannel: New PVR Sound level is : %s',
                         ivtv_dev.getctrl(0x00980905))
Example #37
0
    def run(self):
        logger.log(9, 'Record_Thread.run()')
        while 1:
            logger.debug('Record_Thread::run: mode=%s', self.mode)
            if self.mode == 'idle':
                self.mode_flag.wait()
                self.mode_flag.clear()

            elif self.mode == 'record':
                try:
                    logger.info('Record_Thread::run: started recording')

                    fc = FreevoChannels()
                    logger.debug('Channel: %s', fc.getChannel())

                    vg = fc.getVideoGroup(self.prog.tunerid, False)

                    logger.debug('Opening device %r', vg.vdev)
                    v = tv.ivtv.IVTV(vg.vdev)

                    v.init_settings()

                    logger.debug('Setting input to %r', vg.input_type)
                    v.setinputbyname(vg.input_type)

                    cur_std = v.getstd()
                    try:
                        new_std = V4L2.NORMS.get(vg.tuner_norm)
                        if cur_std != new_std:
                            logger.debug('Setting standard to %s', new_std)
                            v.setstd(new_std)
                    except:
                        logger.error(
                            "Videogroup norm value '%s' not from NORMS: %s",
                            vg.tuner_norm, V4L2.NORMS.keys())

                    logger.debug('Setting channel to %r', self.prog.tunerid)
                    fc.chanSet(str(self.prog.tunerid), False)

                    # Setting the input sound level on the PVR card
                    channel = self.prog.tunerid
                    try:
                        # lookup the channel name in TV_CHANNELS
                        for pos in range(len(config.TV_CHANNELS)):
                            entry = config.TV_CHANNELS[pos]
                            if str(channel) == str(entry[2]):
                                channel_index = pos
                                break
                    except ValueError:
                        pass

                    logger.debug(
                        'SetAudioByChannel: Channel: %r TV_CHANNEL pos(%d)',
                        channel, channel_index)
                    try:
                        ivtv_avol = vg.avol
                    except AttributeError:
                        ivtv_avol = 0
                    if ivtv_avol <= 0:
                        logger.debug(
                            'SetAudioByChannel: The tv_video group for %r doesn\'t set the volume',
                            channel)
                    else:
                        # Is there a specific volume level in TV_CHANNELS_VOLUME
                        avol_percent = 100
                        try:
                            # lookup the channel name in TV_CHANNELS
                            for pos in range(len(config.TV_CHANNELS_VOLUME)):
                                if config.TV_CHANNELS_VOLUME[pos][
                                        0] == config.TV_CHANNELS[
                                            channel_index][0]:
                                    avol_percent = config.TV_CHANNELS_VOLUME[
                                        pos][1]
                                    break
                        except:
                            pass

                        try:
                            avol_percent = int(avol_percent)
                        except ValueError:
                            avol_percent = 100

                        avol = int(ivtv_avol * avol_percent / 100)
                        if avol > 65535:
                            avol = 65535
                        if avol < 0:
                            avol = 0
                        logger.debug(
                            'SetAudioByChannel: Current PVR Sound level is : %s',
                            v.getctrl(0x00980905))
                        logger.debug(
                            'SetAudioByChannel: Set the PVR Sound Level to : %s (%s * %s)',
                            avol, ivtv_avol, avol_percent)
                        v.setctrl(0x00980905, avol)
                        logger.debug(
                            'SetAudioByChannel: New PVR Sound level is : %s',
                            v.getctrl(0x00980905))

                    if vg.cmd != None:
                        logger.debug("Running command %r", vg.cmd)
                        retcode = os.system(vg.cmd)
                        logger.debug("exit code: %g", retcode)

                    now = time.time()
                    stop = now + self.prog.rec_duration

                    rc.post_event(Event('RECORD_START', arg=self.prog))
                    time.sleep(2)

                    v_in = open(vg.vdev, 'r')
                    v_out = open(self.prog.filename, 'w')

                    logger.debug('Recording from %r to %r in %s byte chunks',
                                 vg.vdev, self.prog.filename, CHUNKSIZE)
                    while time.time() < stop:
                        buf = v_in.read(CHUNKSIZE)
                        v_out.write(buf)
                        if self.mode == 'stop':
                            logger.info('Recording stopped')
                            break

                    v_in.close()
                    v_out.close()
                    v.close()
                    v = None

                    self.mode = 'idle'

                    rc.post_event(Event('RECORD_STOP', arg=self.prog))
                    logger.info('Record_Thread::run: finished recording')
                except Exception, why:
                    logger.critical('%s', why)
                    return

            else:
                self.mode = 'idle'

            time.sleep(0.5)
Example #38
0
    def run(self):
        logger.log( 9, 'Record_Thread.run()')
        while 1:
            logger.debug('Record_Thread::run: mode=%s', self.mode)
            if self.mode == 'idle':
                self.mode_flag.wait()
                self.mode_flag.clear()

            elif self.mode == 'record':
                try:
                    logger.info('Record_Thread::run: started recording')

                    fc = FreevoChannels()
                    logger.debug('Channel: %s', fc.getChannel())

                    vg = fc.getVideoGroup(self.prog.tunerid, False)

                    logger.debug('Opening device %r', vg.vdev)
                    v = tv.ivtv.IVTV(vg.vdev)

                    v.init_settings()

                    logger.debug('Setting input to %r', vg.input_type)
                    v.setinputbyname(vg.input_type)

                    cur_std = v.getstd()
                    try:
                        new_std = V4L2.NORMS.get(vg.tuner_norm)
                        if cur_std != new_std:
                            logger.debug('Setting standard to %s', new_std)
                            v.setstd(new_std)
                    except:
                        logger.error("Videogroup norm value '%s' not from NORMS: %s", vg.tuner_norm, V4L2.NORMS.keys())


                    logger.debug('Setting channel to %r', self.prog.tunerid)
                    fc.chanSet(str(self.prog.tunerid), False)

                    # Setting the input sound level on the PVR card
                    channel = self.prog.tunerid
                    try:
                        # lookup the channel name in TV_CHANNELS
                        for pos in range(len(config.TV_CHANNELS)):
                            entry = config.TV_CHANNELS[pos]
                            if str(channel) == str(entry[2]):
                                channel_index = pos
                                break
                    except ValueError:
                        pass

                    logger.debug('SetAudioByChannel: Channel: %r TV_CHANNEL pos(%d)', channel, channel_index)
                    try:
                        ivtv_avol = vg.avol
                    except AttributeError:
                        ivtv_avol = 0
                    if ivtv_avol <= 0:
                        logger.debug('SetAudioByChannel: The tv_video group for %r doesn\'t set the volume', channel)
                    else:
                        # Is there a specific volume level in TV_CHANNELS_VOLUME
                        avol_percent = 100
                        try:
                            # lookup the channel name in TV_CHANNELS
                            for pos in range(len(config.TV_CHANNELS_VOLUME)):
                                if config.TV_CHANNELS_VOLUME[pos][0] == config.TV_CHANNELS[channel_index][0]:
                                    avol_percent = config.TV_CHANNELS_VOLUME[pos][1]
                                    break
                        except:
                            pass

                        try:
                            avol_percent = int(avol_percent)
                        except ValueError:
                            avol_percent = 100

                        avol = int(ivtv_avol * avol_percent / 100)
                        if avol > 65535:
                            avol = 65535
                        if avol < 0:
                            avol = 0
                        logger.debug('SetAudioByChannel: Current PVR Sound level is : %s', v.getctrl(0x00980905))
                        logger.debug('SetAudioByChannel: Set the PVR Sound Level to : %s (%s * %s)', avol, ivtv_avol, avol_percent)
                        v.setctrl(0x00980905, avol)
                        logger.debug('SetAudioByChannel: New PVR Sound level is : %s', v.getctrl(0x00980905))

                    if vg.cmd != None:
                        logger.debug("Running command %r", vg.cmd)
                        retcode = os.system(vg.cmd)
                        logger.debug("exit code: %g", retcode)

                    now = time.time()
                    stop = now + self.prog.rec_duration

                    rc.post_event(Event('RECORD_START', arg=self.prog))
                    time.sleep(2)

                    v_in  = open(vg.vdev, 'r')
                    v_out = open(self.prog.filename, 'w')

                    logger.debug('Recording from %r to %r in %s byte chunks', vg.vdev, self.prog.filename, CHUNKSIZE)
                    while time.time() < stop:
                        buf = v_in.read(CHUNKSIZE)
                        v_out.write(buf)
                        if self.mode == 'stop':
                            logger.info('Recording stopped')
                            break

                    v_in.close()
                    v_out.close()
                    v.close()
                    v = None

                    self.mode = 'idle'

                    rc.post_event(Event('RECORD_STOP', arg=self.prog))
                    logger.info('Record_Thread::run: finished recording')
                except Exception, why:
                    logger.critical('%s', why)
                    return

            else:
                self.mode = 'idle'

            time.sleep(0.5)