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.

352 lines
8.5KB

  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. reserve_client_name = libjack.jack_reserve_client_name
  42. reserve_client_name.argtypes = [ client_p, c_char_p, c_char_p ]
  43. reserve_client_name.restype = c_int
  44. class jack_session_command_t( Structure ):
  45. _fields_ = [ ("uuid", 16*c_char ), ("clientname", 33*c_char), ("command", 256*c_char ) ]
  46. session_notify = libjack.jack_session_notify
  47. session_notify.argtypes = [ client_p, c_uint, c_char_p ]
  48. session_notify.restype = POINTER( jack_session_command_t )
  49. get_client_name_by_uuid = libjack.jack_get_client_name_by_uuid
  50. get_client_name_by_uuid.argtypes = [ client_p, c_char_p ]
  51. get_client_name_by_uuid.restype = c_char_p
  52. get_cookie_by_uuid = libjack.jack_get_cookie_by_uuid
  53. get_cookie_by_uuid.argtypes = [ client_p, c_char_p, c_char_p ]
  54. get_cookie_by_uuid.restype = c_char_p
  55. connect = libjack.jack_connect
  56. connect.argtypes = [ client_p, c_char_p, c_char_p ]
  57. connect.restype = c_int
  58. disconnect = libjack.jack_disconnect
  59. disconnect.argtypes = [ client_p, c_char_p, c_char_p ]
  60. disconnect.restype = c_int
  61. PortRegistrationCallback = CFUNCTYPE( None, c_uint, c_int, c_void_p )
  62. set_port_registration_callback = libjack.jack_set_port_registration_callback
  63. set_port_registration_callback.argtypes = [ client_p, PortRegistrationCallback, c_void_p ]
  64. set_port_registration_callback.restype = c_int
  65. port_by_id = libjack.jack_port_by_id
  66. port_by_id.argtypes = [ client_p, c_uint ]
  67. port_by_id.restype = port_p
  68. port_name = libjack.jack_port_name
  69. port_name.argtypes = [ port_p ]
  70. port_name.restype = c_char_p
  71. port_type = libjack.jack_port_type
  72. port_type.argtypes = [ port_p ]
  73. port_type.restype = c_char_p
  74. port_flags = libjack.jack_port_flags
  75. port_flags.argtypes = [ port_p ]
  76. port_flags.restype = c_int
  77. JACK_DEFAULT_AUDIO_TYPE="32 bit float mono audio"
  78. JACK_DEFAULT_MIDI_TYPE="8 bit raw midi"
  79. JackPortIsInput = 0x1
  80. JackPortIsOutput = 0x2
  81. JackPortIsPhysical = 0x4
  82. JackPortCanMonitor = 0x8
  83. JackPortIsTerminal = 0x10
  84. JackSessionSave = 1
  85. JackSessionQuit = 2
  86. class Port( object ):
  87. def __init__( self, client, name ):
  88. self.client = client
  89. self.name = name
  90. self.portname = name.split(':')[1]
  91. self.port_p = port_by_name( self.client, name )
  92. self.conns = self.get_live_connections()
  93. def get_connections( self ):
  94. return self.conns
  95. def get_live_connections( self ):
  96. conns = port_get_all_connections( self.client, self.port_p )
  97. if not conns:
  98. return []
  99. i=0
  100. retval = []
  101. while conns[i]:
  102. retval.append( conns[i] )
  103. i+=1
  104. jack_free(conns)
  105. return retval
  106. def connect( self, other ):
  107. connect( self.client, self.name, other )
  108. def disconnect( self, other ):
  109. disconnect( self.client, self.name, other )
  110. def is_input( self ):
  111. return (port_flags( self.port_p ) & JackPortIsInput) != 0
  112. def is_output( self ):
  113. return (port_flags( self.port_p ) & JackPortIsOutput) != 0
  114. def is_audio( self ):
  115. return (port_type( self.port_p ) == JACK_DEFAULT_AUDIO_TYPE)
  116. def is_midi( self ):
  117. return (port_type( self.port_p ) == JACK_DEFAULT_MIDI_TYPE)
  118. class Client( object ):
  119. def __init__( self, client, name ):
  120. self.client = client
  121. self.name = name
  122. self.ports = []
  123. self.commandline = None
  124. self.isinfra = False
  125. self.uuid = None
  126. def get_commandline( self ):
  127. if self.commandline:
  128. return self.commandline
  129. else:
  130. return ""
  131. def set_commandline( self, cmdline ):
  132. self.commandline = cmdline
  133. def get_uuid( self ):
  134. return self.uuid
  135. def set_uuid( self, uuid ):
  136. self.uuid = uuid
  137. def add_port( self, portname ):
  138. self.ports.append( Port( self.client, portname ) )
  139. def rename( self, newname ):
  140. rename_client( self.client, self.name, newname )
  141. self.ports = []
  142. ports = get_ports( self.client, newname+":.*", None, 0 )
  143. self.name = newname
  144. i=0
  145. while(ports[i]):
  146. self.add_port( ports[i] )
  147. i+=1
  148. jack_free( ports )
  149. def set_infra( self, cmdline ):
  150. self.isinfra = True
  151. self.commandline = cmdline
  152. class JackGraph( object ):
  153. def __init__( self, client, ports, uuids=[] ):
  154. self.client = client
  155. self.clients = {}
  156. self.reserved_names = []
  157. i=0
  158. while(ports[i]):
  159. port_split = ports[i].split(':')
  160. if not self.clients.has_key(port_split[0]):
  161. self.clients[port_split[0]] = Client( client, port_split[0] )
  162. self.clients[port_split[0]].add_port( ports[i] )
  163. i+=1
  164. def get_client( self, name ):
  165. return self.clients[name]
  166. def get_port_list( self ):
  167. retval = []
  168. for c in self.clients.values():
  169. for p in c.ports:
  170. retval.append( p.name )
  171. return retval
  172. def check_client_name( self, client ):
  173. if not client.name in self.reserved_names:
  174. return
  175. oldname = client.name
  176. newname = self.get_free_name( client.name )
  177. client.rename( newname )
  178. del self.clients[oldname]
  179. self.clients[newname] = client
  180. def get_free_name( self, oldname, other_names=[] ):
  181. cname_split = oldname.split('-')
  182. if len(cname_split) == 1:
  183. cname_prefix = cname_split[0]
  184. else:
  185. cname_prefix = string.join( cname_split[:-1], '-' )
  186. num = 1
  187. while ("%s-%d"%(cname_prefix,num)) in (self.clients.keys()+self.reserved_names+other_names):
  188. num+=1
  189. return ("%s-%d"%(cname_prefix,num))
  190. def remove_client( self, name ):
  191. del self.clients[name]
  192. for c in self.clients.values():
  193. for p in c.ports:
  194. for conn in p.get_connections():
  195. if conn.startswith(name+":"):
  196. p.conns.remove( conn )
  197. def remove_client_only( self, name ):
  198. del self.clients[name]
  199. def ensure_clientnames( self, names ):
  200. self.reserved_names = names
  201. for c in self.clients.values():
  202. self.check_client_name( c )
  203. def get_taken_names( self ):
  204. return self.clients.keys() + self.reserved_names
  205. def reserve_name( self, uuid, name ):
  206. if reserve_client_name( self.client, name, uuid ):
  207. raise Exception( "reservation failure" )
  208. self.reserved_names.append( name )
  209. class NotifyReply(object):
  210. def __init__( self, uuid, clientname, commandline ):
  211. self.uuid = uuid
  212. self.clientname = clientname
  213. self.commandline = commandline
  214. class JackClient(object):
  215. def __init__( self, name ):
  216. self.client = client_open( name, 0, None )
  217. if not self.client:
  218. raise Exception( "got no client name" )
  219. self.reg_cb = PortRegistrationCallback( self.port_registration_cb )
  220. set_port_registration_callback( self.client, self.reg_cb, None )
  221. self.port_queue = Queue()
  222. activate( self.client )
  223. def close( self ):
  224. client_close( self.client )
  225. def get_graph( self ):
  226. ports = get_ports( self.client, None, None, 0 )
  227. retval = JackGraph( self.client, ports )
  228. jack_free( ports )
  229. return retval
  230. def rename_client( self, old, new ):
  231. if rename_client( self.client, old, new ):
  232. raise Exception
  233. def port_registration_cb( self, port_id, reg, arg ):
  234. port_p = port_by_id( self.client, port_id )
  235. self.port_queue.put( (port_p,reg) )
  236. def session_save( self, path ):
  237. commands = session_notify( self.client, JackSessionSave, path )
  238. i=0
  239. retval = []
  240. while( commands[i].uuid != "" ):
  241. retval.append( NotifyReply( commands[i].uuid, commands[i].clientname, commands[i].command ) )
  242. i+=1
  243. jack_free( commands )
  244. return retval
  245. def connect( self, a, b ):
  246. portA_p = port_by_name( self.client, a )
  247. if( port_flags( portA_p ) & JackPortIsOutput ):
  248. connect( self.client, a, b )
  249. else:
  250. connect( self.client, b, a )