jack2 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.

208 lines
4.7KB

  1. /** @file mp_thread_client.c
  2. *
  3. * @brief This simple client demonstrates the use of "jack_thread_wait" function in a multi-threaded context.
  4. A set of n threads (the jack process thread + (n - 1) helper threads) are used to work on a global queue of tasks.
  5. The last finishing thread gives control back to libjack using the "jack_thread_wait" function. Other threads suspend
  6. on a condition variable and are resumed next cycle by the libjack suspended thread.
  7. */
  8. #include <unistd.h>
  9. #include <stdio.h>
  10. #include <errno.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <math.h>
  14. #define __SMP__ 1
  15. #include <jack/jack.h>
  16. #include <jack/thread.h>
  17. //#include "jack.h"
  18. //#include "thread.h"
  19. #include <math.h>
  20. #include "JackAtomic.h"
  21. jack_port_t *input_port;
  22. jack_port_t *output_port;
  23. jack_client_t *client;
  24. int buffer_size;
  25. #define WORK_AT_EACH_CYCLE 1000
  26. #define WORK_AT_EACH_LOOP 15
  27. static SInt32 cycle_work_count = 0;
  28. pthread_cond_t cond;
  29. pthread_mutex_t mutex;
  30. jack_nframes_t last_time = 0;
  31. static int print_count = 50;
  32. int result = 0;
  33. typedef struct thread_context
  34. {
  35. pthread_t thread;
  36. int num;
  37. };
  38. // Simulate workload
  39. static int fib(int n)
  40. {
  41. if (n < 2)
  42. return n;
  43. else
  44. return fib(n - 2) + fib(n - 1);
  45. }
  46. static void do_some_work(void *arg)
  47. {
  48. result = fib(WORK_AT_EACH_LOOP);
  49. }
  50. static void resume_all_threads(void *arg)
  51. {
  52. thread_context* context = (thread_context*)arg;
  53. jack_nframes_t cur_time = jack_frame_time(client);
  54. if (--print_count == 0) {
  55. printf("resume_all_threads from thread = %ld jack_frame_time = %u jack_cpu_load = %f\n", context->num, (cur_time - last_time), jack_cpu_load(client));
  56. print_count = 50;
  57. }
  58. pthread_mutex_lock(&mutex); // Hum...
  59. pthread_cond_broadcast(&cond);
  60. pthread_mutex_unlock(&mutex); // Hum...
  61. cycle_work_count = WORK_AT_EACH_CYCLE;
  62. last_time = cur_time;
  63. }
  64. static void suspend_jack_thread(void *arg)
  65. {
  66. jack_thread_wait(client, 0);
  67. }
  68. static void suspend_worker_thread(void *arg)
  69. {
  70. pthread_mutex_lock(&mutex); // Hum...
  71. pthread_cond_wait(&cond, &mutex);
  72. pthread_mutex_unlock(&mutex); // Hum...
  73. }
  74. static void * worker_aux_thread(void *arg)
  75. {
  76. while (1) {
  77. int val = DEC_ATOMIC(&cycle_work_count);
  78. if (val == 1) { // Last thread
  79. suspend_jack_thread(arg);
  80. resume_all_threads(arg);
  81. } else if (val < 1) {
  82. suspend_worker_thread(arg);
  83. } else {
  84. do_some_work(arg);
  85. }
  86. }
  87. return 0;
  88. }
  89. static void * worker_thread(void *arg)
  90. {
  91. suspend_worker_thread(arg); // Start in "suspended" state
  92. worker_aux_thread(arg);
  93. return 0;
  94. }
  95. // Example of audio process
  96. int process(jack_nframes_t nframes, void *arg)
  97. {
  98. resume_all_threads(arg);
  99. worker_aux_thread(arg);
  100. return 0;
  101. }
  102. /**
  103. * JACK calls this shutdown_callback if the server ever shuts down or
  104. * decides to disconnect the client.
  105. */
  106. void jack_shutdown (void *arg)
  107. {
  108. exit(1);
  109. }
  110. int main (int argc, char *argv[])
  111. {
  112. thread_context* worker_threads;
  113. int n, nthreads = 0;
  114. if (argc == 2)
  115. nthreads = atoi(argv[1]);
  116. worker_threads = (thread_context *) malloc (sizeof (thread_context) * nthreads);
  117. /* open a client connection to the JACK server */
  118. if ((client = jack_client_open("mp_thread_test", JackNoStartServer, NULL)) == NULL) {
  119. fprintf(stderr, "Cannot open client\n");
  120. exit(1);
  121. }
  122. buffer_size = jack_get_buffer_size(client);
  123. /* tell the JACK server to call the 'callback' function
  124. */
  125. worker_threads[0].num = 0;
  126. jack_set_process_callback(client, process, &worker_threads[0]);
  127. /* tell the JACK server to call `jack_shutdown()' if
  128. it ever shuts down, either entirely, or if it
  129. just decides to stop calling us.
  130. */
  131. jack_on_shutdown(client, jack_shutdown, 0);
  132. pthread_mutex_init(&mutex, NULL);
  133. pthread_cond_init(&cond, NULL);
  134. input_port = jack_port_register(client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
  135. output_port = jack_port_register(client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
  136. if ((input_port == NULL) || (output_port == NULL)) {
  137. fprintf(stderr, "no more JACK ports available\n");
  138. exit(1);
  139. }
  140. fprintf(stderr, "Creating %d threads\n", nthreads);
  141. for (n = 1; n <= nthreads; ++n) {
  142. worker_threads[n].num = n;
  143. if (jack_client_create_thread(client, &worker_threads[n].thread, 90, 1, worker_thread, &worker_threads[n]) < 0)
  144. exit(1);
  145. jack_acquire_real_time_scheduling (worker_threads[n].thread, 90);
  146. }
  147. /* Tell the JACK server that we are ready to roll. Our
  148. * process() callback will start running now. */
  149. if (jack_activate(client)) {
  150. fprintf(stderr, "cannot activate client");
  151. exit(1);
  152. }
  153. while (1) {
  154. #ifdef WIN32
  155. Sleep(1000);
  156. #else
  157. sleep(1);
  158. #endif
  159. }
  160. jack_client_close(client);
  161. pthread_mutex_destroy(&mutex);
  162. pthread_cond_destroy(&cond);
  163. exit(0);
  164. }