def checkTicket347(): """ Check for a recent enough PyGTK to not leak python integers in message processing (mostly affects soundcard, firewire) """ result = messages.Result() import pygtk pygtk.require('2.0') import gobject # Really, we want to check for pygobject_version, but that doesn't exist in # all versions of pygtk, and this check is sufficient. (major, minor, nano) = gobject.pygtk_version if (major, minor, nano) < (2, 8, 6): m = messages.Warning(T_( N_("Version %d.%d.%d of the PyGTK library contains " "a memory leak.\n"), major, minor, nano), mid='ticket-347') m.add( T_( N_("The Soundcard and Firewire sources may leak a lot of " "memory as a result, and would need to be restarted " "frequently.\n"))) m.add( T_(N_("Please upgrade '%s' to version %s or later."), 'pygtk', '2.8.6')) result.add(m) result.succeed(None) return defer.succeed(result)
def haveResult(res): if not termtimeout.active(): self.info("Discarding error %s", res) res = messages.Result() res.add( messages.Error(T_(N_("Check timed out.")), debug=("Timed out running %s." % methodName))) else: def expire(): if (job, expireDC) in self.jobPool: self.debug('stopping idle check job process %s', job.avatarId) self.jobPool.remove((job, expireDC)) job.mindCallRemote('stop') expireDC = reactor.callLater(self._timeout, expire) self.jobPool.append((job, expireDC)) if termtimeout.active(): termtimeout.cancel() if killtimeout.active(): killtimeout.cancel() return res
def checkPlugin(pluginName, packageName, minimumVersion=None, featureName=None, featureCheck=None): """ Check if the given plug-in is available. Return a result with an error if it is not, or not new enough. @param pluginName: name of the plugin to check @param packageName: name of the package to tell the user to install if the check fails @param minimumVersion: minimum version of the plugin, as a tuple. Optional. @param featureName: name of a specific feature to check for in the plugin. Optional. Overrides the minimum version check, if given. @param featureCheck: function to call on the found feature, which should return a boolean representing whether the feature is good or not. Optional, and only makes sense if you specify featureName. @rtype: L{messages.Result} """ result = messages.Result() version = gstreamer.get_plugin_version(pluginName) if not version: m = messages.Error(T_( N_("This host is missing the '%s' GStreamer plug-in.\n"), pluginName)) m.add(T_(N_( "Please install '%s'.\n"), packageName)) documentation.messageAddGStreamerInstall(m) result.add(m) elif featureName: r = gst.registry_get_default() features = r.get_feature_list_by_plugin(pluginName) byname = dict([(f.get_name(), f) for f in features]) if (featureName not in byname or (featureCheck and not featureCheck(byname[featureName]))): m = messages.Error(T_( N_("Your '%s' GStreamer plug-in is too old.\n"), pluginName), mid = 'plugin-%s-check' % pluginName) m.add(T_(N_( "Please upgrade '%s' to version %s or higher."), packageName, ".".join([str(x) for x in minimumVersion]))) documentation.messageAddGStreamerInstall(m) result.add(m) elif version < minimumVersion: m = messages.Error(T_( N_("Version %s of the '%s' GStreamer plug-in is too old.\n"), ".".join([str(x) for x in version]), pluginName), mid = 'plugin-%s-check' % pluginName) m.add(T_(N_( "Please upgrade '%s' to version %s."), packageName, ".".join([str(x) for x in minimumVersion]))) documentation.messageAddGStreamerInstall(m) result.add(m) result.succeed(None) return defer.succeed(result)
def testSerializeWithError(self): wresult = messages.Result() wresult.add(messages.Error(T_(N_("uh oh")))) mresult = jelly.unjelly(jelly.jelly(wresult)) self.failUnless(mresult.failed) self.assertEquals(mresult.value, None) m = mresult.messages[0] self.assertEquals(m.level, messages.ERROR) text = self.translator.translate( m, lang=["nl_NL", ]) self.assertEquals(text, "o jeetje")
def testSerializeWithWarning(self): wresult = messages.Result() wresult.add(messages.Warning(T_(N_("Warning")))) wresult.succeed("I did it") mresult = jelly.unjelly(jelly.jelly(wresult)) self.failIf(mresult.failed) self.assertEquals(mresult.value, "I did it") m = mresult.messages[0] self.assertEquals(m.level, messages.WARNING) text = self.translator.translate( m, lang=["nl_NL", ]) self.assertEquals(text, "Waarschuwing")
def checkFile(filePath): """ Checks if a path is a file. @param filePath : The path of the file @type filePath : str @returns : True if filePath exists and is a file, False otherwise. @rtype : L{messages.Result} """ log.debug('check', 'checkFile: %s', filePath) result = messages.Result() result.succeed(os.path.isfile(filePath)) return result
def checkDirectory(pathName): """ Check if a path is a directory and that it is readable and executable @param pathName: path to check @type pathName: string @returns: if the path is a directory and readable @rtype: L{messages.Result} """ result = messages.Result() succeeded = False if (os.path.isdir(pathName) and os.access(pathName, os.R_OK|os.X_OK)): succeeded = True result.succeed(succeeded) return result
def checkTheora(): """ Check for a recent enough Theora encoder. """ result = messages.Result() version = gstreamer.get_plugin_version('theora') if version >= (0, 10, 0, 0) and version < (0, 10, 3, 0): m = messages.Warning(T_( N_("Version %s of the '%s' GStreamer plug-in contains a bug.\n"), string.join([str(x) for x in version], '.'), 'theora'), mid='theora-check') m.add(T_(N_( "Synchronization between audio and video may not be correct.\n"))) m.add(T_(N_( "Please upgrade '%s' to version %s."), 'gst-plugins-base', '0.10.3')) result.add(m) result.succeed(None) return defer.succeed(result)
def discovered(dcv, ismedia): result = messages.Result() if not ismedia: result.succeed((False, None)) return d.callback(result) if mimetype and not (mimetype in dcv.mimetype): result.succeed((False, None)) return d.callback(result) if not dcv.is_audio and audio: result.succeed((False, None)) return d.callback(result) properties = dict() if video: if not dcv.is_video or not dcv.videorate: result.succeed((False, None)) return d.callback(result) properties['width'] = dcv.videowidth properties['height'] = dcv.videoheight properties['framerate'] = (float(dcv.videorate.num) / dcv.videorate.denom) result.succeed((True, properties)) return d.callback(result)
def checkOgg(): """ Check for a recent enough Ogg muxer. """ result = messages.Result() version = gstreamer.get_plugin_version('ogg') if version >= (0, 10, 3, 0) and version < (0, 10, 4, 0): m = messages.Warning(T_( N_("Version %s of the '%s' GStreamer plug-in contains a bug.\n"), string.join([str(x) for x in version], '.'), 'ogg'), mid='ogg-check') m.add( T_( N_("The generated Ogg stream will not be fully compliant, " "and might not even play correctly.\n"))) m.add( T_(N_("Please upgrade '%s' to version %s."), 'gst-plugins-base', '0.10.4')) result.add(m) result.succeed(None) return defer.succeed(result)
def checkTicket348(): result = messages.Result() import pygst pygst.require('0.10') import gst (major, minor, nano) = gst.pygst_version if (major, minor, nano) < (0, 10, 3): m = messages.Warning(T_( N_("Version %d.%d.%d of the gst-python library contains " "a large memory leak.\n"), major, minor, nano), mid='ticket-348') m.add( T_( N_("The Soundcard and Firewire sources may leak a lot of " "memory as a result, and need to be restarted frequently.\n" ))) m.add( T_(N_("Please upgrade '%s' to version %s or later."), 'gst-python', '0.10.3')) result.add(m) result.succeed(None) return defer.succeed(result)
def checkTVCard(device, mid='check-tvcard'): """ Probe the given device node as a TV card. Return a deferred firing a human-readable device name, a list of channel names (Tuner/Composite/...), and a list of norms (PAL/NTSC/SECAM/...). @rtype: L{twisted.internet.defer.Deferred} """ result = messages.Result() def get_name_channels_norms(element): deviceName = element.get_property('device-name') channels = [channel.label for channel in element.list_channels()] norms = [norm.label for norm in element.list_norms()] return (deviceName, channels, norms) pipeline = 'v4lsrc name=source device=%s ! fakesink' % device d = do_element_check(pipeline, 'source', get_name_channels_norms) d.addCallback(check.callbackResult, result) d.addErrback(check.errbackNotFoundResult, result, mid, device) d.addErrback(check.errbackResult, result, mid, device) return d
def checkTicket349(): result = messages.Result() import pygst pygst.require('0.10') import gst if get_gst_version(gst) < (0, 10, 4, 1): major, minor, micro, nano = get_gst_version(gst) m = messages.Error(T_( N_("Version %d.%d.%d of the GStreamer library is too old.\n"), major, minor, micro), mid='ticket-349') m.add( T_(N_("The '%s' component needs a newer version of '%s'.\n"), 'looper', 'gstreamer')) m.add( T_(N_("Please upgrade '%s' to version %s or later."), 'gstreamer', '0.10.5')) result.add(m) if get_pygst_version(gst) < (0, 10, 3, 1): major, minor, micro, nano = get_pygst_version(gst) m = messages.Error(T_( N_("Version %d.%d.%d of the gst-python library is too old.\n"), major, minor, micro), mid='ticket-349') m.add( T_(N_("The '%s' component needs a newer version of '%s'.\n"), 'looper', 'gst-python')) m.add( T_(N_("Please upgrade '%s' to version %s or later."), 'gst-python', '0.10.4')) result.add(m) result.succeed(None) return defer.succeed(result)
def checkTicket1344(): """ Check if the version of oggmux is the one that can create borked ogg files. Note: this also checks for a problem with gdppay reported in #1341. """ result = messages.Result() if gstreamer.get_plugin_version('ogg') == (0, 10, 24, 0): m = messages.Warning(T_( N_("Version %s of the '%s' GStreamer plug-ins set " "contains various bugs.\n"), '0.10.24', 'gst-plugins-base'), mid='oggmux-check') m.add( T_( N_("They are regressions introduced in %s and will be " "fixed in %s.\n"), '0.10.24', '0.10.25')) m.add(T_(N_("The component will probably never go to happy.\n"))) m.add( T_(N_("Please use a different version of %s instead."), 'gst-plugins-base')) result.add(m) result.succeed(None) return defer.succeed(result)
def fetchDevices(mid, factories, parameter): """ Fetches the available devices on the system according to the specified factories. If the first factory succeeds the other are ignored. The result is either: - succesful, with a list of tuples with guid and device-name - succesful, with an error - failed @param mid: the id to set on the message. @param factories: The gstreamer elements to check @type factories: L{str} @param parameter: The parameter that specifies the device @type parameter: str @rtype: L{twisted.internet.defer.Deferred} of L{flumotion.common.messages.Result} """ result = messages.Result() factory = factories.pop() try: element = gst.element_factory_make(factory) except gst.ElementNotFoundError: element = None if not element: log.debug("device-check", "Could not instantiate the %s factory.", factory) if not factories: log.debug("device-check", "No more factories were specified.") m = messages.Error(T_( N_("GStreamer error, %s factory could not be found.\n" "Maybe the plugin is not properly installed.")), mid=mid) result.add(m) return defer.succeed(result) else: return fetchDevices(mid, factories, parameter) element.probe_property_name(parameter) values = element.probe_get_values_name(parameter) pipeline_str = "%s name=source %s" % (factory, parameter) pipeline_str += "=%s ! fakesink" devices = [] for value in values: pipeline = gst.parse_launch(pipeline_str % value) pipeline.set_state(gst.STATE_READY) source = pipeline.get_by_name("source") name = source.get_property("device-name") log.debug("device-check", "New device found: %s with values=%s", name, value) devices.append((name, value)) pipeline.set_state(gst.STATE_NULL) if devices: result.succeed(devices) return defer.succeed(result) else: log.debug("device-check", "No devices were found using %s factory.", factory) if factories: return fetchDevices(mid, factories, parameter) else: m = messages.Error(T_(N_("No devices were found for %s."), factory), mid=mid) result.add(m) return defer.succeed(result)
def checkMixerTracks(source_factory, device, mid=None): """ Probe the given GStreamer element factory with the given device for audio mixer tracks. Return a deferred firing a result. The result is either: - succesful, with a None value: no device found - succesful, with a human-readable device name and a list of mixer track labels. - failed @rtype: L{twisted.internet.defer.Deferred} """ result = messages.Result() def get_tracks(element): # Only mixers have list_tracks. Why is this a perm error? FIXME in 0.9? if not element.implements_interface(gst.interfaces.Mixer): msg = 'Cannot get mixer tracks from the device. '\ 'Check permissions on the mixer device.' log.debug('checks', "returning failure: %s" % msg) raise check.CheckProcError(msg) devName = element.get_property('device-name') tracks = [track.label for track in element.list_tracks()] structs = [] for structure in element.get_pad('src').get_caps(): structDict = dict(structure) for key, value in structDict.items()[:]: # Filter items which are not serializable over pb if isinstance(value, gst.IntRange): structDict[key] = (value.high, value.low) structs.append(structDict) return (devName, tracks, structs) def errbackAlsaBugResult(failure, result, mid, device): # alsasrc in gst-plugins-base <= 0.10.14 was accidentally reporting # GST_RESOURCE_ERROR_WRITE when it could not be opened for reading. if not failure.check(errors.GStreamerGstError): return failure if source_factory != 'alsasrc': return failure version = gstreamer.get_plugin_version('alsasrc') if version > (0, 10, 14): return failure source, gerror, debug = failure.value.args log.debug( 'check', 'GStreamer GError: %s (domain %s, code %d, debug %s)' % (gerror.message, gerror.domain, gerror.code, debug)) if gerror.domain == "gst-resource-error-quark": if gerror.code == int(gst.RESOURCE_ERROR_OPEN_WRITE): m = messages.Error( T_( N_("Could not open device '%s' for reading. " "Check permissions on the device."), device)) result.add(m) return result return failure pipeline = ('%s name=source device=%s ! fakesink') % (source_factory, device) d = do_element_check(pipeline, 'source', get_tracks, set_state_deferred=True) d.addCallback(check.callbackResult, result) d.addErrback(check.errbackNotFoundResult, result, mid, device) d.addErrback(errbackAlsaBugResult, result, mid, device) d.addErrback(check.errbackResult, result, mid, device) return d
def getAudioDevices(source_factory, mid=None): """ Search the available devices in worker for the specified factory. Return a deferred firing a result. The result is either: - succesful, with an empty list: no device found - succesful, with the list of found devices - failed @rtype: L{twisted.internet.defer.Deferred} """ result = messages.Result() devices = [] def getOssDevices(): bus = dbus.SystemBus() hal = dbus.Interface( bus.get_object('org.freedesktop.Hal', '/org/freedesktop/Hal/Manager'), 'org.freedesktop.Hal.Manager') udis = hal.FindDeviceStringMatch('oss.type', 'pcm') for udi in udis: dev = dbus.Interface(bus.get_object('org.freedesktop.Hal', udi), 'org.freedesktop.Hal.Device') if not dev.PropertyExists('oss.device'): continue if dev.GetProperty('oss.device') != 0: continue devices.append((str(dev.GetProperty('info.product')), str(dev.GetProperty('oss.device_file')))) def getAlsaDevices(): source = gst.element_factory_make('alsasrc') pipeline = 'alsasrc name=source device=%s ! fakesink' for device in source.probe_get_values_name('device'): p = gst.parse_launch(pipeline % device) p.set_state(gst.STATE_READY) s = p.get_by_name('source') devices.append( (s.get_property('device-name'), device.split(',')[0])) p.set_state(gst.STATE_NULL) try: {'alsasrc': getAlsaDevices, 'osssrc': getOssDevices}[source_factory]() except dbus.DBusException: devices = [("/dev/dsp", "/dev/dsp"), ("/dev/dsp1", "/dev/dsp1"), ("/dev/dsp2", "/dev/dsp2")] result.succeed(devices) failure = defer.failure.Failure() m = messages.Warning(T_( N_("There has been an error while fetching the OSS audio devices " "through Hal.\nThe listed devices have been guessed and may " "not work properly.")), debug=check.debugFailure(failure)) m.id = mid result.add(m) return defer.succeed(result) except: failure = defer.failure.Failure() log.debug( 'check', 'unhandled failure: %r (%s)\nTraceback:\n%s' % (failure, failure.getErrorMessage(), failure.getTraceback())) m = messages.Error(T_(N_("Could not probe devices.")), debug=check.debugFailure(failure)) m.id = mid result.add(m) return defer.fail(result) else: result.succeed(devices) if not devices: m = messages.Error( T_( N_("Could not find any device in the system.\n" "Please check whether the device is correctly plugged " "in and whether the modules are correctly loaded."))) m.id = mid result.add(m) return defer.succeed(result)
def checkWebcam(device, mid): """ Probe the given device node as a webcam. The result is either: - succesful, with a None value: no device found - succesful, with a tuple: - device name - dict of mime, format, width, height, fps pair - failed @rtype: L{flumotion.common.messages.Result} """ # FIXME: add code that checks permissions and ownership on errors, # so that we can offer helpful hints on what to do. def probeDevice(element): caps = element.get_pad("src").get_caps() log.debug('check', 'caps: %s' % caps.to_string()) sizes = {} # (width, height) => [{'framerate': (framerate_num, # framerate_denom), # 'mime': str, # 'fourcc': fourcc}] def forAllStructValues(struct, key, proc): vals = struct[key] if isinstance(vals, list): for val in vals: proc(struct, val) elif isinstance(vals, gst.IntRange): val = vals.low while val < vals.high: proc(struct, val) val *= 2 proc(struct, vals.high) elif isinstance(vals, gst.DoubleRange): # hack :) proc(struct, vals.high) elif isinstance(vals, gst.FractionRange): # hack :) val = vals.low while float(val) < float(vals.high): proc(struct, val) val.num += 5 proc(struct, vals.high) else: # scalar proc(struct, vals) def addRatesForWidth(struct, width): def addRatesForHeight(struct, height): def addRate(struct, rate): if not rate.num: return if (width, height) not in sizes: sizes[(width, height)] = [] d = { 'framerate': (rate.num, rate.denom), 'mime': struct.get_name() } if 'yuv' in d['mime']: d['format'] = struct['format'].fourcc sizes[(width, height)].append(d) forAllStructValues(struct, 'framerate', addRate) forAllStructValues(struct, 'height', addRatesForHeight) for struct in caps: if 'yuv' not in struct.get_name(): continue forAllStructValues(struct, 'width', addRatesForWidth) return (element.get_factory().get_name(), sizes) def tryV4L2(): log.debug('webcam', 'trying v4l2') version = gstreamer.get_plugin_version('video4linux2') minVersion = (0, 10, 5, 1) if not version or version < minVersion: log.info('webcam', 'v4l2 version %r too old (need >=%r)', version, minVersion) return defer.fail(NotImplementedError()) pipeline = 'v4l2src name=source device=%s ! fakesink' % (device, ) d = do_element_check(pipeline, 'source', probeDevice, state=gst.STATE_PAUSED, set_state_deferred=True) return d def tryV4L1(_): log.debug('webcam', 'trying v4l1') pipeline = 'v4lsrc name=source device=%s ! fakesink' % (device, ) d = do_element_check(pipeline, 'source', probeDevice, state=gst.STATE_PAUSED, set_state_deferred=True) return d result = messages.Result() d = tryV4L2() d.addErrback(tryV4L1) d.addCallback(check.callbackResult, result) d.addErrback(check.errbackNotFoundResult, result, mid, device) d.addErrback(check.errbackResult, result, mid, device) return d
def check1394(mid, guid): """ Probe the firewire device. Return a deferred firing a result. The result is either: - succesful, with a None value: no device found - succesful, with a dictionary of width, height, and par as a num/den pair - failed @param mid: the id to set on the message. @param guid: the id of the selected device. @rtype: L{twisted.internet.defer.Deferred} of L{flumotion.common.messages.Result} """ result = messages.Result() def do_check(demux): pad = demux.get_pad('video') if not pad or pad.get_negotiated_caps() == None: raise errors.GStreamerError('Pipeline failed to negotiate?') caps = pad.get_negotiated_caps() s = caps.get_structure(0) w = s['width'] h = s['height'] par = s['pixel-aspect-ratio'] # FIXME: not a good idea to reuse the result name which # also exists in the parent context. # pychecker should warn; however it looks like # the parent result doesn't get stored as name, # but instead with STORE_DEREF result = dict(width=w, height=h, par=(par.num, par.denom)) log.debug('check', 'returning dict %r' % result) return result pipeline = \ 'dv1394src guid=%s ! dvdemux name=demux .video ! fakesink' % guid d = do_element_check(pipeline, 'demux', do_check) def errbackResult(failure): log.debug('check', 'returning failed Result, %r' % failure) m = None if failure.check(errors.GStreamerGstError): source, gerror, debug = failure.value.args log.debug( 'check', 'GStreamer GError: %s (debug: %s)' % (gerror.message, debug)) if gerror.domain == "gst-resource-error-quark": if gerror.code == int(gst.RESOURCE_ERROR_NOT_FOUND): # dv1394src was fixed after gst-plugins-good 0.10.2 # to distinguish NOT_FOUND and OPEN_READ version = gstreamer.get_plugin_version('1394') if version >= (0, 10, 0, 0) and version <= (0, 10, 2, 0): m = messages.Error( T_( N_("Could not find or open the Firewire device. " "Check the device node and its permissions." ))) else: m = messages.Error(T_(N_("No Firewire device found."))) elif gerror.code == int(gst.RESOURCE_ERROR_OPEN_READ): m = messages.Error( T_( N_("Could not open Firewire device for reading. " "Check permissions on the device."))) if not m: m = check.handleGStreamerDeviceError(failure, 'Firewire', mid=mid) if not m: m = messages.Error(T_(N_("Could not probe Firewire device.")), debug=check.debugFailure(failure)) m.id = mid result.add(m) return result d.addCallback(check.callbackResult, result) d.addErrback(errbackResult) return d