jack.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. #include <python2.7/Python.h>
  2. #include <jack/jack.h>
  3. typedef struct {
  4. PyObject_HEAD
  5. jack_client_t* client;
  6. PyObject* registration_callback;
  7. PyObject* registration_callback_argument;
  8. } Client;
  9. typedef struct {
  10. PyObject_HEAD
  11. jack_port_t* port;
  12. } Port;
  13. static PyObject* error;
  14. static PyObject* failure;
  15. static PyTypeObject port_type = {
  16. PyObject_HEAD_INIT(NULL)
  17. };
  18. static void jack_registration_callback(jack_port_id_t port_id, int registered, void* arg)
  19. {
  20. // register: non-zero if the port is being registered, zero if the port is being unregistered
  21. Client* client = (Client*)arg;
  22. if(client->registration_callback) {
  23. // Ensure that the current thread is ready to call the Python API.
  24. PyGILState_STATE gil_state = PyGILState_Ensure();
  25. Port* port = PyObject_New(Port, &port_type);
  26. port->port = jack_port_by_id(client->client, port_id);
  27. // 'O' increases reference count
  28. PyObject* callback_argument_list;
  29. if(client->registration_callback_argument) {
  30. callback_argument_list = Py_BuildValue("(O,i,O)", (PyObject*)port, registered, client->registration_callback_argument);
  31. } else {
  32. callback_argument_list = Py_BuildValue("(O,i)", (PyObject*)port, registered);
  33. }
  34. PyObject* result = PyObject_CallObject(client->registration_callback, callback_argument_list);
  35. Py_DECREF(callback_argument_list);
  36. if(!result) {
  37. PyErr_PrintEx(0);
  38. } else {
  39. Py_DECREF(result);
  40. }
  41. // Release the thread. No Python API calls are allowed beyond this point.
  42. PyGILState_Release(gil_state);
  43. }
  44. }
  45. static PyObject* client___new__(PyTypeObject* type, PyObject* args, PyObject* kwargs)
  46. {
  47. Client* self = (Client*)type->tp_alloc(type, 0);
  48. if(self) {
  49. const char* name;
  50. if(!PyArg_ParseTuple(args, "s", &name)) {
  51. return NULL;
  52. }
  53. jack_status_t status;
  54. self->client = jack_client_open(name, JackNullOption, &status);
  55. if(!self->client) {
  56. if(status & JackFailure) {
  57. PyErr_SetString(failure, "Overall operation failed.");
  58. }
  59. return NULL;
  60. }
  61. self->registration_callback = NULL;
  62. int error_code = jack_set_port_registration_callback(
  63. self->client,
  64. jack_registration_callback,
  65. (void*)self
  66. );
  67. if(error_code) {
  68. PyErr_SetString(error, "Could not set port registration callback.");
  69. return NULL;
  70. }
  71. }
  72. return (PyObject*)self;
  73. }
  74. static PyObject* client_activate(Client* self) {
  75. int error_code = jack_activate(self->client);
  76. if(error_code) {
  77. PyErr_SetString(error, "");
  78. return NULL;
  79. } else {
  80. Py_INCREF(Py_None);
  81. return Py_None;
  82. }
  83. }
  84. static PyObject* client_get_name(Client* self)
  85. {
  86. return (PyObject*)PyString_FromString(jack_get_client_name(self->client));
  87. }
  88. static PyObject* client_get_ports(Client* self)
  89. {
  90. PyObject* ports = PyList_New(0);
  91. if(!ports) {
  92. return NULL;
  93. }
  94. const char** port_names = jack_get_ports(self->client, NULL, NULL, 0);
  95. int port_index;
  96. for(port_index = 0; port_names[port_index] != NULL; port_index++) {
  97. Port* port = PyObject_New(Port, &port_type);
  98. port->port = jack_port_by_name(self->client, port_names[port_index]);
  99. if(PyList_Append(ports, (PyObject*)port)) {
  100. return NULL;
  101. }
  102. }
  103. jack_free(port_names);
  104. return ports;
  105. }
  106. static PyObject* client_set_port_registration_callback(Client* self, PyObject* args)
  107. {
  108. PyObject* callback = 0;
  109. PyObject* callback_argument = 0;
  110. if(!PyArg_ParseTuple(args, "O|O", &callback, &callback_argument)) {
  111. return NULL;
  112. }
  113. if(!PyCallable_Check(callback)) {
  114. PyErr_SetString(PyExc_TypeError, "Parameter must be callable.");
  115. return NULL;
  116. }
  117. Py_XINCREF(callback);
  118. Py_XDECREF(self->registration_callback);
  119. self->registration_callback = callback;
  120. Py_XINCREF(callback_argument);
  121. Py_XDECREF(self->registration_callback_argument);
  122. self->registration_callback_argument = callback_argument;
  123. Py_INCREF(Py_None);
  124. return Py_None;
  125. }
  126. static void client_dealloc(Client* self)
  127. {
  128. jack_client_close(self->client);
  129. self->ob_type->tp_free((PyObject*)self);
  130. }
  131. static PyMethodDef client_methods[] = {
  132. {
  133. "activate",
  134. (PyCFunction)client_activate,
  135. METH_NOARGS,
  136. "Tell the Jack server that the program is ready to start processing audio.",
  137. },
  138. {
  139. "get_name",
  140. (PyCFunction)client_get_name,
  141. METH_NOARGS,
  142. "Return client's actual name.",
  143. },
  144. {
  145. "get_ports",
  146. (PyCFunction)client_get_ports,
  147. METH_NOARGS,
  148. "Return list of ports.",
  149. },
  150. {
  151. "set_port_registration_callback",
  152. (PyCFunction)client_set_port_registration_callback,
  153. METH_VARARGS,
  154. "Tell the JACK server to call a function whenever a port is registered or unregistered.",
  155. },
  156. {NULL},
  157. };
  158. static PyObject* port_get_name(Port* self)
  159. {
  160. return (PyObject*)PyString_FromString(jack_port_name(self->port));
  161. }
  162. static PyObject* port_get_short_name(Port* self)
  163. {
  164. return (PyObject*)PyString_FromString(jack_port_short_name(self->port));
  165. }
  166. static PyObject* port_set_short_name(Port* self, PyObject* args)
  167. {
  168. const char* name;
  169. if(!PyArg_ParseTuple(args, "s", &name)) {
  170. return NULL;
  171. }
  172. // 0 on success, otherwise a non-zero error code.
  173. if(jack_port_set_name(self->port, name)) {
  174. return NULL;
  175. }
  176. Py_INCREF(Py_None);
  177. return Py_None;
  178. }
  179. static PyObject* port_get_client_name(Port* self)
  180. {
  181. // e.g. "PulseAudio JACK Sink:front-left"
  182. const char* port_name = jack_port_name(self->port);
  183. int client_name_length = strlen(port_name) - strlen(jack_port_short_name(self->port)) - 1;
  184. // e.g. "PulseAudio JACK Sink"
  185. char* client_name = (char*) malloc(jack_port_name_size());
  186. strncpy(client_name, port_name, client_name_length);
  187. client_name[client_name_length] = '\0';
  188. PyObject* client_name_python = PyString_FromString(client_name);
  189. free(client_name);
  190. return client_name_python;
  191. }
  192. static PyObject* port_get_aliases(Port* self)
  193. {
  194. PyObject* aliases_list = PyList_New(0);
  195. if(!aliases_list) {
  196. return NULL;
  197. }
  198. char* aliases[2];
  199. aliases[0] = (char*) malloc(jack_port_name_size());
  200. aliases[1] = (char*) malloc(jack_port_name_size());
  201. int alias_count = jack_port_get_aliases(self->port, aliases);
  202. int alias_index;
  203. for(alias_index = 0; alias_index < alias_count; alias_index++) {
  204. PyList_Append(aliases_list, PyString_FromString(aliases[alias_index]));
  205. }
  206. free(aliases[0]);
  207. free(aliases[1]);
  208. return aliases_list;
  209. }
  210. static PyObject* port___repr__(Port* self)
  211. {
  212. static PyObject* format;
  213. if(!format) {
  214. format = PyString_FromString("jack.Port(name = '%s')");
  215. }
  216. PyObject* name = PyString_FromString(jack_port_name(self->port));
  217. PyObject* repr = PyString_Format(format, name);
  218. Py_DECREF(name);
  219. return repr;
  220. }
  221. static PyMethodDef port_methods[] = {
  222. {
  223. "get_name",
  224. (PyCFunction)port_get_name,
  225. METH_NOARGS,
  226. "Return port's name.",
  227. },
  228. {
  229. "get_short_name",
  230. (PyCFunction)port_get_short_name,
  231. METH_NOARGS,
  232. "Return port's name without the preceding name of the associated client.",
  233. },
  234. {
  235. "get_client_name",
  236. (PyCFunction)port_get_client_name,
  237. METH_NOARGS,
  238. "Return the name of the associated client.",
  239. },
  240. {
  241. "set_short_name",
  242. (PyCFunction)port_set_short_name,
  243. METH_VARARGS,
  244. "Modify a port's short name. May be called at any time.",
  245. },
  246. {
  247. "get_aliases",
  248. (PyCFunction)port_get_aliases,
  249. METH_NOARGS,
  250. "Return list of assigned aliases.",
  251. },
  252. {NULL},
  253. };
  254. PyMODINIT_FUNC initjack()
  255. {
  256. // Initialize and acquire the global interpreter lock.
  257. // This must be done in the main thread before creating engaging in any thread operations.
  258. PyEval_InitThreads();
  259. PyObject* module = Py_InitModule("jack", NULL);
  260. if(!module) {
  261. return;
  262. }
  263. error = PyErr_NewException((char*)"jack.Error", NULL, NULL);
  264. Py_INCREF(error);
  265. PyModule_AddObject(module, "Error", error);
  266. failure = PyErr_NewException((char*)"jack.Failure", error, NULL);
  267. Py_INCREF(failure);
  268. PyModule_AddObject(module, "Failure", failure);
  269. static PyTypeObject client_type = {
  270. PyObject_HEAD_INIT(NULL)
  271. };
  272. client_type.tp_name = "jack.Client";
  273. client_type.tp_basicsize = sizeof(Client);
  274. client_type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
  275. client_type.tp_new = client___new__;
  276. client_type.tp_dealloc = (destructor)client_dealloc;
  277. client_type.tp_methods = client_methods;
  278. if(PyType_Ready(&client_type) < 0) {
  279. return;
  280. }
  281. Py_INCREF(&client_type);
  282. PyModule_AddObject(module, "Client", (PyObject*)&client_type);
  283. port_type.tp_name = "jack.Port";
  284. port_type.tp_basicsize = sizeof(Port);
  285. port_type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
  286. // Forbid direct instantiation.
  287. port_type.tp_new = NULL;
  288. port_type.tp_repr = (reprfunc)port___repr__;
  289. port_type.tp_methods = port_methods;
  290. if(PyType_Ready(&port_type) < 0) {
  291. return;
  292. }
  293. Py_INCREF(&port_type);
  294. PyModule_AddObject(module, "Port", (PyObject*)&port_type);
  295. }