wingo - in flumotion/trunk: . flumotion/component/combiners/switch
flumotion-commit at lists.fluendo.com
flumotion-commit at lists.fluendo.com
Tue Dec 18 17:48:51 CET 2007
Author: wingo
Date: Tue Dec 18 17:48:43 2007
New Revision: 6016
Modified:
flumotion/trunk/ChangeLog
flumotion/trunk/flumotion/component/combiners/switch/switch.py
Log:
* flumotion/component/combiners/switch/switch.py (Switch.init):
Remove self._started state variable -- subclasses should hack this
in if needed.
(Switch.configure_pipeline, Switch.install_logical_feed_watches)
(Switch.feedSetActive, Switch.feedSetInactive): Rework to provide
an activation api in terms of logical feeds instead of eaters, for
simpler client code.
(Switch.do_switch): Rename from try_switch(). Always succeed. The
caller is responsible for ensuring that the feed is active, if
necessary. Remove some comments fixed by improvements to the
switch gstreamer element.
Modified: flumotion/trunk/ChangeLog
==============================================================================
--- flumotion/trunk/ChangeLog (original)
+++ flumotion/trunk/ChangeLog Tue Dec 18 17:48:43 2007
@@ -1,5 +1,17 @@
2007-12-18 Andy Wingo <wingo at pobox.com>
+ * flumotion/component/combiners/switch/switch.py (Switch.init):
+ Remove self._started state variable -- subclasses should hack this
+ in if needed.
+ (Switch.configure_pipeline, Switch.install_logical_feed_watches)
+ (Switch.feedSetActive, Switch.feedSetInactive): Rework to provide
+ an activation api in terms of logical feeds instead of eaters, for
+ simpler client code.
+ (Switch.do_switch): Rename from try_switch(). Always succeed. The
+ caller is responsible for ensuring that the feed is active, if
+ necessary. Remove some comments fixed by improvements to the
+ switch gstreamer element.
+
* flumotion/component/component.py (BaseComponent._pollMemory): Be
less verbose.
Modified: flumotion/trunk/flumotion/component/combiners/switch/switch.py
==============================================================================
--- flumotion/trunk/flumotion/component/combiners/switch/switch.py (original)
+++ flumotion/trunk/flumotion/component/combiners/switch/switch.py Tue Dec 18 17:48:43 2007
@@ -86,9 +86,6 @@
self.uiState.addKey("active-eater")
self.icalScheduler = None
- # foo
- self._started = False
-
# This structure maps logical feeds to sets of eaters. For
# example, "master" and "backup" could be logical feeds, and
# would be the keys in this dict, mapping to lists of eater
@@ -98,6 +95,7 @@
#
# For example, {"master": ["audio-master", "video-master"],
# "backup": ["audio-backup", "video-backup"]}
+ # logical feed name -> [eater alias]
self.logicalFeeds = {}
# eater alias -> (sink pad, switch element)
@@ -174,11 +172,30 @@
self.debug('eater %s maps to pad %s', alias, pad)
self.switchPads[alias] = pad, e
- for alias in self.eaters:
- self.eaters[alias].addWatch(self.eaterSetActive,
- self.eaterSetInactive)
+ self.install_logical_feed_watches()
+
+ self.do_switch()
- self.try_switch(checkActive=False)
+ def install_logical_feed_watches(self):
+ def eaterSetActive(eaterAlias):
+ for feed, aliases in self.logicalFeeds.items():
+ if eaterAlias in aliases:
+ if feed not in activeFeeds:
+ activeFeeds.append(feed)
+ self.feedSetActive(feed)
+ return
+
+ def eaterSetInactive(eaterAlias):
+ for feed, aliases in self.logicalFeeds.items():
+ if eaterAlias in aliases:
+ if feed in activeFeeds:
+ activeFeeds.remove(feed)
+ self.feedSetInactive(feed)
+ return
+
+ activeFeeds = []
+ for alias in self.eaters:
+ self.eaters[alias].addWatch(eaterSetActive, eaterSetInactive)
def get_switch_elements(self, pipeline):
raise errors.NotImplementedError('subclasses should implement '
@@ -189,23 +206,13 @@
return all([self.eaters[alias].isActive()
for alias in self.logicalFeeds[feed]])
- def do_pipeline_playing(self):
- feedcomponent.MultiInputParseLaunchComponent.do_pipeline_playing(self)
- # needed to stop the flapping between master and backup on startup
- # in the watchdogs if the starting state is backup
- self._started = True
-
- def eaterSetActive(self, eaterAlias):
- if not self._started and moods.get(self.getMood()) == moods.happy:
- # need to just set _started to True if False and mood is happy
- # FIXME: why?
- self._started = True
+ def feedSetActive(self, feed):
+ self.debug('feed %r is now active', feed)
+ if feed == self.idealFeed:
+ self.do_switch()
- if self.activeFeed != self.idealFeed:
- self.try_switch()
-
- def eaterSetInactive(self, eaterAlias):
- pass
+ def feedSetInactive(self, feed):
+ self.debug('feed %r is now inactive', feed)
def switch_to(self, feed):
"""
@@ -221,38 +228,27 @@
if not self.pipeline:
return
- success = self.try_switch()
- if not success:
+ if self.is_active(feed):
+ self.do_switch()
+ else:
fmt = N_("Tried to switch to %s, but feed is unavailable. "
"Will retry when the feed is back.")
self.addWarning("temporary-switch-problem", fmt, feed)
- # So switching multiple eaters is not that easy.
- #
- # We have to make sure the current segment on both the switch
- # elements has the same stop value, and the next segment on both to
- # have the same start value to maintain sync.
- #
- # In order to do this:
- # 1) we need to block the switch from processing more data
- # 2) we need to query the last_stop on all stream segments of the
- # previously active stream, and take the maximum to set as the
- # stop_time of the old segments
- # 3) we need to query the last_stop on all stream segments of the
- # new stream, and take the minimum to set as the start_time of
- # the new segments
- # 4) tell the switches to switch, with the stop_time and start_time
+ # Switching multiple eaters is easy. The only trick is that we have
+ # to close the previous segment at the same running time, on both
+ # switch elements, and open the new segment at the same running
+ # time. The block()/switch() signal API on switch elements lets us
+ # do this. See the docs for switch's `block' and `switch' signals
+ # for more information.
- def try_switch(self, checkActive=True):
+ def do_switch(self):
feed = self.idealFeed
+ self.clearWarning('temporary-switch-problem')
if feed == self.activeFeed:
- self.debug("feed %s is already active", feed)
- self.clearWarning('temporary-switch-problem')
- return True
-
- if checkActive and not self.is_active(feed):
- return False
+ self.debug("already streaming from feed %r", feed)
+ return
# (pad, switch)
pairs = [self.switchPads[alias]
@@ -261,14 +257,6 @@
stop_times = [e.emit('block') for p, e in pairs]
start_times = [p.get_property('running-time') for p, e in pairs]
- # FIXME: I don't know what to do if we get a GST_CLOCK_TIME_NONE
- # for one of the stop_times. E.g. if we get audio data but no
- # video data. The two options would be (1) to open and close
- # e.g. a video segment of equal extent to the audio segment, or
- # to (2) not open and close a video segment, relying on the
- # future segment setting things right. (1) would certainly be
- # correct, but (2) might be fine also.
-
stop_time = max(stop_times)
self.debug('stop time = %d', stop_time)
self.debug('stop time = %s', gst.TIME_ARGS(stop_time))
@@ -281,9 +269,6 @@
self.addWarning('large-timestamp-difference', fmt,
feed, diff / gst.SECOND, priority=40)
- # FIXME: I don't know what to do if we get a GST_CLOCK_TIME_NONE
- # in the start_times. For now I am punting on this one. Yick.
-
start_time = min(start_times)
self.debug('start time = %s', gst.TIME_ARGS(start_time))
@@ -293,7 +278,6 @@
self.activeFeed = feed
self.uiState.set("active-eater", feed)
- return True
class SingleSwitch(Switch):
logCategory = "single-switch"
More information about the flumotion-commit
mailing list