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.

319 lines
7.6KB

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