jack1 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

330 lines
7.9KB

  1. from ctypes import *
  2. import string
  3. from Queue import Queue
  4. class jack_client_t(Structure):
  5. pass
  6. class jack_port_t(Structure):
  7. pass
  8. client_p = POINTER(jack_client_t)
  9. port_p = POINTER(jack_port_t)
  10. libjack = cdll.LoadLibrary( "libjack.so" )
  11. client_new = libjack.jack_client_new
  12. client_new.argtypes = [ c_char_p ]
  13. client_new.restype = client_p
  14. client_open = libjack.jack_client_open
  15. client_open.argtypes = [ c_char_p, c_uint, POINTER( c_uint ) ]
  16. client_open.restype = client_p
  17. client_close = libjack.jack_client_close
  18. client_close.argtypes = [ client_p ]
  19. client_close.restype = None
  20. activate = libjack.jack_activate
  21. activate.argtypes = [ client_p ]
  22. activate.restype = None
  23. deactivate = libjack.jack_deactivate
  24. deactivate.argtypes = [ client_p ]
  25. deactivate.restype = None
  26. get_ports = libjack.jack_get_ports
  27. get_ports.argtypes = [ client_p, c_char_p, c_char_p, c_ulong ]
  28. get_ports.restype = POINTER( c_char_p )
  29. port_by_name = libjack.jack_port_by_name
  30. port_by_name.argtypes = [ client_p, c_char_p ]
  31. port_by_name.restype = port_p
  32. port_get_all_connections = libjack.jack_port_get_all_connections
  33. port_get_all_connections.argtypes = [ client_p, port_p ]
  34. port_get_all_connections.restype = POINTER( c_char_p )
  35. jack_free = libjack.jack_free
  36. jack_free.argtypes = [ c_void_p ]
  37. jack_free.restype = None
  38. rename_client = libjack.jack_rename_client
  39. rename_client.argtypes = [ client_p, c_char_p, c_char_p ]
  40. rename_client.restype = c_int
  41. class jack_session_command_t( Structure ):
  42. _fields_ = [ ("uuid", 16*c_char ), ("clientname", 33*c_char), ("command", 256*c_char ) ]
  43. session_notify = libjack.jack_session_notify
  44. session_notify.argtypes = [ client_p, c_uint, c_char_p ]
  45. session_notify.restype = POINTER( jack_session_command_t )
  46. get_client_name_by_uuid = libjack.jack_get_client_name_by_uuid
  47. get_client_name_by_uuid.argtypes = [ client_p, c_char_p ]
  48. get_client_name_by_uuid.restype = c_char_p
  49. get_cookie_by_uuid = libjack.jack_get_cookie_by_uuid
  50. get_cookie_by_uuid.argtypes = [ client_p, c_char_p, c_char_p ]
  51. get_cookie_by_uuid.restype = c_char_p
  52. connect = libjack.jack_connect
  53. connect.argtypes = [ client_p, c_char_p, c_char_p ]
  54. connect.restype = c_int
  55. disconnect = libjack.jack_disconnect
  56. disconnect.argtypes = [ client_p, c_char_p, c_char_p ]
  57. disconnect.restype = c_int
  58. PortRegistrationCallback = CFUNCTYPE( None, c_uint, c_int, c_void_p )
  59. set_port_registration_callback = libjack.jack_set_port_registration_callback
  60. set_port_registration_callback.argtypes = [ client_p, PortRegistrationCallback, c_void_p ]
  61. set_port_registration_callback.restype = c_int
  62. port_by_id = libjack.jack_port_by_id
  63. port_by_id.argtypes = [ client_p, c_uint ]
  64. port_by_id.restype = port_p
  65. port_name = libjack.jack_port_name
  66. port_name.argtypes = [ port_p ]
  67. port_name.restype = c_char_p
  68. port_type = libjack.jack_port_type
  69. port_type.argtypes = [ port_p ]
  70. port_type.restype = c_char_p
  71. port_flags = libjack.jack_port_flags
  72. port_flags.argtypes = [ port_p ]
  73. port_flags.restype = c_int
  74. JACK_DEFAULT_AUDIO_TYPE="32 bit float mono audio"
  75. JACK_DEFAULT_MIDI_TYPE="8 bit raw midi"
  76. JackPortIsInput = 0x1
  77. JackPortIsOutput = 0x2
  78. JackPortIsPhysical = 0x4
  79. JackPortCanMonitor = 0x8
  80. JackPortIsTerminal = 0x10
  81. JackSessionSave = 1
  82. JackSessionQuit = 2
  83. class Port( object ):
  84. def __init__( self, client, name ):
  85. self.client = client
  86. self.name = name
  87. self.portname = name.split(':')[1]
  88. self.port_p = port_by_name( self.client, name )
  89. self.conns = self.get_live_connections()
  90. def get_connections( self ):
  91. return self.conns
  92. def get_live_connections( self ):
  93. conns = port_get_all_connections( self.client, self.port_p )
  94. if not conns:
  95. return []
  96. i=0
  97. retval = []
  98. while conns[i]:
  99. retval.append( conns[i] )
  100. i+=1
  101. jack_free(conns)
  102. return retval
  103. def connect( self, other ):
  104. connect( self.client, self.name, other )
  105. def disconnect( self, other ):
  106. disconnect( self.client, self.name, other )
  107. def is_input( self ):
  108. return (port_flags( self.port_p ) & JackPortIsInput) != 0
  109. def is_output( self ):
  110. return (port_flags( self.port_p ) & JackPortIsOutput) != 0
  111. def is_audio( self ):
  112. return (port_type( self.port_p ) == JACK_DEFAULT_AUDIO_TYPE)
  113. def is_midi( self ):
  114. return (port_type( self.port_p ) == JACK_DEFAULT_MIDI_TYPE)
  115. class Client( object ):
  116. def __init__( self, client, name ):
  117. self.client = client
  118. self.name = name
  119. self.ports = []
  120. self.commandline = None
  121. self.isinfra = False
  122. def get_commandline( self ):
  123. if self.commandline:
  124. return self.commandline
  125. else:
  126. return ""
  127. def set_commandline( self, cmdline ):
  128. self.commandline = cmdline
  129. def add_port( self, portname ):
  130. self.ports.append( Port( self.client, portname ) )
  131. def rename( self, newname ):
  132. rename_client( self.client, self.name, newname )
  133. self.ports = []
  134. ports = get_ports( self.client, newname+":.*", None, 0 )
  135. self.name = newname
  136. i=0
  137. while(ports[i]):
  138. self.add_port( ports[i] )
  139. i+=1
  140. jack_free( ports )
  141. def set_infra( self, cmdline ):
  142. self.isinfra = True
  143. self.commandline = cmdline
  144. class JackGraph( object ):
  145. def __init__( self, client, ports, uuids=[] ):
  146. self.client = client
  147. self.clients = {}
  148. i=0
  149. while(ports[i]):
  150. port_split = ports[i].split(':')
  151. if not self.clients.has_key(port_split[0]):
  152. self.clients[port_split[0]] = Client( client, port_split[0] )
  153. self.clients[port_split[0]].add_port( ports[i] )
  154. i+=1
  155. def get_client( self, name ):
  156. return self.clients[name]
  157. def get_port_list( self ):
  158. retval = []
  159. for c in self.clients.values():
  160. for p in c.ports:
  161. retval.append( p.name )
  162. return retval
  163. def check_client_name( self, client ):
  164. if not client.name in self.reserved_names:
  165. return
  166. oldname = client.name
  167. cname_split = client.name.split('-')
  168. if len(cname_split) == 1:
  169. cname_prefix = cname_split[0]
  170. else:
  171. cname_prefix = string.join( cname_split[:-1], '-' )
  172. num = 1
  173. while ("%s-%d"%(cname_prefix,num)) in (self.clients.keys()+self.reserved_names):
  174. num+=1
  175. # XXX: this might still fail due to race.
  176. # also needs to lock
  177. newname = "%s-%d"%(cname_prefix,num )
  178. client.rename( newname )
  179. del self.clients[oldname]
  180. self.clients[newname] = client
  181. def remove_client( self, name ):
  182. del self.clients[name]
  183. for c in self.clients.values():
  184. for p in c.ports:
  185. for conn in p.get_connections():
  186. if conn.startswith(name+":"):
  187. p.conns.remove( conn )
  188. def remove_client_only( self, name ):
  189. del self.clients[name]
  190. def ensure_clientnames( self, names ):
  191. self.reserved_names = names
  192. for c in self.clients.values():
  193. self.check_client_name( c )
  194. class NotifyReply(object):
  195. def __init__( self, uuid, clientname, commandline ):
  196. self.uuid = uuid
  197. self.clientname = clientname
  198. self.commandline = commandline
  199. class JackClient(object):
  200. def __init__( self, name ):
  201. self.client = client_open( name, 0, None )
  202. if not self.client:
  203. raise Exception( "got no client name" )
  204. self.reg_cb = PortRegistrationCallback( self.port_registration_cb )
  205. set_port_registration_callback( self.client, self.reg_cb, None )
  206. self.port_queue = Queue()
  207. activate( self.client )
  208. def close( self ):
  209. client_close( self.client )
  210. def get_graph( self ):
  211. ports = get_ports( self.client, None, None, 0 )
  212. retval = JackGraph( self.client, ports )
  213. jack_free( ports )
  214. return retval
  215. def rename_client( self, old, new ):
  216. if rename_client( self.client, old, new ):
  217. raise Exception
  218. def port_registration_cb( self, port_id, reg, arg ):
  219. port_p = port_by_id( self.client, port_id )
  220. self.port_queue.put( (port_p,reg) )
  221. def session_save( self, path ):
  222. commands = session_notify( self.client, JackSessionSave, path )
  223. i=0
  224. retval = []
  225. while( commands[i].uuid != "" ):
  226. retval.append( NotifyReply( commands[i].uuid, commands[i].clientname, commands[i].command ) )
  227. i+=1
  228. jack_free( commands )
  229. return retval
  230. def connect( self, a, b ):
  231. portA_p = port_by_name( self.client, a )
  232. if( port_flags( portA_p ) & JackPortIsOutput ):
  233. connect( self.client, a, b )
  234. else:
  235. connect( self.client, b, a )