Allows linux users to control pulse audio from node. So far functionality is... um... limited :)
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.

178 lines
4.7 KiB

  1. #include <node/node_api.h>
  2. #include <stdio.h>
  3. #include <execinfo.h>
  4. #include <signal.h>
  5. #include <unistd.h>
  6. #include <pulse/pulseaudio.h>
  7. struct PACBData {
  8. pa_context *context;
  9. pa_mainloop *mainloop;
  10. };
  11. struct NapiCBData {
  12. napi_value *cb;
  13. napi_env *env;
  14. napi_ref *cbRef;
  15. };
  16. const char *NAME = "miccontrol";
  17. void handleSourceList(struct pa_context *c, const pa_source_info *i, int eol, void *userdata);
  18. void connectToPulseCB(pa_context *context, void *userdata);
  19. napi_value connectToPulse(napi_env env, napi_callback_info info);
  20. napi_value init(napi_env env, napi_value exports);
  21. napi_value connectToPulse(napi_env env, napi_callback_info info) {
  22. size_t argc = 1;
  23. napi_value args[1];
  24. struct PACBData *paCBData;
  25. napi_status status;
  26. struct NapiCBData *napiCBData = malloc(sizeof(struct NapiCBData));
  27. napiCBData->cbRef = malloc(sizeof(napi_ref));
  28. status = napi_get_cb_info(env, info, &argc, args, NULL, (void**)&paCBData);
  29. assert(argc == 1);
  30. assert(status == napi_ok);
  31. printf("finished getting calback info... \n");
  32. napiCBData->env = &env;
  33. status = napi_create_reference(env, *args, 1, napiCBData->cbRef);
  34. assert(status == napi_ok);
  35. int ret = 1;
  36. pa_context_set_state_callback(paCBData->context, connectToPulseCB, napiCBData);
  37. pa_context_connect(paCBData->context, NULL, 0, NULL);
  38. pa_mainloop_run(paCBData->mainloop, &ret);
  39. pa_context_unref(paCBData->context);
  40. pa_mainloop_free(paCBData->mainloop);
  41. //free(napiCBData);
  42. return NULL;
  43. }
  44. void connectToPulseCB(pa_context *context, void *userdata) {
  45. printf("Callback called... \n");
  46. napi_status status;
  47. napi_value argv[1];
  48. struct NapiCBData *napiCBData = (struct NapiCBData*)userdata;
  49. pa_context_state_t pa_state = pa_context_get_state(context);
  50. napi_value errorString;
  51. if(pa_state == PA_CONTEXT_READY) {
  52. status = napi_get_undefined(*(napiCBData->env), &argv[0]);
  53. } else if(pa_state == PA_CONTEXT_FAILED) {
  54. status = napi_create_string_utf8(
  55. *(napiCBData->env),
  56. "Error connecting to Pulse Audio",
  57. NAPI_AUTO_LENGTH,
  58. &errorString);
  59. assert(status == napi_ok);
  60. status = napi_create_error(*(napiCBData->env), NULL, errorString, &argv[0]);
  61. assert(status == napi_ok);
  62. } else {
  63. return;
  64. //eventually need to look into reconnecting on disconnections and handling
  65. //connection failures.
  66. }
  67. napi_value global;
  68. status = napi_get_global(*(napiCBData->env), &global);
  69. assert(status == napi_ok);
  70. napi_value result;
  71. napi_value cb;
  72. status = napi_get_reference_value(*(napiCBData->env), *(napiCBData->cbRef), &cb);
  73. assert(status == napi_ok);
  74. printf("Calling callback from native... \n");
  75. status = napi_call_function(*(napiCBData->env), global, cb, 1, argv, &result);
  76. assert(status == napi_ok);
  77. }
  78. //napi_value getSources() {
  79. // pa_operation *getSourceOp = NULL;
  80. // getSourceOp = pa_context_get_source_info_list(context, handleSourceList, NULL);
  81. // if(!getSourceOp) {
  82. // } else {
  83. // pa_operation_state_t state = pa_operation_get_state(getSourceOp);
  84. // switch(state) {
  85. // case PA_OPERATION_RUNNING:
  86. // break;
  87. // case PA_OPERATION_DONE:
  88. // break;
  89. // case PA_OPERATION_CANCELLED:
  90. // }
  91. // }
  92. //}
  93. //
  94. //void handleSourceList(pa_context *c, const pa_source_info *i, int eol, void *userdata) {
  95. // printf("Callback called...\n");
  96. // printf("eol is %d\n", eol);
  97. // printf(i->description);
  98. // printf("\n");
  99. //
  100. // return;
  101. //}
  102. void handler(int sig) {
  103. void *array[10];
  104. size_t size;
  105. size = backtrace(array, 10);
  106. fprintf(stderr, "Error: signal %d:\n", sig);
  107. backtrace_symbols_fd(array, size, STDERR_FILENO);
  108. exit(1);
  109. }
  110. napi_value init(napi_env env, napi_value exports) {
  111. signal(SIGSEGV, handler);
  112. pa_mainloop *mainloop = pa_mainloop_new();
  113. pa_mainloop_api *mainloop_api = pa_mainloop_get_api(mainloop);
  114. pa_context *context = pa_context_new(mainloop_api, NULL);
  115. struct PACBData *paCBData = malloc(sizeof(*paCBData));
  116. paCBData->context = context;
  117. paCBData->mainloop = mainloop;
  118. napi_status status;
  119. napi_value fn;
  120. status = napi_create_function(
  121. env,
  122. "connectToPulse",
  123. NAPI_AUTO_LENGTH,
  124. connectToPulse,
  125. paCBData,
  126. &fn);
  127. if(status != napi_ok) {
  128. return NULL;
  129. }
  130. status = napi_set_named_property(env, exports, "connectToPulse", fn);
  131. if(status != napi_ok) {
  132. return NULL;
  133. }
  134. // status = napi_create_function(env, NULL, NAPI_AUTO_LENGTH, getSources, paCBData, &fn);
  135. //
  136. // if(status != napi_ok) {
  137. // return NULL;
  138. // }
  139. //
  140. // status = napi_set_named_property(env, exports, "getSources", fn);
  141. //
  142. // if(status != napi_ok) {
  143. // return NULL;
  144. // }
  145. return exports;
  146. }
  147. NAPI_MODULE(NODE_GYP_MODULE_NAME, init);