Esempio n. 1
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()
Esempio n. 2
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
Esempio n. 3
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
Esempio n. 4
0
class Xine:
    """
    the main class to control xine
    """
    def __init__(self, type):
        self.name      = 'xine'

        self.event_context = 'tv'
        self.xine_type = type
        self.app       = None

        self.fc = FreevoChannels()

        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(' ')


    def ShowMessage(self, msg):
        """
        Show a message on the OSD
        """
        logger.debug("XINE: Show OSD Message: '%s'", msg)
        self.app.write("OSDWriteText$     %s\n" % msg)


    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()

        command = copy.copy(self.command)

        if config.XINE_HAS_NO_LIRC:
            command.append('--no-lirc')

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

        command.append('dvb://' + tuner_channel)

        logger.debug('Starting cmd=%s', command)

        rc.add_app(self)

        self.app = childapp.ChildApp2(command)
        dialog.enable_overlay_display(AppTextDisplay(self.ShowMessage))
        return None


    def stop(self, channel_change=0):
        """
        Stop xine
        """
        if self.app:
            if config.OSD_SINGLE_WINDOW:
                osd.video_window.hide()

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

            if not channel_change:
                pass


    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
        """
        if event in ( PLAY_END, USER_END, STOP ):
            self.stop()
            rc.post_event(PLAY_END)
            return True

        if event == PAUSE or event == PLAY:
            self.app.write('pause\n')
            return True

        elif event in [ TV_CHANNEL_UP, TV_CHANNEL_DOWN] or str(event).startswith('INPUT_'):
            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(channel_change=1)
            self.fc.chanSet(nextchan, True)
            self.Play('tv', nextchan)
            return True

        if event == TOGGLE_OSD:
            self.app.write('PartMenu\n')
            return True

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

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

        # nothing found
        return False
Esempio n. 5
0
class LivePauseController:
    """
    The main class to control play back.
    """
    def __init__(self, player):
        self.name = 'livepause'
        self.event_context  = 'tv'

        self.fc = FreevoChannels()

        self.backend = backend.get_backend()
        self.backend.set_mode(player.mode)

        self.last_channel = None
        self.stop_time = 0
        self.data_started_timer = kaa.OneShotTimer(self.__buffering_data_timedout)
        self.disable_buffering_timer = kaa.OneShotTimer(self.__disable_buffering_timeout)

        self.state = State.IDLE
        self.player = player

        self.changing_channel = False

        self.subtitles = None
        self.subtitle_index = -1

        self.audio_langs = None
        self.audio_lang_index = -1

        self.recording = False

        self.state_dialog = None

        # Setup Event Maps
        self.event_maps = {}
        self.event_maps[State.IDLE] = {
            'READER_OVERTAKEN'    : self.__idle_reader_overtaken,
            }

        self.event_maps[State.TUNING] = {
            'DATA_STARTED' : self.__tuning_data_started,
            'DATA_TIMEDOUT': self.__tuning_data_timedout,
            'PLAY_END'     : self.__handle_stop,
            'USER_END'     : self.__handle_stop,
            'STOP'         : self.__handle_stop
            }

        self.event_maps[State.BUFFERING] = {
            'DATA_ACQUIRED': self.__buffering_data_acquired,
            'DATA_TIMEDOUT': self.__buffering_data_timedout,
            'PLAY_END'     : self.__handle_stop,
            'USER_END'     : self.__handle_stop,
            'STOP'         : self.__handle_stop
            }

        self.event_maps[State.PLAYING] = {
            'PLAY'                : self.__playing_play_pause,
            'PAUSE'               : self.__playing_play_pause,
            'PLAY_END'            : self.__handle_stop,
            'USER_END'            : self.__handle_stop,
            'STOP'                : self.__handle_stop,
            'TV_CHANNEL_UP'       : self.__playing_tv_channel_up,
            'TV_CHANNEL_DOWN'     : self.__playing_tv_channel_down,
            'TV_CHANNEL_NUMBER'   : self.__playing_tv_channel_number,
            'TV_START_RECORDING'  : self.__playing_tv_record,
            'SAVE_STARTED'        : self.__playing_tv_record_start,
            'SAVE_FINISHED'       : self.__playing_tv_record_stop,
            'BUTTON'              : self.__playing_button_pressed,
            'TOGGLE_OSD'          : self.__playing_display_info,
            'SEEK'                : self.__playing_seek,
            'SECONDS_LEFT'        : self.__playing_seconds_left,
            'READER_OVERTAKEN'    : self.__playing_reader_overtaken,
            'DATA_ACQUIRED'       : None,
            'DATA_TIMEDOUT'       : None,
            'VIDEO_NEXT_FILLMODE' : None,
            'VIDEO_NEXT_AUDIOMODE': None,
            'VIDEO_NEXT_AUDIOLANG': None, #self.__playing_toggle_audo_lang,
            'VIDEO_NEXT_SUBTITLE' : self.__playing_toggle_subtitles,
            }

        self.current_event_map = self.event_maps[self.state]


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

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

        self.disable_buffering_timer.stop()

        rc.add_app(self)

        # 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 self.last_channel == tuner_channel:
            now = time.time()
            seconds_since_played = now - self.stop_time
            logger.debug('Same channel, seconds since last playing this channel %d', seconds_since_played)
            self.backend.set_events_enabled(True)
            if seconds_since_played > 120.0:
                # Start at the end of the buffer
                buffer_info = self.backend.get_buffer_info()
                self.backend.seekto(buffer_info[2] - 3)

            self.__change_state(State.PLAYING)
        else:
            logger.debug('New channel, tuning to %s', tuner_channel)
            self.backend.set_events_enabled(True)
            self.change_channel(tuner_channel)

        return None


    def stop(self):
        """
        Stop playback and go into idle.
        """
        logger.debug('Stopping play back.')
        display.get_osd().hide()
        dialog.disable_overlay_display()
        self.player.stop()
        self.stop_time = time.time()
        self.backend.set_events_enabled(False)
        self.__change_state(State.IDLE)
        self.disable_buffering_timer.start(config.LIVE_PAUSE2_BUFFER_TIMEOUT)
        return True

    def disable_buffering(self):
        """
        Stop buffering the current channel.
        """
        self.stop_time = 0
        self.last_channel = None
        self.disable_buffering_timer.stop()
        self.backend.disable_buffering()
        logger.debug('Buffering disabled.')

    def shutdown(self):
        """
        Stop buffering and the slave server.
        """
        self.disable_buffering()


    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
        self.fc.chanSet(channel, True)

        self.last_channel = channel
        self.backend.change_channel(channel)
        self.__change_state(State.TUNING)


    ###########################################################################
    # Event Handlers
    ###########################################################################
    def eventhandler(self, event, menuw=None):
        """
        Eventhandler for livepause control. If an event is not bound in this
        function it will be passed over to the items eventhandler
        """
        logger.log( 9, 'Event %s', event)
        event_consumed = False
        if self.state == State.PLAYING:
            event_consumed = tv.dialogs.handle_channel_number_input(event)

        if not event_consumed and event.name in self.current_event_map:
            handler = self.current_event_map[event.name]
            if handler:
                event_consumed = handler(event, menuw)
            else:
                # Event was in map but no handler so just consume the event.
                event_consumed = True

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

        return event_consumed

    def __handle_stop(self, event, menuw):
        if self.changing_channel:
            self.changing_channel = False
        else:
            self.stop()
        return True

    def __idle_reader_overtaken(self, event, menuw):
        # Seek ten seconds forward from the end of the buffer.
        self.backend.seek(10, now=True)
        return True

    def __tuning_data_started(self, event, menuw):
        self.__change_state(State.BUFFERING)
        return True

    def __tuning_data_timedout(self, event, menuw):
        # Timeout while waiting for data!
        # We could display a searching for signal graphic or something here
        self.__change_state(State.IDLE)
        return True

    def __buffering_data_acquired(self, event, menuw):
        self.wait_for_data_count -= 1
        self.__draw_state_screen()
        if self.wait_for_data_count <= 0:
            self.__change_state(State.PLAYING)
        return True

    def __buffering_data_timedout(self, event, menuw):
        # Timeout while waiting for data!
        # We could display a searching for signal graphic or something here
        self.__change_state(State.IDLE)
        return True

    def __playing_play_pause(self, event, menuw):
        if self.player.paused:
            self.player.resume()
        else:
            self.player.pause()
        self.osd.display_buffer_pos(self.__get_display_info)
        return True

    def __playing_tv_channel_up(self, event, menuw):
        next_channel = self.fc.getNextChannel()

        self.changing_channel = True
        self.player.stop()

        self.change_channel(next_channel)
        return True

    def __playing_tv_channel_down(self, event, menuw):
        next_channel = self.fc.getPrevChannel()

        self.changing_channel = True
        self.player.stop()

        self.change_channel(next_channel)
        return True

    def __playing_tv_channel_number(self, event, menuw):
        next_channel = self.fc.getManChannel(event.arg)
        if self.last_channel != next_channel:
            self.changing_channel = True
            self.player.stop()

            self.change_channel(next_channel)
        return True

    def __playing_tv_record(self, event, menuw):
        if self.recording:
            self.backend.cancelsave()
            self.recording = False
        else:
            self.recording = True
            record.start_recording(self.backend, self.last_channel)

    def __playing_tv_record_start(self, event, menuw):
        dialog.show_message(_('Recording started'))

    def __playing_tv_record_stop(self, event, menuw):
        if self.state == State.PLAYING:
            dialog.show_message(_('Recording stopped'))
        self.recording = False

    def __playing_seconds_left(self, event, menuw):
        if self.player.paused:
            self.player.resume()
            dialog.show_message(_('Out of buffer space, playback resumed'))
        else:
            logger.debug('while playing ~%d seconds left in buffer before overwrite', event.arg)
        return True
    
    def __playing_reader_overtaken(self, event, menuw):
        if self.player.paused:
            self.player.resume()
            dialog.show_message(_('Out of buffer space, playback resumed'))
        else:
            dialog.show_message(_('Out of buffer space'))
            logger.debug('Out of buffer space while playing!')
        return True

    def __playing_button_pressed(self, event, menuw):
        consumed = False
        logger.debug('Button %s', event.arg)
        if event.arg == 'SUBTITLE':
            self.__playing_toggle_subtitles(event, menuw)
            consumed = True

        return consumed

    def __playing_toggle_subtitles(self, event, menuw):
        # Enable/Disable subtitles
        if self.subtitles:
            self.subtitle_index += 1

        else:
            self.subtitles = self.player.get_subtitles()
            self.subtitle_index = 0

        if self.subtitles:
            if self.subtitle_index >= len(self.subtitles):
                self.subtitle_index = -1

            self.player.set_subtitles(self.subtitle_index)
            if self.subtitle_index == -1:
                subtitle_text = _('Disabled')
            else:
                subtitle_text = self.subtitles[self.subtitle_index]
            dialog.show_message(_('Subtitles: %s') % subtitle_text)
        else:
            dialog.show_message(_('Subtitles not supported'))

        return True

    def __playing_toggle_audio_lang(self, event, menuw):
        if self.audio_langs:
            self.audio_lang_index += 1

        else:
            self.audio_langs = self.player.get_audio_langs()
            self.audio_lang_index = 0

        if self.audio_langs:
            if self.audio_lang_index >= len(self.audio_langs):
                self.audio_lang_index = -1

            self.player.set_audio_lang(self.audio_lang_index)
            if self.audio_lang_index == -1:
                audio_lang_text = _('Default')
            else:
                audio_lang_text = self.subtitles[self.subtitle_index]

            dialog.show_message(_('Audio language: %s') % audio_lang_text)
        else:
            dialog.show_message(_('Audio language selection not supported'))

        return True

    def __playing_display_info(self, event, menuw):
        self.osd.display_info(self.__get_display_info)
        return True

    def __get_display_info(self):
        info_dict = {}
        info_dict['channel'] = self.__get_display_channel()
        buffer_info = self.backend.get_buffer_info()
        info_dict['current_time'] = buffer_info[3]
        info_dict['start_time'] = buffer_info[1]
        info_dict['end_time'] = buffer_info[2]
        info_dict['percent_through_buffer'] = float(buffer_info[3] - buffer_info[1]) / float(buffer_info[2] - buffer_info[1])
        info_dict['percent_buffer_full'] = buffer_info[0]
        info_dict['paused'] = self.player.paused
        info_dict['recording'] = self.recording
        return info_dict

    def __playing_seek(self, event, menuw):
        steps = int(event.arg)
        buffer_info = self.backend.get_buffer_info()
        if steps > 0:
            can_seek = buffer_info[2] != buffer_info[3]
            steps = min(buffer_info[2] - buffer_info[3], steps)
        else:
            steps = max(buffer_info[1] - buffer_info[3], steps)
            can_seek = buffer_info[1] != buffer_info[3]
        if can_seek:
            self.backend.seek(steps)
            self.player.restart()
        time.sleep(0.2)
        self.osd.display_buffer_pos(self.__get_display_info)
        return True

    ###########################################################################
    # State Management
    ###########################################################################

    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

        logger.debug('Changing state from %s to %s', self.state, new_state)
        old_state = self.state
        self.state = new_state
        self.current_event_map = self.event_maps[new_state]

        # State Initialisation code

        if self.state == State.IDLE:
            self.state_dialog.hide()
            rc.remove_app(self)
            rc.post_event(PLAY_END)
            self.backend.set_events_enabled(False)

        elif self.state == State.TUNING:
            # Display the current state on the OSD
            self.__draw_state_screen()

        elif self.state == State.BUFFERING:
            self.wait_for_data_count = WAIT_FOR_DATA_COUNT
            # Display the current state on the OSD
            self.__draw_state_screen()

        elif self.state == State.PLAYING:
            # Display the current state on the OSD
            self.__draw_state_screen()

            self.player.start((self.backend.get_server_address(), config.LIVE_PAUSE2_PORT))
            dialog.enable_overlay_display(self.player.get_display())
            self.osd = display.get_osd()



    def __draw_state_screen(self):
        if self.state_dialog is None:
            self.state_dialog = StateDialog()

        percent = 0.0
        if self.state == State.BUFFERING:
            percent = float(WAIT_FOR_DATA_COUNT - self.wait_for_data_count) / float(WAIT_FOR_DATA_COUNT)

        elif self.state == State.PLAYING:
            percent = 1.0

        channel = self.__get_display_channel()
        self.state_dialog.set_state(self.state, percent, channel)
        self.state_dialog.show()

    def __get_display_channel(self):
        channel = self.last_channel

        for entry in config.TV_CHANNELS:
            if self.last_channel == entry[2]:
                channel = entry[1]

        return channel

    def __fire_channel_number(self):
        rc.post_event(TV_CHANNEL_NUMBER)
        self.channel_number_timer = None

    def __disable_buffering_timeout(self):
        self.disable_buffering()
Esempio n. 6
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)
Esempio n. 7
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))
Esempio n. 8
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))
Esempio n. 9
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
Esempio n. 10
0
class Xine:
    """
    the main class to control xine
    """
    def __init__(self, type):
        self.name      = 'xine'

        self.app_mode  = 'tv'
        self.xine_type = type
        self.app       = None

        self.fc = FreevoChannels()

        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(' ')


    def ShowMessage(self, msg):
        """
        Show a message on the OSD
        """
        _debug_("XINE: Show OSD Message: '%s'" % msg)
        self.app.write("OSDWriteText$     %s\n" % msg)


    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()

        command = copy.copy(self.command)

        if not config.XINE_HAS_NO_LIRC and '--no-lirc' in command:
            command.remove('--no-lirc')

        command.append('dvb://' + tuner_channel)

        _debug_('Xine.play(): Starting cmd=%s' % command)

        rc.app(self)

        self.app = childapp.ChildApp2(command)
        return None


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

            if not channel_change:
                pass


    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
        """
        if event in ( PLAY_END, USER_END, STOP ):
            self.stop()
            rc.post_event(PLAY_END)
            return True

        if event == PAUSE or event == PLAY:
            self.app.write('pause\n')
            return True

        elif event in [ TV_CHANNEL_UP, TV_CHANNEL_DOWN] or str(event).startswith('INPUT_'):
            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(channel_change=1)
            self.fc.chanSet(nextchan, True)
            self.Play('tv', nextchan)
            return True

        if event == TOGGLE_OSD:
            self.app.write('PartMenu\n')
            return True

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

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

        # nothing found
        return False
Esempio n. 11
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
Esempio n. 12
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
Esempio n. 13
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)
Esempio n. 14
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