gstlal  1.4.1
simplehandler.py
1 # Copyright (C) 2009--2013 Kipp Cannon, Chad Hanna, Drew Keppel
2 #
3 # This program is free software; you can redistribute it and/or modify it
4 # under the terms of the GNU General Public License as published by the
5 # Free Software Foundation; either version 2 of the License, or (at your
6 # option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful, but
9 # WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
11 # Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License along
14 # with this program; if not, write to the Free Software Foundation, Inc.,
15 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 
17 
18 #
19 # =============================================================================
20 #
21 # Preamble
22 #
23 # =============================================================================
24 #
25 
26 
27 import sys
28 import os
29 
30 
31 import gi
32 gi.require_version('Gst', '1.0')
33 from gi.repository import Gst
34 Gst.init(None)
35 import signal
36 
37 __doc__="""
38 
39 **Review Status**
40 
41 +-------------------------------------------------+------------------------------------------+------------+
42 | Names | Hash | Date |
43 +=================================================+==========================================+============+
44 | Florent, Sathya, Duncan Me., Jolien, Kipp, Chad | b3ef077fe87b597578000f140e4aa780f3a227aa | 2014-05-01 |
45 +-------------------------------------------------+------------------------------------------+------------+
46 
47 """
48 
49 
50 #
51 # =============================================================================
52 #
53 # Pipeline Handler
54 #
55 # =============================================================================
56 #
57 
58 
59 class Handler(object):
60  """
61  A simple handler that prints pipeline error messages to stderr, and
62  stops the pipeline and terminates the mainloop at EOS. Complex
63  applications will need to write their own pipeline handler, but for
64  most simple applications this will suffice, and it's easier than
65  copy-and-pasting this all over the place.
66  """
67  def __init__(self, mainloop, pipeline):
68  self.mainloop = mainloop
69  self.pipeline = pipeline
70 
71  bus = pipeline.get_bus()
72  bus.add_signal_watch()
73  self.on_message_handler_id = bus.connect("message", self.on_message)
74 
75  def excepthook(*args):
76  # system exception hook that forces hard exit. without this,
77  # exceptions that occur inside python code invoked as a call-back
78  # from the gstreamer pipeline just stop the pipeline, they don't
79  # cause gstreamer to exit.
80 
81  # FIXME: they probably *would* cause if we could figure out why
82  # element errors and the like simply stop the pipeline instead of
83  # crashing it, as well. Perhaps this should be removed when/if the
84  # "element error's don't crash program" problem is fixed
85  sys.__excepthook__(*args)
86  os._exit(1)
87 
88  sys.excepthook = excepthook
89 
90 
91  def quit(self, bus):
92  """
93  Decouple this object from the Bus object to allow the Bus'
94  reference count to drop to 0, and .quit() the mainloop
95  object. This method is invoked by the default EOS and
96  ERROR message handlers.
97  """
98  bus.disconnect(self.on_message_handler_id)
99  del self.on_message_handler_id
100  bus.remove_signal_watch()
101  self.mainloop.quit()
102 
103  def do_on_message(self, bus, message):
104  """
105  Add extra message handling by overriding this in your
106  subclass. If this method returns True, no further message
107  handling is performed. If this method returns False,
108  message handling continues with default cases or EOS, INFO,
109  WARNING and ERROR messages.
110  """
111  return False
112 
113  def on_message(self, bus, message):
114  if self.do_on_message(bus, message):
115  pass
116  elif message.type == Gst.MessageType.EOS:
117  self.pipeline.set_state(Gst.State.NULL)
118  self.quit(bus)
119  elif message.type == Gst.MessageType.INFO:
120  gerr, dbgmsg = message.parse_info()
121  print >>sys.stderr, "info (%s:%d '%s'): %s" % (gerr.domain, gerr.code, gerr.message, dbgmsg)
122  elif message.type == Gst.MessageType.WARNING:
123  gerr, dbgmsg = message.parse_warning()
124  print >>sys.stderr, "warning (%s:%d '%s'): %s" % (gerr.domain, gerr.code, gerr.message, dbgmsg)
125  elif message.type == Gst.MessageType.ERROR:
126  gerr, dbgmsg = message.parse_error()
127  # FIXME: this deadlocks. shouldn't we be doing this?
128  #self.pipeline.set_state(gst.STATE_NULL)
129  self.quit(bus)
130  sys.exit("error (%s:%d '%s'): %s" % (gerr.domain, gerr.code, gerr.message, dbgmsg))
131 
132 
133 class OneTimeSignalHandler(object):
134  """
135  A helper class for application signal handling. Use this to help your
136  application to cleanly shutdown gstreamer pipelines when responding to e.g.,
137  ctrl+c.
138  """
139  def __init__(self, pipeline, signals = [signal.SIGINT, signal.SIGTERM]):
140  self.pipeline = pipeline
141  self.count = 0
142  for sig in signals:
143  signal.signal(sig, self)
144 
145  def do_on_call(self, signum, frame):
146  """
147  Over ride this for your subclass
148  """
149  pass
150 
151  def __call__(self, signum, frame):
152  self.count += 1
153  if self.count == 1:
154  print >>sys.stderr, "*** SIG %d attempting graceful shutdown (this might take several minutes) ... ***" % signum
155  try:
156  self.do_on_call(signum, frame)
157  if not self.pipeline.send_event(Gst.Event.new_eos()):
158  raise Exception("pipeline.send_event(EOS) returned failure")
159  except Exception, e:
160  print >>sys.stderr, "graceful shutdown failed: %s\naborting." % str(e)
161  os._exit(1)
162  else:
163  print >>sys.stderr, "*** received SIG %d %d times... ***" % (signum, self.count)
def do_on_message(self, bus, message)
def on_message(self, bus, message)