Asterisk - The Open Source Telephony Project  21.4.1
app_jack.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2007 - 2008, Russell Bryant
5  *
6  * Russell Bryant <russell@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*!
20  * \file
21  * \brief Jack Application
22  *
23  * \author Russell Bryant <russell@digium.com>
24  *
25  * This is an application to connect an Asterisk channel to an input
26  * and output jack port so that the audio can be processed through
27  * another application, or to play audio from another application.
28  *
29  * \extref http://www.jackaudio.org/
30  *
31  * \note To install libresample, check it out of the following repository:
32  * <code>$ svn co http://svn.digium.com/svn/thirdparty/libresample/trunk</code>
33  *
34  * \ingroup applications
35  */
36 
37 /*** MODULEINFO
38  <depend>jack</depend>
39  <depend>resample</depend>
40  <support_level>extended</support_level>
41  ***/
42 
43 #include "asterisk.h"
44 
45 #include <limits.h>
46 
47 #include <jack/jack.h>
48 #include <jack/ringbuffer.h>
49 
50 #include <libresample.h>
51 
52 #include "asterisk/module.h"
53 #include "asterisk/channel.h"
54 #include "asterisk/strings.h"
55 #include "asterisk/lock.h"
56 #include "asterisk/app.h"
57 #include "asterisk/pbx.h"
58 #include "asterisk/audiohook.h"
59 #include "asterisk/format_cache.h"
60 
61 #define RESAMPLE_QUALITY 1
62 
63 /* The number of frames the ringbuffers can store. The actual size is RINGBUFFER_FRAME_CAPACITY * jack_data->frame_datalen */
64 #define RINGBUFFER_FRAME_CAPACITY 100
65 
66 /*! \brief Common options between the Jack() app and JACK_HOOK() function */
67 #define COMMON_OPTIONS \
68 " s(<name>) - Connect to the specified jack server name.\n" \
69 " i(<name>) - Connect the output port that gets created to the specified\n" \
70 " jack input port.\n" \
71 " o(<name>) - Connect the input port that gets created to the specified\n" \
72 " jack output port.\n" \
73 " n - Do not automatically start the JACK server if it is not already\n" \
74 " running.\n" \
75 " c(<name>) - By default, Asterisk will use the channel name for the jack client\n" \
76 " name. Use this option to specify a custom client name.\n"
77 /*** DOCUMENTATION
78  <application name="JACK" language="en_US">
79  <synopsis>
80  Jack Audio Connection Kit
81  </synopsis>
82  <syntax>
83  <parameter name="options" required="false">
84  <optionlist>
85  <option name="s">
86  <argument name="name" required="true">
87  <para>Connect to the specified jack server name</para>
88  </argument>
89  </option>
90  <option name="i">
91  <argument name="name" required="true">
92  <para>Connect the output port that gets created to the specified jack input port</para>
93  </argument>
94  </option>
95  <option name="o">
96  <argument name="name" required="true">
97  <para>Connect the input port that gets created to the specified jack output port</para>
98  </argument>
99  </option>
100  <option name="c">
101  <argument name="name" required="true">
102  <para>By default, Asterisk will use the channel name for the jack client name.</para>
103  <para>Use this option to specify a custom client name.</para>
104  </argument>
105  </option>
106  </optionlist>
107  </parameter>
108  </syntax>
109  <description>
110  <para>When executing this application, two jack ports will be created;
111  one input and one output. Other applications can be hooked up to
112  these ports to access audio coming from, or being send to the channel.</para>
113  </description>
114  </application>
115  ***/
116 
117 static const char jack_app[] = "JACK";
118 
119 struct jack_data {
121  AST_STRING_FIELD(server_name);
122  AST_STRING_FIELD(client_name);
123  AST_STRING_FIELD(connect_input_port);
124  AST_STRING_FIELD(connect_output_port);
125  );
126  jack_client_t *client;
127  jack_port_t *input_port;
128  jack_port_t *output_port;
129  jack_ringbuffer_t *input_rb;
130  jack_ringbuffer_t *output_rb;
131  struct ast_format *audiohook_format;
132  unsigned int audiohook_rate;
133  unsigned int frame_datalen;
134  void *output_resampler;
135  double output_resample_factor;
136  void *input_resampler;
137  double input_resample_factor;
138  unsigned int stop:1;
139  unsigned int has_audiohook:1;
140  unsigned int no_start_server:1;
141  /*! Only used with JACK_HOOK */
143 };
144 
145 static const struct {
146  jack_status_t status;
147  const char *str;
148 } jack_status_table[] = {
149  { JackFailure, "Failure" },
150  { JackInvalidOption, "Invalid Option" },
151  { JackNameNotUnique, "Name Not Unique" },
152  { JackServerStarted, "Server Started" },
153  { JackServerFailed, "Server Failed" },
154  { JackServerError, "Server Error" },
155  { JackNoSuchClient, "No Such Client" },
156  { JackLoadFailure, "Load Failure" },
157  { JackInitFailure, "Init Failure" },
158  { JackShmFailure, "Shared Memory Access Failure" },
159  { JackVersionError, "Version Mismatch" },
160 };
161 
162 static const char *jack_status_to_str(jack_status_t status)
163 {
164  int i;
165 
166  for (i = 0; i < ARRAY_LEN(jack_status_table); i++) {
167  if (jack_status_table[i].status == status)
168  return jack_status_table[i].str;
169  }
170 
171  return "Unknown Error";
172 }
173 
174 static void log_jack_status(const char *prefix, jack_status_t status)
175 {
176  struct ast_str *str = ast_str_alloca(512);
177  int i, first = 0;
178 
179  for (i = 0; i < (sizeof(status) * 8); i++) {
180  if (!(status & (1 << i)))
181  continue;
182 
183  if (!first) {
184  ast_str_set(&str, 0, "%s", jack_status_to_str((1 << i)));
185  first = 1;
186  } else
187  ast_str_append(&str, 0, ", %s", jack_status_to_str((1 << i)));
188  }
189 
190  ast_log(LOG_NOTICE, "%s: %s\n", prefix, ast_str_buffer(str));
191 }
192 
193 static int alloc_resampler(struct jack_data *jack_data, int input)
194 {
195  double from_srate, to_srate, jack_srate;
196  void **resampler;
197  double *resample_factor;
198 
199  if (input && jack_data->input_resampler)
200  return 0;
201 
202  if (!input && jack_data->output_resampler)
203  return 0;
204 
205  jack_srate = jack_get_sample_rate(jack_data->client);
206 
207  to_srate = input ? jack_data->audiohook_rate : jack_srate;
208  from_srate = input ? jack_srate : jack_data->audiohook_rate;
209 
210  resample_factor = input ? &jack_data->input_resample_factor :
211  &jack_data->output_resample_factor;
212 
213  if (from_srate == to_srate) {
214  /* Awesome! The jack sample rate is the same as ours.
215  * Resampling isn't needed. */
216  *resample_factor = 1.0;
217  return 0;
218  }
219 
220  *resample_factor = to_srate / from_srate;
221 
222  resampler = input ? &jack_data->input_resampler :
223  &jack_data->output_resampler;
224 
225  if (!(*resampler = resample_open(RESAMPLE_QUALITY,
226  *resample_factor, *resample_factor))) {
227  ast_log(LOG_ERROR, "Failed to open %s resampler\n",
228  input ? "input" : "output");
229  return -1;
230  }
231 
232  return 0;
233 }
234 
235 /*!
236  * \brief Handle jack input port
237  *
238  * Read nframes number of samples from the input buffer, resample it
239  * if necessary, and write it into the appropriate ringbuffer.
240  */
241 static void handle_input(void *buf, jack_nframes_t nframes,
242  struct jack_data *jack_data)
243 {
244  short s_buf[nframes];
245  float *in_buf = buf;
246  size_t res;
247  int i;
248  size_t write_len = sizeof(s_buf);
249 
250  if (jack_data->input_resampler) {
251  int total_in_buf_used = 0;
252  int total_out_buf_used = 0;
253  float f_buf[nframes + 1];
254 
255  memset(f_buf, 0, sizeof(f_buf));
256 
257  while (total_in_buf_used < nframes) {
258  int in_buf_used;
259  int out_buf_used;
260 
261  out_buf_used = resample_process(jack_data->input_resampler,
262  jack_data->input_resample_factor,
263  &in_buf[total_in_buf_used], nframes - total_in_buf_used,
264  0, &in_buf_used,
265  &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used);
266 
267  if (out_buf_used < 0)
268  break;
269 
270  total_out_buf_used += out_buf_used;
271  total_in_buf_used += in_buf_used;
272 
273  if (total_out_buf_used == ARRAY_LEN(f_buf)) {
274  ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size, "
275  "nframes '%d', total_out_buf_used '%d'\n", nframes, total_out_buf_used);
276  break;
277  }
278  }
279 
280  for (i = 0; i < total_out_buf_used; i++)
281  s_buf[i] = f_buf[i] * (SHRT_MAX / 1.0);
282 
283  write_len = total_out_buf_used * sizeof(int16_t);
284  } else {
285  /* No resampling needed */
286 
287  for (i = 0; i < nframes; i++)
288  s_buf[i] = in_buf[i] * (SHRT_MAX / 1.0);
289  }
290 
291  res = jack_ringbuffer_write(jack_data->input_rb, (const char *) s_buf, write_len);
292  if (res != write_len) {
293  ast_log(LOG_WARNING, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
294  (int) sizeof(s_buf), (int) res);
295  }
296 }
297 
298 /*!
299  * \brief Handle jack output port
300  *
301  * Read nframes number of samples from the ringbuffer and write it out to the
302  * output port buffer.
303  */
304 static void handle_output(void *buf, jack_nframes_t nframes,
305  struct jack_data *jack_data)
306 {
307  size_t res, len;
308 
309  len = nframes * sizeof(float);
310 
311  res = jack_ringbuffer_read(jack_data->output_rb, buf, len);
312 
313  if (len != res) {
314  ast_debug(2, "Wanted %d bytes to send to the output port, "
315  "but only got %d\n", (int) len, (int) res);
316  }
317 }
318 
319 static int jack_process(jack_nframes_t nframes, void *arg)
320 {
321  struct jack_data *jack_data = arg;
322  void *input_port_buf, *output_port_buf;
323 
324  if (!jack_data->input_resample_factor)
325  alloc_resampler(jack_data, 1);
326 
327  input_port_buf = jack_port_get_buffer(jack_data->input_port, nframes);
328  handle_input(input_port_buf, nframes, jack_data);
329 
330  output_port_buf = jack_port_get_buffer(jack_data->output_port, nframes);
331  handle_output(output_port_buf, nframes, jack_data);
332 
333  return 0;
334 }
335 
336 static void jack_shutdown(void *arg)
337 {
338  struct jack_data *jack_data = arg;
339 
340  jack_data->stop = 1;
341 }
342 
343 static struct jack_data *destroy_jack_data(struct jack_data *jack_data)
344 {
345  if (jack_data->input_port) {
346  jack_port_unregister(jack_data->client, jack_data->input_port);
347  jack_data->input_port = NULL;
348  }
349 
350  if (jack_data->output_port) {
351  jack_port_unregister(jack_data->client, jack_data->output_port);
352  jack_data->output_port = NULL;
353  }
354 
355  if (jack_data->client) {
356  jack_client_close(jack_data->client);
357  jack_data->client = NULL;
358  }
359 
360  if (jack_data->input_rb) {
361  jack_ringbuffer_free(jack_data->input_rb);
362  jack_data->input_rb = NULL;
363  }
364 
365  if (jack_data->output_rb) {
366  jack_ringbuffer_free(jack_data->output_rb);
367  jack_data->output_rb = NULL;
368  }
369 
370  if (jack_data->output_resampler) {
371  resample_close(jack_data->output_resampler);
372  jack_data->output_resampler = NULL;
373  }
374 
375  if (jack_data->input_resampler) {
376  resample_close(jack_data->input_resampler);
377  jack_data->input_resampler = NULL;
378  }
379 
380  if (jack_data->has_audiohook)
381  ast_audiohook_destroy(&jack_data->audiohook);
382 
383  ast_string_field_free_memory(jack_data);
384 
385  ast_free(jack_data);
386 
387  return NULL;
388 }
389 
390 static int init_jack_data(struct ast_channel *chan, struct jack_data *jack_data)
391 {
392  const char *client_name;
393  jack_status_t status = 0;
394  jack_options_t jack_options = JackNullOption;
395 
396  unsigned int channel_rate;
397 
398  unsigned int ringbuffer_size;
399 
400  /* Deducing audiohook sample rate from channel format
401  ATTENTION: Might be problematic, if channel has different sampling than used by audiohook!
402  */
403  channel_rate = ast_format_get_sample_rate(ast_channel_readformat(chan));
404  jack_data->audiohook_format = ast_format_cache_get_slin_by_rate(channel_rate);
405  jack_data->audiohook_rate = ast_format_get_sample_rate(jack_data->audiohook_format);
406 
407  /* Guessing frame->datalen assuming a ptime of 20ms */
408  jack_data->frame_datalen = jack_data->audiohook_rate / 50;
409 
410  ringbuffer_size = jack_data->frame_datalen * RINGBUFFER_FRAME_CAPACITY;
411 
412  ast_debug(1, "Audiohook parameters: slin-format:%s, rate:%d, frame-len:%d, ringbuffer_size: %d\n",
413  ast_format_get_name(jack_data->audiohook_format), jack_data->audiohook_rate, jack_data->frame_datalen, ringbuffer_size);
414 
415  if (!ast_strlen_zero(jack_data->client_name)) {
416  client_name = jack_data->client_name;
417  } else {
418  ast_channel_lock(chan);
419  client_name = ast_strdupa(ast_channel_name(chan));
420  ast_channel_unlock(chan);
421  }
422 
423  if (!(jack_data->output_rb = jack_ringbuffer_create(ringbuffer_size)))
424  return -1;
425 
426  if (!(jack_data->input_rb = jack_ringbuffer_create(ringbuffer_size)))
427  return -1;
428 
429  if (jack_data->no_start_server)
430  jack_options |= JackNoStartServer;
431 
432  if (!ast_strlen_zero(jack_data->server_name)) {
433  jack_options |= JackServerName;
434  jack_data->client = jack_client_open(client_name, jack_options, &status,
435  jack_data->server_name);
436  } else {
437  jack_data->client = jack_client_open(client_name, jack_options, &status);
438  }
439 
440  if (status)
441  log_jack_status("Client Open Status", status);
442 
443  if (!jack_data->client)
444  return -1;
445 
446  jack_data->input_port = jack_port_register(jack_data->client, "input",
447  JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0);
448  if (!jack_data->input_port) {
449  ast_log(LOG_ERROR, "Failed to create input port for jack port\n");
450  return -1;
451  }
452 
453  jack_data->output_port = jack_port_register(jack_data->client, "output",
454  JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0);
455  if (!jack_data->output_port) {
456  ast_log(LOG_ERROR, "Failed to create output port for jack port\n");
457  return -1;
458  }
459 
460  if (jack_set_process_callback(jack_data->client, jack_process, jack_data)) {
461  ast_log(LOG_ERROR, "Failed to register process callback with jack client\n");
462  return -1;
463  }
464 
465  jack_on_shutdown(jack_data->client, jack_shutdown, jack_data);
466 
467  if (jack_activate(jack_data->client)) {
468  ast_log(LOG_ERROR, "Unable to activate jack client\n");
469  return -1;
470  }
471 
472  while (!ast_strlen_zero(jack_data->connect_input_port)) {
473  const char **ports;
474  int i;
475 
476  ports = jack_get_ports(jack_data->client, jack_data->connect_input_port,
477  NULL, JackPortIsInput);
478 
479  if (!ports) {
480  ast_log(LOG_ERROR, "No input port matching '%s' was found\n",
481  jack_data->connect_input_port);
482  break;
483  }
484 
485  for (i = 0; ports[i]; i++) {
486  ast_debug(1, "Found port '%s' that matched specified input port '%s'\n",
487  ports[i], jack_data->connect_input_port);
488  }
489 
490  if (jack_connect(jack_data->client, jack_port_name(jack_data->output_port), ports[0])) {
491  ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0],
492  jack_port_name(jack_data->output_port));
493  } else {
494  ast_debug(1, "Connected '%s' to '%s'\n", ports[0],
495  jack_port_name(jack_data->output_port));
496  }
497 
498  jack_free(ports);
499 
500  break;
501  }
502 
503  while (!ast_strlen_zero(jack_data->connect_output_port)) {
504  const char **ports;
505  int i;
506 
507  ports = jack_get_ports(jack_data->client, jack_data->connect_output_port,
508  NULL, JackPortIsOutput);
509 
510  if (!ports) {
511  ast_log(LOG_ERROR, "No output port matching '%s' was found\n",
512  jack_data->connect_output_port);
513  break;
514  }
515 
516  for (i = 0; ports[i]; i++) {
517  ast_debug(1, "Found port '%s' that matched specified output port '%s'\n",
518  ports[i], jack_data->connect_output_port);
519  }
520 
521  if (jack_connect(jack_data->client, ports[0], jack_port_name(jack_data->input_port))) {
522  ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0],
523  jack_port_name(jack_data->input_port));
524  } else {
525  ast_debug(1, "Connected '%s' to '%s'\n", ports[0],
526  jack_port_name(jack_data->input_port));
527  }
528 
529  jack_free(ports);
530 
531  break;
532  }
533 
534  return 0;
535 }
536 
537 static int queue_voice_frame(struct jack_data *jack_data, struct ast_frame *f)
538 {
539  float f_buf[f->samples * 8];
540  size_t f_buf_used = 0;
541  int i;
542  int16_t *s_buf = f->data.ptr;
543  size_t res;
544 
545  memset(f_buf, 0, sizeof(f_buf));
546 
547  if (!jack_data->output_resample_factor)
548  alloc_resampler(jack_data, 0);
549 
550  if (jack_data->output_resampler) {
551  float in_buf[f->samples];
552  int total_in_buf_used = 0;
553  int total_out_buf_used = 0;
554 
555  memset(in_buf, 0, sizeof(in_buf));
556 
557  for (i = 0; i < f->samples; i++)
558  in_buf[i] = s_buf[i] * (1.0 / SHRT_MAX);
559 
560  while (total_in_buf_used < ARRAY_LEN(in_buf)) {
561  int in_buf_used;
562  int out_buf_used;
563 
564  out_buf_used = resample_process(jack_data->output_resampler,
565  jack_data->output_resample_factor,
566  &in_buf[total_in_buf_used], ARRAY_LEN(in_buf) - total_in_buf_used,
567  0, &in_buf_used,
568  &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used);
569 
570  if (out_buf_used < 0)
571  break;
572 
573  total_out_buf_used += out_buf_used;
574  total_in_buf_used += in_buf_used;
575 
576  if (total_out_buf_used == ARRAY_LEN(f_buf)) {
577  ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size\n");
578  break;
579  }
580  }
581 
582  f_buf_used = total_out_buf_used;
583  if (f_buf_used > ARRAY_LEN(f_buf))
584  f_buf_used = ARRAY_LEN(f_buf);
585  } else {
586  /* No resampling needed */
587 
588  for (i = 0; i < f->samples; i++)
589  f_buf[i] = s_buf[i] * (1.0 / SHRT_MAX);
590 
591  f_buf_used = f->samples;
592  }
593 
594  res = jack_ringbuffer_write(jack_data->output_rb, (const char *) f_buf, f_buf_used * sizeof(float));
595  if (res != (f_buf_used * sizeof(float))) {
596  ast_log(LOG_WARNING, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
597  (int) (f_buf_used * sizeof(float)), (int) res);
598  }
599  return 0;
600 }
601 
602 /*!
603  * \brief handle jack audio
604  *
605  * \param[in] chan The Asterisk channel to write the frames to if no output frame
606  * is provided.
607  * \param[in] jack_data This is the jack_data struct that contains the input
608  * ringbuffer that audio will be read from.
609  * \param[out] out_frame If this argument is non-NULL, then assuming there is
610  * enough data avilable in the ringbuffer, the audio in this frame
611  * will get replaced with audio from the input buffer. If there is
612  * not enough data available to read at this time, then the frame
613  * data gets zeroed out.
614  *
615  * Read data from the input ringbuffer, which is the properly resampled audio
616  * that was read from the jack input port. Write it to the channel in 20 ms frames,
617  * or fill up an output frame instead if one is provided.
618  */
619 static void handle_jack_audio(struct ast_channel *chan, struct jack_data *jack_data,
620  struct ast_frame *out_frame)
621 {
622  short buf[jack_data->frame_datalen];
623  struct ast_frame f = {
625  .subclass.format = jack_data->audiohook_format,
626  .src = "JACK",
627  .data.ptr = buf,
628  .datalen = sizeof(buf),
629  .samples = ARRAY_LEN(buf),
630  };
631 
632  for (;;) {
633  size_t res, read_len;
634  char *read_buf;
635 
636  read_len = out_frame ? out_frame->datalen : sizeof(buf);
637  read_buf = out_frame ? out_frame->data.ptr : buf;
638 
639  res = jack_ringbuffer_read_space(jack_data->input_rb);
640 
641  if (res < read_len) {
642  /* Not enough data ready for another frame, move on ... */
643  if (out_frame) {
644  ast_debug(1, "Sending an empty frame for the JACK_HOOK\n");
645  memset(out_frame->data.ptr, 0, out_frame->datalen);
646  }
647  break;
648  }
649 
650  res = jack_ringbuffer_read(jack_data->input_rb, (char *) read_buf, read_len);
651 
652  if (res < read_len) {
653  ast_log(LOG_ERROR, "Error reading from ringbuffer, even though it said there was enough data\n");
654  break;
655  }
656 
657  if (out_frame) {
658  /* If an output frame was provided, then we just want to fill up the
659  * buffer in that frame and return. */
660  break;
661  }
662 
663  ast_write(chan, &f);
664  }
665 }
666 
667 enum {
668  OPT_SERVER_NAME = (1 << 0),
669  OPT_INPUT_PORT = (1 << 1),
670  OPT_OUTPUT_PORT = (1 << 2),
671  OPT_NOSTART_SERVER = (1 << 3),
672  OPT_CLIENT_NAME = (1 << 4),
673 };
674 
675 enum {
676  OPT_ARG_SERVER_NAME,
677  OPT_ARG_INPUT_PORT,
678  OPT_ARG_OUTPUT_PORT,
679  OPT_ARG_CLIENT_NAME,
680 
681  /* Must be the last element */
682  OPT_ARG_ARRAY_SIZE,
683 };
684 
685 AST_APP_OPTIONS(jack_exec_options, BEGIN_OPTIONS
686  AST_APP_OPTION_ARG('s', OPT_SERVER_NAME, OPT_ARG_SERVER_NAME),
687  AST_APP_OPTION_ARG('i', OPT_INPUT_PORT, OPT_ARG_INPUT_PORT),
688  AST_APP_OPTION_ARG('o', OPT_OUTPUT_PORT, OPT_ARG_OUTPUT_PORT),
689  AST_APP_OPTION('n', OPT_NOSTART_SERVER),
690  AST_APP_OPTION_ARG('c', OPT_CLIENT_NAME, OPT_ARG_CLIENT_NAME),
691 END_OPTIONS );
692 
693 static struct jack_data *jack_data_alloc(void)
694 {
695  struct jack_data *jack_data;
696 
697  if (!(jack_data = ast_calloc_with_stringfields(1, struct jack_data, 32))) {
698  return NULL;
699  }
700 
701  return jack_data;
702 }
703 
704 /*!
705  * \note This must be done before calling init_jack_data().
706  */
707 static int handle_options(struct jack_data *jack_data, const char *__options_str)
708 {
709  struct ast_flags options = { 0, };
710  char *option_args[OPT_ARG_ARRAY_SIZE];
711  char *options_str;
712 
713  options_str = ast_strdupa(__options_str);
714 
715  ast_app_parse_options(jack_exec_options, &options, option_args, options_str);
716 
717  if (ast_test_flag(&options, OPT_SERVER_NAME)) {
718  if (!ast_strlen_zero(option_args[OPT_ARG_SERVER_NAME]))
719  ast_string_field_set(jack_data, server_name, option_args[OPT_ARG_SERVER_NAME]);
720  else {
721  ast_log(LOG_ERROR, "A server name must be provided with the s() option\n");
722  return -1;
723  }
724  }
725 
726  if (ast_test_flag(&options, OPT_CLIENT_NAME)) {
727  if (!ast_strlen_zero(option_args[OPT_ARG_CLIENT_NAME]))
728  ast_string_field_set(jack_data, client_name, option_args[OPT_ARG_CLIENT_NAME]);
729  else {
730  ast_log(LOG_ERROR, "A client name must be provided with the c() option\n");
731  return -1;
732  }
733  }
734 
735  if (ast_test_flag(&options, OPT_INPUT_PORT)) {
736  if (!ast_strlen_zero(option_args[OPT_ARG_INPUT_PORT]))
737  ast_string_field_set(jack_data, connect_input_port, option_args[OPT_ARG_INPUT_PORT]);
738  else {
739  ast_log(LOG_ERROR, "A name must be provided with the i() option\n");
740  return -1;
741  }
742  }
743 
744  if (ast_test_flag(&options, OPT_OUTPUT_PORT)) {
745  if (!ast_strlen_zero(option_args[OPT_ARG_OUTPUT_PORT]))
746  ast_string_field_set(jack_data, connect_output_port, option_args[OPT_ARG_OUTPUT_PORT]);
747  else {
748  ast_log(LOG_ERROR, "A name must be provided with the o() option\n");
749  return -1;
750  }
751  }
752 
753  jack_data->no_start_server = ast_test_flag(&options, OPT_NOSTART_SERVER) ? 1 : 0;
754 
755  return 0;
756 }
757 
758 static int jack_exec(struct ast_channel *chan, const char *data)
759 {
760  struct jack_data *jack_data;
761 
762  if (!(jack_data = jack_data_alloc()))
763  return -1;
764 
765  if (!ast_strlen_zero(data) && handle_options(jack_data, data)) {
766  destroy_jack_data(jack_data);
767  return -1;
768  }
769 
770  if (init_jack_data(chan, jack_data)) {
771  destroy_jack_data(jack_data);
772  return -1;
773  }
774 
775  if (ast_set_read_format(chan, jack_data->audiohook_format)) {
776  destroy_jack_data(jack_data);
777  return -1;
778  }
779 
780  if (ast_set_write_format(chan, jack_data->audiohook_format)) {
781  destroy_jack_data(jack_data);
782  return -1;
783  }
784 
785  while (!jack_data->stop) {
786  struct ast_frame *f;
787 
788  if (ast_waitfor(chan, -1) < 0) {
789  break;
790  }
791 
792  f = ast_read(chan);
793  if (!f) {
794  jack_data->stop = 1;
795  continue;
796  }
797 
798  switch (f->frametype) {
799  case AST_FRAME_CONTROL:
801  jack_data->stop = 1;
802  break;
803  case AST_FRAME_VOICE:
804  queue_voice_frame(jack_data, f);
805  default:
806  break;
807  }
808 
809  ast_frfree(f);
810 
811  handle_jack_audio(chan, jack_data, NULL);
812  }
813 
814  jack_data = destroy_jack_data(jack_data);
815 
816  return 0;
817 }
818 
819 static void jack_hook_ds_destroy(void *data)
820 {
821  struct jack_data *jack_data = data;
822 
823  destroy_jack_data(jack_data);
824 }
825 
826 static const struct ast_datastore_info jack_hook_ds_info = {
827  .type = "JACK_HOOK",
828  .destroy = jack_hook_ds_destroy,
829 };
830 
831 static int jack_hook_callback(struct ast_audiohook *audiohook, struct ast_channel *chan,
832  struct ast_frame *frame, enum ast_audiohook_direction direction)
833 {
834  struct ast_datastore *datastore;
835  struct jack_data *jack_data;
836 
837  if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
838  return 0;
839 
840  if (direction != AST_AUDIOHOOK_DIRECTION_READ)
841  return 0;
842 
843  if (frame->frametype != AST_FRAME_VOICE)
844  return 0;
845 
846  ast_channel_lock(chan);
847 
848  if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
849  ast_log(LOG_ERROR, "JACK_HOOK datastore not found for '%s'\n", ast_channel_name(chan));
850  ast_channel_unlock(chan);
851  return -1;
852  }
853 
854  jack_data = datastore->data;
855 
856  if (ast_format_cmp(frame->subclass.format, jack_data->audiohook_format) == AST_FORMAT_CMP_NOT_EQUAL) {
857  ast_log(LOG_WARNING, "Expected frame in %s for the audiohook, but got format %s\n",
858  ast_format_get_name(jack_data->audiohook_format),
860  ast_channel_unlock(chan);
861  return 0;
862  }
863 
864  queue_voice_frame(jack_data, frame);
865 
866  handle_jack_audio(chan, jack_data, frame);
867 
868  ast_channel_unlock(chan);
869 
870  return 0;
871 }
872 
873 static int enable_jack_hook(struct ast_channel *chan, char *data)
874 {
875  struct ast_datastore *datastore;
876  struct jack_data *jack_data = NULL;
878  AST_APP_ARG(mode);
879  AST_APP_ARG(options);
880  );
881 
882  AST_STANDARD_APP_ARGS(args, data);
883 
884  ast_channel_lock(chan);
885 
886  if ((datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
887  ast_log(LOG_ERROR, "JACK_HOOK already enabled for '%s'\n", ast_channel_name(chan));
888  goto return_error;
889  }
890 
891  if (ast_strlen_zero(args.mode) || strcasecmp(args.mode, "manipulate")) {
892  ast_log(LOG_ERROR, "'%s' is not a supported mode. Only manipulate is supported.\n",
893  S_OR(args.mode, "<none>"));
894  goto return_error;
895  }
896 
897  if (!(jack_data = jack_data_alloc()))
898  goto return_error;
899 
900  if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options))
901  goto return_error;
902 
903  if (init_jack_data(chan, jack_data))
904  goto return_error;
905 
906  if (!(datastore = ast_datastore_alloc(&jack_hook_ds_info, NULL)))
907  goto return_error;
908 
909  jack_data->has_audiohook = 1;
911  jack_data->audiohook.manipulate_callback = jack_hook_callback;
912 
913  datastore->data = jack_data;
914 
915  if (ast_audiohook_attach(chan, &jack_data->audiohook))
916  goto return_error;
917 
918  if (ast_channel_datastore_add(chan, datastore))
919  goto return_error;
920 
921  ast_channel_unlock(chan);
922 
923  return 0;
924 
925 return_error:
926  ast_channel_unlock(chan);
927 
928  if (jack_data) {
929  destroy_jack_data(jack_data);
930  }
931 
932  if (datastore) {
933  datastore->data = NULL;
934  ast_datastore_free(datastore);
935  }
936 
937  return -1;
938 }
939 
940 static int disable_jack_hook(struct ast_channel *chan)
941 {
942  struct ast_datastore *datastore;
943  struct jack_data *jack_data;
944 
945  ast_channel_lock(chan);
946 
947  if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
948  ast_channel_unlock(chan);
949  ast_log(LOG_WARNING, "No JACK_HOOK found to disable\n");
950  return -1;
951  }
952 
953  ast_channel_datastore_remove(chan, datastore);
954 
955  jack_data = datastore->data;
956  ast_audiohook_detach(&jack_data->audiohook);
957 
958  /* Keep the channel locked while we destroy the datastore, so that we can
959  * ensure that all of the jack stuff is stopped just in case another frame
960  * tries to come through the audiohook callback. */
961  ast_datastore_free(datastore);
962 
963  ast_channel_unlock(chan);
964 
965  return 0;
966 }
967 
968 static int jack_hook_write(struct ast_channel *chan, const char *cmd, char *data,
969  const char *value)
970 {
971  int res;
972 
973  if (!chan) {
974  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
975  return -1;
976  }
977 
978  if (!strcasecmp(value, "on"))
979  res = enable_jack_hook(chan, data);
980  else if (!strcasecmp(value, "off"))
981  res = disable_jack_hook(chan);
982  else {
983  ast_log(LOG_ERROR, "'%s' is not a valid value for JACK_HOOK()\n", value);
984  res = -1;
985  }
986 
987  return res;
988 }
989 
990 static struct ast_custom_function jack_hook_function = {
991  .name = "JACK_HOOK",
992  .synopsis = "Enable a jack hook on a channel",
993  .syntax = "JACK_HOOK(<mode>,[options])",
994  .desc =
995  " The JACK_HOOK allows turning on or off jack connectivity to this channel.\n"
996  "When the JACK_HOOK is turned on, jack ports will get created that allow\n"
997  "access to the audio stream for this channel. The mode specifies which mode\n"
998  "this hook should run in. A mode must be specified when turning the JACK_HOOK.\n"
999  "on. However, all arguments are optional when turning it off.\n"
1000  "\n"
1001  " Valid modes are:\n"
1002 #if 0
1003  /* XXX TODO */
1004  " spy - Create a read-only audio hook. Only an output jack port will\n"
1005  " get created.\n"
1006  " whisper - Create a write-only audio hook. Only an input jack port will\n"
1007  " get created.\n"
1008 #endif
1009  " manipulate - Create a read/write audio hook. Both an input and an output\n"
1010  " jack port will get created. Audio from the channel will be\n"
1011  " sent out the output port and will be replaced by the audio\n"
1012  " coming in on the input port as it gets passed on.\n"
1013  "\n"
1014  " Valid options are:\n"
1016  "\n"
1017  " Examples:\n"
1018  " To turn on the JACK_HOOK,\n"
1019  " Set(JACK_HOOK(manipulate,i(pure_data_0:input0)o(pure_data_0:output0))=on)\n"
1020  " To turn off the JACK_HOOK,\n"
1021  " Set(JACK_HOOK()=off)\n"
1022  "",
1023  .write = jack_hook_write,
1024 };
1025 
1026 static int unload_module(void)
1027 {
1028  int res;
1029 
1030  res = ast_unregister_application(jack_app);
1031  res |= ast_custom_function_unregister(&jack_hook_function);
1032 
1033  return res;
1034 }
1035 
1036 static int load_module(void)
1037 {
1038  if (ast_register_application_xml(jack_app, jack_exec)) {
1039  return AST_MODULE_LOAD_DECLINE;
1040  }
1041 
1042  if (ast_custom_function_register(&jack_hook_function)) {
1043  ast_unregister_application(jack_app);
1044  return AST_MODULE_LOAD_DECLINE;
1045  }
1046 
1047  return AST_MODULE_LOAD_SUCCESS;
1048 }
1049 
1050 AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "JACK Interface");
const char * name
Definition: pbx.h:119
const char * type
Definition: datastore.h:32
Main Channel structure associated with a channel.
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
String manipulation functions.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
Audiohooks Architecture.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
static void handle_input(void *buf, jack_nframes_t nframes, struct jack_data *jack_data)
Handle jack input port.
Definition: app_jack.c:241
static int handle_options(struct jack_data *jack_data, const char *__options_str)
Definition: app_jack.c:707
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4257
Structure for a data store type.
Definition: datastore.h:31
#define ast_calloc_with_stringfields(n, type, size)
Allocate a structure with embedded stringfields in a single allocation.
Definition: stringfields.h:432
Definition of a media format.
Definition: format.c:43
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition: audiohook.c:484
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
Structure for a data store object.
Definition: datastore.h:64
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2399
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition: audiohook.c:124
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
struct ast_frame_subclass subclass
static void handle_output(void *buf, jack_nframes_t nframes, struct jack_data *jack_data)
Handle jack output port.
Definition: app_jack.c:304
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
ast_audiohook_manipulate_callback manipulate_callback
Definition: audiohook.h:118
int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source, enum ast_audiohook_init_flags flags)
Initialize an audiohook structure.
Definition: audiohook.c:100
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
#define COMMON_OPTIONS
Common options between the Jack() app and JACK_HOOK() function.
Definition: app_jack.c:67
enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
Compare two formats.
Definition: format.c:201
General Asterisk PBX channel definitions.
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition: channel.c:5762
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:303
#define ast_debug(level,...)
Log a DEBUG message.
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5803
static void handle_jack_audio(struct ast_channel *chan, struct jack_data *jack_data, struct ast_frame *out_frame)
handle jack audio
Definition: app_jack.c:619
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: main/app.c:3066
Core PBX routines and definitions.
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
Definition: audiohook.c:550
Support for dynamic strings.
Definition: strings.h:623
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
unsigned int stop
Definition: res_smdi.c:217
union ast_frame::@224 data
int ast_write(struct ast_channel *chan, struct ast_frame *frame)
Write a frame to a channel This function writes the given frame to the indicated channel.
Definition: channel.c:5144
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
Structure used to handle boolean flags.
Definition: utils.h:199
ast_audiohook_direction
Definition: audiohook.h:48
void * data
Definition: datastore.h:66
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3162
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:80
unsigned int ast_format_get_sample_rate(const struct ast_format *format)
Get the sample rate of a media format.
Definition: format.c:379
Data structure associated with a single frame of data.
enum ast_audiohook_status status
Definition: audiohook.h:108
enum ast_frame_type frametype
struct ast_audiohook audiohook
Definition: app_jack.c:142
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
struct ast_format * format
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2385
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2394
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1558
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640
struct ast_format * ast_format_cache_get_slin_by_rate(unsigned int rate)
Retrieve the best signed linear format given a sample rate.
Definition: format_cache.c:512
Media Format Cache API.
#define AST_APP_ARG(name)
Define an application argument.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521