Package flumotion :: Package component :: Package producers :: Package soundcard :: Module soundcard
[hide private]

Source Code for Module flumotion.component.producers.soundcard.soundcard

  1  # -*- Mode: Python; test-case-name:flumotion.test.test_soundcard -*- 
  2  # vi:si:et:sw=4:sts=4:ts=4 
  3   
  4  # Flumotion - a streaming media server 
  5  # Copyright (C) 2004,2005,2006,2007,2008,2009 Fluendo, S.L. 
  6  # Copyright (C) 2010,2011 Flumotion Services, S.A. 
  7  # All rights reserved. 
  8  # 
  9  # This file may be distributed and/or modified under the terms of 
 10  # the GNU Lesser General Public License version 2.1 as published by 
 11  # the Free Software Foundation. 
 12  # This file is distributed without any warranty; without even the implied 
 13  # warranty of merchantability or fitness for a particular purpose. 
 14  # See "LICENSE.LGPL" in the source distribution for more information. 
 15  # 
 16  # Headers in this file shall remain intact. 
 17   
 18  import gst 
 19  import gst.interfaces 
 20   
 21  from twisted.internet import defer 
 22   
 23  from flumotion.common import messages 
 24  from flumotion.common.i18n import N_, gettexter 
 25  from flumotion.component import feedcomponent 
 26  from flumotion.component.effects.volume import volume 
 27   
 28  __version__ = "$Rev$" 
 29  T_ = gettexter() 
 30   
 31   
32 -class Soundcard(feedcomponent.ParseLaunchComponent):
33
34 - def do_check(self):
35 self.debug('running PyGTK/PyGST checks') 36 from flumotion.component.producers import checks 37 d1 = checks.checkTicket347() 38 d2 = checks.checkTicket348() 39 dl = defer.DeferredList([d1, d2]) 40 dl.addCallback(self._checkCallback) 41 return dl
42
43 - def _checkCallback(self, results):
44 for (state, result) in results: 45 for m in result.messages: 46 self.addMessage(m)
47
48 - def get_pipeline_string(self, properties):
49 element = properties.get('source-element', 'alsasrc') 50 self.device = properties.get('device', 'hw:0') 51 samplerate = properties.get('samplerate', 44100) 52 depth = properties.get('depth', 16) 53 channels = properties.get('channels', 2) 54 self.inputTrackLabel = properties.get('input-track', None) 55 d = self._change_monitor.add(gst.STATE_CHANGE_NULL_TO_READY) 56 d.addCallback(self._set_input_track, self.inputTrackLabel) 57 # FIXME: we should find a way to figure out what the card supports, 58 # so we can add in correct elements on the fly 59 # just adding audioscale and audioconvert always makes the soundcard 60 # open in 1000 Hz, mono 61 caps = 'audio/x-raw-int,rate=(int)%d,depth=%d,channels=%d' % ( 62 samplerate, depth, channels) 63 pipeline = "%s device=%s name=src ! %s ! " \ 64 "level name=volumelevel message=true" % ( 65 element, self.device, caps) 66 self._srcelement = None 67 return pipeline
68
69 - def configure_pipeline(self, pipeline, properties):
70 # add volume effect 71 comp_level = pipeline.get_by_name('volumelevel') 72 allowVolumeSet = True 73 if gst.pygst_version < (0, 10, 7): 74 allowVolumeSet = False 75 m = messages.Info(T_( 76 N_("The soundcard volume cannot be changed with this version " 77 "of the 'gst-python' library.\n")), 78 mid='mixer-track-setting') 79 m.add(T_(N_("Please upgrade '%s' to version %s or later " 80 "if you require this functionality."), 81 'gst-python', '0.10.7')) 82 self.addMessage(m) 83 84 vol = volume.Volume('inputVolume', comp_level, pipeline, 85 allowIncrease=False, allowVolumeSet=allowVolumeSet) 86 self.addEffect(vol) 87 self._srcelement = pipeline.get_by_name("src")
88
89 - def _set_input_track(self, result, trackLabel=None):
90 element = self._srcelement 91 for track in element.list_tracks(): 92 if trackLabel != None: 93 self.debug("Setting track %s to record", trackLabel) 94 # some low-end sound cards require the Capture track to be 95 # set to recording to get any sound, so set that track and 96 # the input track we selected 97 element.set_record(track, 98 (track.get_property("label") == trackLabel or 99 track.get_property("label") == "Capture"))
100
101 - def setVolume(self, value):
102 if gst.pygst_version < (0, 10, 7): 103 self.warning( 104 "Cannot set volume on soundcards with gst-python < 0.10.7") 105 return 106 self.debug("Volume set to: %f", value) 107 if self.inputTrackLabel and self._srcelement: 108 element = self._srcelement 109 volumeSet = False 110 for track in element.list_tracks(): 111 if track.get_property("label") == self.inputTrackLabel: 112 volumeVals = tuple(int(value/1.0 * 113 track.get_property("max-volume")) 114 for _ in xrange(0, track.get_property("num-channels"))) 115 element.set_volume(track, volumeVals) 116 volumeSet = True 117 break 118 if not volumeSet: 119 self.warning("could not find track %s", self.inputTrackLabel) 120 else: 121 self.warning("no input track selected, cannot set volume")
122
123 - def getVolume(self):
124 if gst.pygst_version < (0, 10, 7): 125 self.warning( 126 "Cannot query volume on soundcards with gst-python < 0.10.7") 127 return 1.0 128 if self.inputTrackLabel and self._srcelement: 129 element = self._srcelement 130 for track in element.list_tracks(): 131 if track.get_property("label") == self.inputTrackLabel: 132 volumeVals = element.get_volume(track) 133 vol = 0 134 nchannels = track.get_property("num-channels") 135 for k in range(0, track.get_property("num-channels")): 136 vol = vol + (volumeVals[k] / nchannels) 137 maxVolume = float(track.get_property('max-volume')) 138 self.debug("vol: %f max vol: %f", vol, maxVolume) 139 140 if maxVolume == 0.0: 141 return 1.0 142 143 v = vol / maxVolume 144 145 self.debug("v: %f", v) 146 return v 147 self.warning("could not find track %s", self.inputTrackLabel) 148 else: 149 self.warning("no input track selected, cannot set volume") 150 return 1.0
151
152 - def make_message_for_gstreamer_error(self, gerror, debug):
153 if gerror.domain == 'gst-resource-error-quark': 154 # before 0.10.14 gst-plugins-base had the error as WRITE by mistake 155 if gerror.code in [ 156 gst.RESOURCE_ERROR_OPEN_WRITE, 157 gst.RESOURCE_ERROR_OPEN_READ]: 158 m = messages.Error(T_(N_( 159 "Could not open sound device '%s'. " 160 "Please check permissions on the device."), 161 self.device), debug=debug) 162 return m 163 if gerror.code == gst.RESOURCE_ERROR_BUSY: 164 m = messages.Error(T_(N_( 165 "The sound device '%s' is in use by another program. " 166 "Please stop the other program and try again."), 167 self.device)) 168 return m 169 170 base = feedcomponent.ParseLaunchComponent 171 return base.make_message_for_gstreamer_error(self, gerror, debug)
172