So finally i got a first version of the resource system as discussed
before. I'm sure it isn't yet perfect. There are some position in the
code where i don't know how to do it better. So i thought i post it here
and some one may take a look at it.
What works so far. In my test everything that worked before and in
addition the joystick plugin can release the joystick for a game and
gets resumed afterward. So it should work but maybe there should be some
clean up.
Tell me what you think.
Thanks
Mathias
Index: freevo_trunk/core/src/resources.py
===================================================================
--- freevo_trunk/core/src/resources.py (revision 9421)
+++ freevo_trunk/core/src/resources.py (working copy)
@@ -29,32 +29,113 @@
#
# -----------------------------------------------------------------------------
+# kaa imports
+from kaa.notifier import InProgress, Callback
+
_resources = {}
-def get_resources(instance, *resources):
+class ResourceHandler(object):
"""
- Reserve a list of resources. If one or more resources can not be
- reserved, the whole operation fails. The function will return the
- list of failed resources with the instance having this resource.
+ The ResourceHandler inherit from it if you want to use resources that need
+ a specific access rights.
"""
- blocked = {}
- for r in resources:
- if r in _resources:
- blocked[r] = _resources[r]
- if blocked:
- # failed to reserve
- return blocked
- # reserve all resources
- for r in resources:
- _resources[r] = instance
- return {}
+ suspended_handler = []
+ def get_resources(self, *resources):
+ """
+ Reserve a list of resources. If one or more resources can not be
+ reserved, the whole operation fails. The function will return the
+ list of failed resources with this instance having this resource.
+ """
+ blocked = {}
+ for r in resources:
+ if r in _resources:
+ if _resources[r].can_suspend():
+ blocked[r] = _resources[r]
+ else:
+ return False
+ if blocked:
+ # failed to reserve
+ return blocked
+ # reserve all resources
+ for r in resources:
+ _resources[r] = self
+ return {}
-def free_resources(instance, *resources):
- """
- Free all resources blocked by the instance. If not resources are
- provided, free all resources.
- """
- for res, app in _resources.items()[:]:
- if app == instance and (not resources or res in resources):
- del _resources[res]
+
+ def free_resources(self, *resources):
+ """
+ Free all resources blocked by this instance. If no resources are
+ provided, free all resources.
+ """
+ for res, app in _resources.items()[:]:
+ if app == self and (not resources or res in resources):
+ del _resources[res]
+
+
+ def _handler_suspended(self, t, blocked, callback):
+ """
+ Callback for handler that need some more time to release a resource.
+ """
+ for resource in blocked.keys():
+ if resource in _resources:
+ # not yet all resources are free yet
+ return
+
+ # all resource are free now call the handler
+ callback()
+
+
+ def suspend_all(self, blocked, callback):
+ """
+ Suspend all handler that block a resource if done call the callback
+ method.
+ """
+ wait = False
+ # call for all the suspend
+ for handler in blocked:
+ self.suspended_handler.append(blocked[handler])
+ answer = blocked[handler].suspend()
+ if isinstance(answer, InProgress):
+ callback = Callback(self._handler_suspended, blocked, callback)
+# answer.connect(self._handler_suspended, blocked, callback)
+ answer.connect(callback)
+ wait = True
+
+ if wait == True:
+ return
+ else:
+ callback()
+
+
+ def resume_all(self):
+ """
+ Resume all handler suspended by this handler. Clear list at the end.
+ """
+ # resume suspended handlers
+ for handler in self.suspended_handler:
+ handler.resume()
+ # clear list with suspended handler since all resumed
+ self.suspended_handler = []
+
+
+ def can_suspend(self):
+ """
+ Return if it is possible for this handler to release its resource.
+ """
+ return False
+
+
+ def suspend(self):
+ """
+ Suspend this resource handler. Should free all the resources.
+ """
+ return False
+
+
+ def resume(self):
+ """
+ Resume the plugin acquire all the resources again.
+ """
+ pass
+
Index: freevo_trunk/ui/src/games/emulator.py
===================================================================
--- freevo_trunk/ui/src/games/emulator.py (revision 9422)
+++ freevo_trunk/ui/src/games/emulator.py (working copy)
@@ -47,9 +47,11 @@
# freevo imports
import freevo.conf
+from freevo.resources import ResourceHandler
from freevo.ui.mainmenu import MainMenuItem, MainMenuPlugin
from freevo.ui.directory import DirItem
from freevo.ui.event import *
+from freevo.ui import plugin, application
from freevo.ui.menu import Item, Action, Menu
from freevo.ui.plugins.mediamenu import MediaMenu
@@ -135,7 +137,7 @@
Action(_('Remove %s') % self.name, self.remove)]
-class EmulatorPlayer(object):
+class EmulatorPlayer(ResourceHandler):
"""
Generic game player.
"""
@@ -165,7 +167,6 @@
Play game. Should work with most emulators. Will start
[command_name] [parameters] [url]
"""
- self._releaseJoystick()
params = "%s %s" % (self.parameters, self.url)
log.info('Start playing EmulatorItem (%s %s)' % \
(self.command_name, params))
@@ -191,7 +192,6 @@
The game was quit. Send stop event to get back to the menu.
"""
Event(STOP, handler=gameplayer.player.eventhandler).post()
- self._acquireJoystick()
log.info('emulator completed')
@@ -203,23 +203,7 @@
self.child.stop()
- def _releaseJoystick(self):
- """
- Release Joystick that it can be used by the game/emulator
- """
- #FIXME
- pass
-
- def _acquireJoystick(self):
- """
- Acquire Joysitck back that it can be used by freevo
- """
- #FIXME
- pass
-
-
-
class EmulatorMenuItem(MainMenuItem):
"""
This is a menu entry for the different emulators in the games subdirectory.
Index: freevo_trunk/ui/src/games/plugins/pcgames.py
===================================================================
--- freevo_trunk/ui/src/games/plugins/pcgames.py (revision 9422)
+++ freevo_trunk/ui/src/games/plugins/pcgames.py (working copy)
@@ -75,7 +75,6 @@
Play PcGame
"""
log.info('Start playing PcGame (%s %s)', self.command_name, self.parameters)
- self._releaseJoystick()
self.child = kaa.notifier.Process(self.command_name)
self.child.start(self.parameters).connect(self.completed)
self.signals = self.child.signals
@@ -88,7 +87,6 @@
The game was quit. Send Stop event to get back to the menu.
"""
Event(STOP, handler=gameplayer.player.eventhandler).post()
- self._acquireJoystick()
log.info('Game completed')
Index: freevo_trunk/ui/src/games/plugins/scummvm.py
===================================================================
--- freevo_trunk/ui/src/games/plugins/scummvm.py (revision 9422)
+++ freevo_trunk/ui/src/games/plugins/scummvm.py (working copy)
@@ -36,7 +36,6 @@
# python imports
import logging
-from subprocess import Popen, PIPE
# kaa imports
import kaa.utils
@@ -74,7 +73,6 @@
"""
log.info('Start playing PcGame (Scummvm: %s)', self.emulator_item)
parameters = '%s %s' % (config.parameters, self.emulator_item)
- self._releaseJoystick()
self.child = kaa.notifier.Process(config.bin)
self.child.start(parameters).connect(self.completed)
self.signals = self.child.signals
@@ -97,25 +95,54 @@
"""
romlist = []
finished = False
+ parent = None
+ items = None
+ list_started = False
+ def completed(self, exit_code):
+ """
+ The ScummVM returned all configured games, append them to the menu.
+ Add an entry for the ScummVM it self to configure new games or the
+ ScummVM it self.
+ """
+ if self.items == None:
+ self.items = []
+ self.items.append(ScummvmItem(self.parent, 'ScummVM', ''))
+ self.parent.pushmenu(Menu(config.name, self.items, type='games'))
+ self.parent = None
+
+
+ def get_stdout(self, data):
+ """
+ Receive updates from the stdout of the ScummVM. Wait with parsing
+ until a line that starts with '---'
+ """
+ if self.items == None:
+ if data.startswith('---'):
+ self.items = []
+ return
+ # since list was started there are now the configured games coming
+ name = data[:data.find(' ')]
+ description = data[data.find(' '):].strip()
+ self.items.append(ScummvmItem(self.parent, description, name))
+
+
def roms(self, parent):
"""
Show all games.
"""
+ # allready waiting for updated menu?
+ if self.parent != None:
+ return
+ self.parent = parent
+ self.items = None
items = []
- # get list of scummvm
- pipe = Popen([config.bin, '-t'], stdout=PIPE).stdout
- # FIXME: this blocks the notifier loop. Maybe better use
- # kaa.notifier.Process and yield_execution.
- for item in pipe.readlines()[2:]:
- name = item[:item.find(' ')]
- description = item[item.find(' '):].strip()
- items.append(ScummvmItem(parent, description, name))
- # append the scummvm it self, to configure new games
- items.append(ScummvmItem(parent, 'ScummVM', ''))
- parent.pushmenu(Menu(config.name, items, type='games'))
+ # get list of scummvm start a new process
+ self.child = kaa.notifier.Process(config.bin)
+ self.child.start('-t').connect(self.completed)
+ self.child.signals['stdout'].connect(self.get_stdout)
+
-
def items(self, parent):
"""
Return the main menu item.
Index: freevo_trunk/ui/src/games/player.py
===================================================================
--- freevo_trunk/ui/src/games/player.py (revision 9422)
+++ freevo_trunk/ui/src/games/player.py (working copy)
@@ -65,6 +65,7 @@
if player == None:
return False
self.player = player
+ retry = kaa.notifier.Callback(self.play, item, player)
if not self.status in (STATUS_IDLE, STATUS_STOPPED):
# Already running, stop the current player by sending a STOP
# event. The event will also get to the playlist behind the
@@ -83,38 +84,13 @@
# Try to get VIDEO and AUDIO resources. The ressouces will be freed
# by the system when the application switches to STATUS_STOPPED or
# STATUS_IDLE.
- blocked = self.get_resources('AUDIO', 'VIDEO')
- if 'VIDEO' in blocked:
- # Something has the video resource blocked. The only application
- # possible is the tv player right now. It would be possible to
- # ask the user what to do with a popup but we assume the user
- # does not care about the tv and just stop it. FIXME ask user
- Event(STOP, handler=blocked['VIDEO'].eventhandler).post()
- # Now connect to the 'stop' signal once to repeat this current
- # function call without the player playing
- blocked['VIDEO'].signals['stop'].connect_once(retry)
+ blocked = self.get_resources('AUDIO', 'VIDEO', 'JOYSTICK')
+ if blocked == False:
+ log.error("Can't get resource AUDIO, VIDEO, JOYSTICK")
+ return False
+ elif len(blocked) > 0:
+ self.suspend_all(blocked, retry)
return True
- if 'AUDIO' in blocked:
- # AUDIO is blocked, VIDEO is not. This is most likely the audio
- # player and we can pause it. Do this if possible.
- if not blocked['AUDIO'].has_capability(CAPABILITY_PAUSE):
- # Unable to pause, just stop it
- Event(STOP, handler=blocked['AUDIO'].eventhandler).post()
- # Now connect to the 'stop' signal once to repeat this current
- # function call without the player playing
- blocked['AUDIO'].signals['stop'].connect_once(retry)
- return True
- # Now pause the current player. On its pause signal this player can
- # play again. And on the stop signal of this player (STATUS_IDLE)
- # the other player can be resumed again.
- in_progress = blocked['AUDIO'].pause()
- if isinstance(in_progress, kaa.notifier.InProgress):
- # takes some time, wait
- in_progress.connect(retry).set_ignore_caller_args()
- if in_progress is not False:
- # we paused the application, resume on our stop
- self.signals['stop'].connect_once(blocked['AUDIO'].resume)
- return True
# store item
self.item = item
@@ -144,6 +120,40 @@
self.status = STATUS_STOPPING
+ def can_suspend(self):
+ """
+ Return true since it is possible to stop the game. If it is allways the
+ best thing to just stop a game is more questionable. Maybe False would
+ be better.
+ """
+ return True
+
+
+ def suspend(self):
+ """
+ Release the audio, video, joystick resource. (Stop the game)
+ """
+ if not self.status == STATUS_RUNNING:
+ yield False
+ self.status = STATUS_STOPPING
+ self.player.stop()
+ yield kaa.notifiert.YieldCallback(self.player.signals['end'])
+ self.free_resources()
+ yield True
+
+
+ def resume(self):
+ """
+ Replay the game? At the moment this does nothing. The game won't
+ restart.
+ """
+ # restart the handler stoped by this handler before since we don't
+ # run anymore
+ if not self.status == STATUS_RUNNING:
+ return False
+ self.resume_all()
+ return True
+
def eventhandler(self, event):
"""
React on events and do the right command with the game.
Index: freevo_trunk/ui/src/input/plugins/joystick.py
===================================================================
--- freevo_trunk/ui/src/input/plugins/joystick.py (revision 9422)
+++ freevo_trunk/ui/src/input/plugins/joystick.py (working copy)
@@ -31,51 +31,56 @@
#
# -----------------------------------------------------------------------------
-import kaa.notifier
-
+# python imports
import sys
import os
import select
import struct
from time import sleep
-from freevo.ui import config
+# kaa imports
+import kaa.notifier
+
+# freevo imports
+from freevo.resources import ResourceHandler
+from freevo.ui import config, application
from interface import InputPlugin
+from freevo.ui.config import config
import logging
log = logging.getLogger('input')
-class PluginInterface(InputPlugin):
+class PluginInterface(InputPlugin, ResourceHandler):
# Hardcoded for now to make it work at the CeBIT. This needs to
# be a config variable.
-
- KEYMAP = {
- 'button 1' : 'PLAY',
- 'button 3' : 'STOP',
- 'button 5' : 'EXIT',
- 'button 7' : 'EXIT',
- 'button 8' : 'SELECT',
- 'button 6' : 'ENTER',
- 'up 2' : 'UP',
- 'down 2' : 'DOWN',
- 'left 2' : 'LEFT',
- 'right 2' : 'RIGHT' }
+ KEYMAP = {}
-
def __init__(self):
InputPlugin.__init__(self)
- # TODO: this needs to be a parameter to the plugin
- self.device_name = '/dev/input/js0'
+ self.config = config.input.plugin.joystick
+ self.device_name = self.config.device
+
+ blocked = self.get_resources('JOYSTICK')
+ if len(blocked) != 0:
+ # FIXME maybe different joysticks possible?
+ log.error("Joystick is allready used, can't start joystick plugin")
+ return
+
+ for mapping in self.config.events:
+ self.KEYMAP[mapping.input] = mapping.event
try:
self.joyfd = os.open(self.device_name, os.O_RDONLY|os.O_NONBLOCK)
except OSError:
- reason = 'Unable to open %s' % self.device_name
+# reason = 'Unable to open %s' % self.device_name
+ log.error('Could not open joystick interface (%s)'%self.device_name)
+ self.free_resources()
return
- kaa.notifier.SocketDispatcher(self.handle).register(self.joyfd)
+ self.socket_dispatcher = kaa.notifier.SocketDispatcher(self.handle)
+ self.socket_dispatcher.register(self.joyfd)
self.timer = kaa.notifier.OneShotTimer(self.axis)
self.movement = {}
self.events = {}
@@ -118,7 +123,7 @@
if button in self.KEYMAP:
self.post_key(self.KEYMAP[button])
return True
-
+
if data[2] == 2:
# stick, this is all very ugly!!!
@@ -145,3 +150,53 @@
self.events[button].append(data[1])
self.timer.start(0.1)
return True
+
+
+ def can_suspend(self):
+ """
+ Return true since the plugin can be suspended.
+ """
+ return True
+
+
+ def suspend(self):
+ """
+ Release the joystick that it can be used by others.
+ """
+ try:
+ self.timer.stop()
+ self.socket_dispatcher.unregister()
+ os.close(self.joyfd)
+ self.free_resources()
+ except OSError:
+ log.error('Could not close Filedescriptor for joystick')
+ return False
+ return True
+ log.info('Joystick plugin suspended.')
+
+
+
+ def resume(self):
+ """
+ Acquire Joystick to be used as a remote.
+ """
+ blocked = self.get_resources('JOYSTICK')
+ if blocked == False:
+ return False
+ elif len(blocked) != 0:
+ # FIXME maybe different joysticks possible?
+ log.error("Joystick is allready used, can't start joystick plugin")
+ return False
+
+ try:
+ self.joyfd = os.open(self.device_name, os.O_RDONLY|os.O_NONBLOCK)
+ except OSError:
+ log.error('Could not open joystick interface (%s)'%self.device_name)
+ return
+
+ self.socket_dispatcher.register(self.joyfd)
+ self.movement = {}
+ self.events = {}
+ self.timer.start(0.1)
+ log.info('Jostick plugin resumed')
+
Index: freevo_trunk/ui/src/input/plugins/config.cxml
===================================================================
--- freevo_trunk/ui/src/input/plugins/config.cxml (revision 9422)
+++ freevo_trunk/ui/src/input/plugins/config.cxml (working copy)
@@ -26,9 +26,25 @@
<group name="joystick" plugin="true">
<desc>
- Joystick plugin. This plugin defines a fixed mapping. If someone
- needs more, please send a patch using a config here.
+ Joystick plugin.
</desc>
+ <var name="device" type="str">
+ <desc>The Joystick input device for example /dev/input/js0</desc>
+ </var>
+ <list name="events">
+ <var name="event" type="str">
+ <desc>The event to send on this button/axis event. For
+ example EXIT, SELECT, UP, DOWN,...</desc>
+ </var>
+ <var name="input" type="str">
+ <desc>The input that raises the event. Example:
+ button 1 (for the first button no the joystick)
+ button 2 ...
+ up 0 (the first axis up)
+ down 1 (the second axis down)
+ </desc>
+ </var>
+ </list>
</group>
</config>
Index: freevo_trunk/ui/src/audio/player.py
===================================================================
--- freevo_trunk/ui/src/audio/player.py (revision 9422)
+++ freevo_trunk/ui/src/audio/player.py (working copy)
@@ -44,8 +44,8 @@
from freevo.ui.event import *
from freevo.ui.application import Application, STATUS_RUNNING, STATUS_STOPPING, \
- STATUS_STOPPED, STATUS_IDLE, CAPABILITY_TOGGLE, CAPABILITY_PAUSE, \
- CAPABILITY_FULLSCREEN
+ STATUS_STOPPED, STATUS_IDLE, CAPABILITY_TOGGLE, CAPABILITY_PAUSE, \
+ CAPABILITY_FULLSCREEN
# get logging object
log = logging.getLogger('audio')
@@ -66,6 +66,7 @@
"""
play an item
"""
+ retry = kaa.notifier.Callback(self.play, item)
if not self.status in (STATUS_IDLE, STATUS_STOPPED):
# Already running, stop the current player by sending a STOP
# event. The event will also get to the playlist behind the
@@ -73,7 +74,7 @@
Event(STOP, handler=self.eventhandler).post()
# Now connect to our own 'stop' signal once to repeat this current
# function call without the player playing
- self.signals['stop'].connect_once(self.play, item)
+ self.signals['stop'].connect_once(retry)
return True
if not kaa.notifier.running:
@@ -84,12 +85,11 @@
# Try to get AUDIO resource. The ressouce will be freed by the system
# when the application switches to STATUS_STOPPED or STATUS_IDLE.
blocked = self.get_resources('AUDIO')
- if 'AUDIO' in blocked:
- # Something has the audio resource blocked, stop it
- Event(STOP, handler=blocked['AUDIO'].eventhandler).post()
- # Now connect to the 'stop' signal once to repeat this current
- # function call without the player playing
- blocked['AUDIO'].signals['stop'].connect_once(self.play, item)
+ if blocked == False:
+ log.error("Can't get Audio resource.")
+ return False
+ elif len(blocked) != 0:
+ self.suspend_all(blocked, retry)
return True
# Store item and playlist. We need to keep the playlist object
@@ -141,41 +141,6 @@
self.status = STATUS_STOPPING
- @kaa.notifier.yield_execution()
- def pause(self):
- """
- Pause Playback. Return False if already paused.
- """
- # FIXME: make sure this function is not called twice
- if not self.status == STATUS_RUNNING:
- yield False
- if self.player.get_state() == kaa.popcorn.STATE_PAUSED:
- yield None
- # FIXME: what happens if we send pause() the same time the file
- # is finished? This would create a race condition.
- self.player.pause()
- yield kaa.notifier.YieldCallback(self.player.signals['pause'])
- self.free_resources()
-
-
- @kaa.notifier.yield_execution()
- def resume(self):
- """
- Resume Playback. Return False if already resumed.
- """
- # FIXME: make sure this function is not called twice
- if not self.status == STATUS_RUNNING:
- yield False
- if self.player.get_state() == kaa.popcorn.STATE_PLAYING:
- yield False
- if self.get_resources('AUDIO'):
- # FIXME: what to do in this case?
- log.error('unable to get AUDIO ressource')
- yield False
- self.player.resume()
- yield kaa.notifier.YieldCallback(self.player.signals['play'])
-
-
def elapsed(self):
"""
Callback for elapsed time changes.
@@ -216,7 +181,7 @@
if event in (PAUSE, PLAY):
if self.player.get_state() == kaa.popcorn.STATE_PLAYING:
- self.pause()
+ self.suspend()
return True
if self.player.get_state() == kaa.popcorn.STATE_PAUSED:
self.resume()
@@ -230,6 +195,52 @@
return self.item.eventhandler(event)
+ def can_suspend(self):
+ """
+ Return true since the application can be suspended.
+ """
+ return True
+
+ @kaa.notifier.yield_execution()
+ def suspend(self):
+ """
+ Release the audio resource that others can use it.
+ """
+ # FIXME: make sure this function is not called twice
+ if not self.status == STATUS_RUNNING:
+ yield False
+ if self.player.get_state() == kaa.popcorn.STATE_PAUSED:
+ yield None
+ # FIXME: what happens if we send pause() the same time the file
+ # is finished? This would create a race condition.
+ self.player.pause()
+ yield kaa.notifier.YieldCallback(self.player.signals['pause'])
+ self.free_resources()
+
+
+ @kaa.notifier.yield_execution()
+ def resume(self):
+ """
+ Resume playing the audio, at the position before.
+ """
+ # FIXME: make sure this function is not called twice
+ if not self.status == STATUS_RUNNING:
+ yield False
+ if self.player.get_state() == kaa.popcorn.STATE_PLAYING:
+ yield False
+ blocked = self.get_resources('AUDIO')
+ if blocked == False:
+ # FIXME: what to do in this case?
+ log.error('unable to get AUDIO ressource')
+ yield False
+ elif len(blocked) > 0:
+ self.suspend_all(blocked, self.resume)
+ # FIXME: return an YieldCallback
+ yield None
+ self.player.resume()
+ yield kaa.notifier.YieldCallback(self.player.signals['play'])
+
+
# create singleton object
player = kaa.utils.Singleton(Player)
Index: freevo_trunk/ui/src/application/base.py
===================================================================
--- freevo_trunk/ui/src/application/base.py (revision 9422)
+++ freevo_trunk/ui/src/application/base.py (working copy)
@@ -38,11 +38,11 @@
from kaa.notifier import Signal
# freevo imports
+from freevo.resources import ResourceHandler
from freevo.ui import gui
# application imports
from handler import handler
-from resources import get_resources, free_resources
# get logging object
log = logging.getLogger()
@@ -56,7 +56,7 @@
CAPABILITY_PAUSE = 2
CAPABILITY_FULLSCREEN = 4
-class Application(object):
+class Application(ResourceHandler):
"""
A basic application
"""
@@ -98,6 +98,7 @@
"""
if status in (STATUS_STOPPED, STATUS_IDLE):
self.free_resources()
+ self.resume_all()
if status == STATUS_RUNNING and self._status == STATUS_IDLE:
handler.show_application(self)
self._status = status
@@ -178,23 +179,6 @@
return self.__name
- def get_resources(self, *resources):
- """
- Reserve a list of resources. If one or more resources can not be
- reserved, the whole operation fails. The function will return the
- list of failed resources with the application having this resource.
- """
- return get_resources(self, *resources)
-
-
- def free_resources(self, *resources):
- """
- Free all resources blocked by this application. If not resources are
- provided, free all resources.
- """
- return free_resources(self, *resources)
-
-
def __repr__(self):
"""
String for debugging.
Index: freevo_trunk/ui/src/application/resources.py
===================================================================
--- freevo_trunk/ui/src/application/resources.py (revision 9422)
+++ freevo_trunk/ui/src/application/resources.py (working copy)
@@ -1,60 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-# -----------------------------------------------------------------------------
-# resources.py - Ressource Management
-# -----------------------------------------------------------------------------
-# $Id$
-#
-# -----------------------------------------------------------------------------
-# Freevo - A Home Theater PC framework
-# Copyright (C) 2007 Dirk Meyer, et al.
-#
-# First Edition: Dirk Meyer <[EMAIL PROTECTED]>
-# Maintainer: Dirk Meyer <[EMAIL PROTECTED]>
-#
-# Please see the file AUTHORS for a complete list of authors.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
-# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-# Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# -----------------------------------------------------------------------------
-
-_resources = {}
-
-def get_resources(instance, *resources):
- """
- Reserve a list of resources. If one or more resources can not be
- reserved, the whole operation fails. The function will return the
- list of failed resources with the instance having this resource.
- """
- blocked = {}
- for r in resources:
- if r in _resources:
- blocked[r] = _resources[r]
- if blocked:
- # failed to reserve
- return blocked
- # reserve all resources
- for r in resources:
- _resources[r] = instance
- return {}
-
-
-def free_resources(instance, *resources):
- """
- Free all resources blocked by the instance. If not resources are
- provided, free all resources.
- """
- for res, app in _resources.items()[:]:
- if app == instance and (not resources or res in resources):
- del _resources[res]
Index: freevo_trunk/ui/src/application/__init__.py
===================================================================
--- freevo_trunk/ui/src/application/__init__.py (revision 9422)
+++ freevo_trunk/ui/src/application/__init__.py (working copy)
@@ -29,7 +29,6 @@
#
# -----------------------------------------------------------------------------
-from resources import get_resources, free_resources
from base import Application, STATUS_RUNNING, STATUS_STOPPING, \
STATUS_STOPPED, STATUS_IDLE, CAPABILITY_TOGGLE, CAPABILITY_PAUSE, \
CAPABILITY_FULLSCREEN
Index: freevo_trunk/ui/src/video/player.py
===================================================================
--- freevo_trunk/ui/src/video/player.py (revision 9422)
+++ freevo_trunk/ui/src/video/player.py (working copy)
@@ -44,8 +44,8 @@
from freevo.ui.event import *
from freevo.ui.application import Application, STATUS_RUNNING, STATUS_STOPPING, \
- STATUS_STOPPED, STATUS_IDLE, CAPABILITY_TOGGLE, CAPABILITY_PAUSE, \
- CAPABILITY_FULLSCREEN
+ STATUS_STOPPED, STATUS_IDLE, CAPABILITY_TOGGLE, CAPABILITY_PAUSE, \
+ CAPABILITY_FULLSCREEN
# get logging object
log = logging.getLogger('video')
@@ -87,37 +87,12 @@
# by the system when the application switches to STATUS_STOPPED or
# STATUS_IDLE.
blocked = self.get_resources('AUDIO', 'VIDEO')
- if 'VIDEO' in blocked:
- # Something has the video resource blocked. The only application
- # possible is the tv player right now. It would be possible to
- # ask the user what to do with a popup but we assume the user
- # does not care about the tv and just stop it.
- Event(STOP, handler=blocked['VIDEO'].eventhandler).post()
- # Now connect to the 'stop' signal once to repeat this current
- # function call without the player playing
- blocked['VIDEO'].signals['stop'].connect_once(retry)
+ if blocked == False:
+ log.error("Can't get resource AUDIO, VIDEO")
+ return False
+ elif len(blocked) > 0:
+ self.suspend_all(blocked, retry)
return True
- if 'AUDIO' in blocked:
- # AUDIO is blocked, VIDEO is not. This is most likely the audio
- # player and we can pause it. Do this if possible.
- if not blocked['AUDIO'].has_capability(CAPABILITY_PAUSE):
- # Unable to pause, just stop it
- Event(STOP, handler=blocked['AUDIO'].eventhandler).post()
- # Now connect to the 'stop' signal once to repeat this current
- # function call without the player playing
- blocked['AUDIO'].signals['stop'].connect_once(retry)
- return True
- # Now pause the current player. On its pause signal this player can
- # play again. And on the stop signal of this player (STATUS_IDLE)
- # the other player can be resumed again.
- in_progress = blocked['AUDIO'].pause()
- if isinstance(in_progress, kaa.notifier.InProgress):
- # takes some time, wait
- in_progress.connect(retry).set_ignore_caller_args()
- if in_progress is not False:
- # we paused the application, resume on our stop
- self.signals['stop'].connect_once(blocked['AUDIO'].resume)
- return True
# store item and playlist
self.item = item
@@ -179,6 +154,44 @@
self.item.elapsed = round(self.player.get_position())
+ def can_suspend(self):
+ """
+ Return true since the video player can be suspended. It is more likely
+ to be stoped, but still it will release the resource.
+ """
+ return True
+
+ @kaa.notifier.yield_execution()
+ def suspend(self):
+ """
+ Release the audio and video resource.
+ """
+ if not self.status == STATUS_RUNNING:
+ yield False
+ if self.player.get_state == kaa.popcorn.STATE_PAUSED:
+ yield False
+ self.player.stop()
+ self.status = STATUS_STOPPING
+ yield kaa.notifier.YieldCallback(self.player.signals['stop'])
+ self.free_resources()
+ yield True
+
+
+ def resume(self):
+ """
+ Resume video. At the moment do nothing so video is only stoped, but
+ does not restart. TODO
+ """
+ if not self.status == STATUS_RUNNING:
+ return False
+ if self.player.get_state == kaa.popcorn.STATUS_RUNNING:
+ return False
+ # since we don't pause the video player we stop it restart everything
+ # that was running before.
+ self.resume_all()
+ return True
+
+
def eventhandler(self, event):
"""
React on some events or send them to the real player or the
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Freevo-devel mailing list
Freevo-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/freevo-devel