Package x2go :: Module pulseaudio
[frames] | no frames]

Source Code for Module x2go.pulseaudio

  1  # -*- coding: utf-8 -*- 
  2   
  3  # Copyright (C) 2010-2014 by Mike Gabriel <mike.gabriel@das-netzwerkteam.de> 
  4  # 
  5  # Python X2Go is free software; you can redistribute it and/or modify 
  6  # it under the terms of the GNU Affero General Public License as published by 
  7  # the Free Software Foundation; either version 3 of the License, or 
  8  # (at your option) any later version. 
  9  # 
 10  # Python X2Go is distributed in the hope that it will be useful, 
 11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 13  # GNU Affero General Public License for more details. 
 14  # 
 15  # You should have received a copy of the GNU Affero General Public License 
 16  # along with this program; if not, write to the 
 17  # Free Software Foundation, Inc., 
 18  # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 
 19  # 
 20  # Other contributors: 
 21  #       none so far 
 22   
 23  """\ 
 24  X2GoPulseAudio class - a Pulseaudio daemon guardian thread. 
 25   
 26  """ 
 27   
 28  __NAME__ = 'x2gopulseaudio-pylib' 
 29   
 30  from defaults import X2GOCLIENT_OS as _X2GOCLIENT_OS 
 31  if _X2GOCLIENT_OS == 'Windows': 
 32      import win32process 
 33      import win32con 
 34      import win32event 
 35   
 36  # modules 
 37  import os 
 38  import sys 
 39  import threading 
 40  import gevent 
 41  import copy 
 42  import socket 
 43   
 44  from defaults import LOCAL_HOME as _LOCAL_HOME 
 45   
 46  # Python X2Go modules 
 47  import log 
 48   
 49  import exceptions 
50 -class OSNotSupportedException(exceptions.StandardError): pass
51 """ Exception denoting that this operating system is not supported. """ 52
53 -class X2GoPulseAudio(threading.Thread):
54 """ 55 This class controls the Pulse Audio daemon. 56 """ 57
58 - def __init__(self, path=None, client_instance=None, logger=None, loglevel=log.loglevel_DEFAULT):
59 """\ 60 Initialize a Pulse Audio daemon instance. 61 62 @param path: full path to pulseaudio.exe 63 @type path: C{str} 64 @param client_instance: the calling L{X2GoClient} instance 65 @type client_instance: L{X2GoClient} instance 66 @param logger: you can pass an L{X2GoLogger} object to the L{X2GoClientXConfig} constructor 67 @type logger: C{obj} 68 @param loglevel: if no L{X2GoLogger} object has been supplied a new one will be 69 constructed with the given loglevel 70 @type loglevel: C{int} 71 72 @raise OSNotSupportedException: on non-Windows platforms Python X2Go presumes that pulseaudio is already launched 73 74 """ 75 if _X2GOCLIENT_OS not in ("Windows"): 76 raise OSNotSupportedException('classes of x2go.pulseaudio module are for Windows only') 77 78 if logger is None: 79 self.logger = log.X2GoLogger(loglevel=loglevel) 80 else: 81 self.logger = copy.deepcopy(logger) 82 self.logger.tag = __NAME__ 83 84 self.path = path 85 self.client_instance = client_instance 86 self._keepalive = None 87 88 threading.Thread.__init__(self) 89 self.daemon = True 90 self.start()
91
92 - def run(self):
93 """\ 94 This method is called once the C{X2GoPulseAudio.start()} method has been called. To tear 95 down the Pulseaudio daemon call the L{X2GoPulseAudio.stop_thread()} method. 96 97 """ 98 self._keepalive = True 99 cmd = 'pulseaudio.exe' 100 cmd_options = [ 101 '-n', 102 '--exit-idle-time=-1', 103 '-L "module-native-protocol-tcp port=4713 auth-cookie=\\\\.pulse-cookie"', 104 '-L "module-esound-protocol-tcp port=16001"', 105 '-L module-waveout', 106 ] 107 108 # Fix for python-x2go bug #537. 109 # Works Around PulseAudio bug #80772. 110 # Tested with PulseAudio 5.0. 111 # This argument will not cause PulseAudio 1.1 to fail to launch. 112 # However, PulseAudio 1.1 ignores it for some reason. 113 # So yes, the fact that 1.1 ignores it would be a bug in python-x2go if 114 # we ever ship 1.1 again. 115 # 116 # wv.major == 5 matches 2000, XP, and Server 2003 (R2). 117 # (Not that we support 2000.) 118 wv = sys.getwindowsversion() 119 if (wv.major==5): 120 self.logger('Windows XP or Server 2003 (R2) detected.', loglevel=log.loglevel_DEBUG) 121 self.logger('Setting PulseAudio to "Normal" CPU priority.', loglevel=log.loglevel_DEBUG) 122 cmd_options.insert(0,"--high-priority=no") 123 124 cmd_options = " %s" % " ".join(cmd_options) 125 126 if not os.path.isdir(os.path.join(_LOCAL_HOME, '.pulse', '%s-runtime' % socket.gethostname())): 127 os.makedirs(os.path.join(_LOCAL_HOME, '.pulse', '%s-runtime' % socket.gethostname())) 128 self.logger('starting PulseAudio server with command line: %s%s' % (cmd, cmd_options), loglevel=log.loglevel_DEBUG) 129 130 si = win32process.STARTUPINFO() 131 p_info = win32process.CreateProcess(None, 132 '%s\\%s %s' % (self.path, cmd, cmd_options), 133 None, 134 None, 135 0, 136 win32con.CREATE_NO_WINDOW|win32process.NORMAL_PRIORITY_CLASS, 137 None, 138 None, 139 si, 140 ) 141 (hProcess, hThread, processId, threadId) = p_info 142 143 gevent.sleep(5) 144 rc = win32event.WaitForMultipleObjects([hProcess], 145 1, 146 1, # wait just one millisec 147 ) 148 _is_alive = ( rc != win32event.WAIT_OBJECT_0 ) 149 if self.client_instance and not _is_alive: 150 if os.environ.has_key('CLIENTNAME'): 151 self.client_instance.HOOK_pulseaudio_not_supported_in_RDPsession() 152 else: 153 self.client_instance.HOOK_pulseaudio_server_startup_failed() 154 155 while self._keepalive and _is_alive: 156 gevent.sleep(1) 157 rc = win32event.WaitForMultipleObjects([hProcess], 158 1, 159 1, # wait just one millisec 160 ) 161 _is_alive = ( rc != win32event.WAIT_OBJECT_0 ) 162 if self.client_instance and not _is_alive: 163 self.client_instance.HOOK_pulseaudio_server_died() 164 165 self.logger('terminating running PulseAudio server', loglevel=log.loglevel_DEBUG) 166 167 # there is no real kill command on Windows... 168 self.logger('PulseAudio process ID to terminate: %s' % processId, loglevel=log.loglevel_DEBUG) 169 try: 170 win32process.TerminateProcess(hProcess, 0) 171 except win32process.error: 172 pass
173
174 - def stop_thread(self):
175 """\ 176 Tear down a running Pulseaudio daemon. 177 178 """ 179 self.logger('stop_thread() method has been called', loglevel=log.loglevel_DEBUG) 180 self._keepalive = False
181