Asterisk - The Open Source Telephony Project  21.4.1
Data Structures | Macros | Enumerations | Functions | Variables
app_jack.c File Reference

Jack Application. More...

#include "asterisk.h"
#include <limits.h>
#include <jack/jack.h>
#include <jack/ringbuffer.h>
#include <libresample.h>
#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/strings.h"
#include "asterisk/lock.h"
#include "asterisk/app.h"
#include "asterisk/pbx.h"
#include "asterisk/audiohook.h"
#include "asterisk/format_cache.h"

Go to the source code of this file.

Data Structures

struct  jack_data
 

Macros

#define COMMON_OPTIONS
 Common options between the Jack() app and JACK_HOOK() function.
 
#define RESAMPLE_QUALITY   1
 
#define RINGBUFFER_FRAME_CAPACITY   100
 

Enumerations

enum  {
  OPT_SERVER_NAME = (1 << 0), OPT_INPUT_PORT = (1 << 1), OPT_OUTPUT_PORT = (1 << 2), OPT_NOSTART_SERVER = (1 << 3),
  OPT_CLIENT_NAME = (1 << 4)
}
 
enum  {
  OPT_ARG_SERVER_NAME, OPT_ARG_INPUT_PORT, OPT_ARG_OUTPUT_PORT, OPT_ARG_CLIENT_NAME,
  OPT_ARG_ARRAY_SIZE
}
 

Functions

static int alloc_resampler (struct jack_data *jack_data, int input)
 
 AST_MODULE_INFO_STANDARD_EXTENDED (ASTERISK_GPL_KEY,"JACK Interface")
 
static struct jack_datadestroy_jack_data (struct jack_data *jack_data)
 
static int disable_jack_hook (struct ast_channel *chan)
 
static int enable_jack_hook (struct ast_channel *chan, char *data)
 
static void handle_input (void *buf, jack_nframes_t nframes, struct jack_data *jack_data)
 Handle jack input port. More...
 
static void handle_jack_audio (struct ast_channel *chan, struct jack_data *jack_data, struct ast_frame *out_frame)
 handle jack audio More...
 
static int handle_options (struct jack_data *jack_data, const char *__options_str)
 
static void handle_output (void *buf, jack_nframes_t nframes, struct jack_data *jack_data)
 Handle jack output port. More...
 
static int init_jack_data (struct ast_channel *chan, struct jack_data *jack_data)
 
static struct jack_datajack_data_alloc (void)
 
static int jack_exec (struct ast_channel *chan, const char *data)
 
static int jack_hook_callback (struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
 
static void jack_hook_ds_destroy (void *data)
 
static int jack_hook_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
 
static int jack_process (jack_nframes_t nframes, void *arg)
 
static void jack_shutdown (void *arg)
 
static const char * jack_status_to_str (jack_status_t status)
 
static int load_module (void)
 
static void log_jack_status (const char *prefix, jack_status_t status)
 
static int queue_voice_frame (struct jack_data *jack_data, struct ast_frame *f)
 
static int unload_module (void)
 

Variables

static const char jack_app [] = "JACK"
 
static const struct ast_app_option jack_exec_options [128] = { [ 's' ] = { .flag = OPT_SERVER_NAME , .arg_index = OPT_ARG_SERVER_NAME + 1 }, [ 'i' ] = { .flag = OPT_INPUT_PORT , .arg_index = OPT_ARG_INPUT_PORT + 1 }, [ 'o' ] = { .flag = OPT_OUTPUT_PORT , .arg_index = OPT_ARG_OUTPUT_PORT + 1 }, [ 'n' ] = { .flag = OPT_NOSTART_SERVER }, [ 'c' ] = { .flag = OPT_CLIENT_NAME , .arg_index = OPT_ARG_CLIENT_NAME + 1 }, }
 
static const struct ast_datastore_info jack_hook_ds_info
 
static struct ast_custom_function jack_hook_function
 
struct {
   jack_status_t   status
 
   const char *   str
 
jack_status_table []
 

Detailed Description

Jack Application.

Author
Russell Bryant russe.nosp@m.ll@d.nosp@m.igium.nosp@m..com

This is an application to connect an Asterisk channel to an input and output jack port so that the audio can be processed through another application, or to play audio from another application.

ExtRef:
http://www.jackaudio.org/
Note
To install libresample, check it out of the following repository: $ svn co http://svn.digium.com/svn/thirdparty/libresample/trunk

Definition in file app_jack.c.

Function Documentation

static void handle_input ( void *  buf,
jack_nframes_t  nframes,
struct jack_data jack_data 
)
static

Handle jack input port.

Read nframes number of samples from the input buffer, resample it if necessary, and write it into the appropriate ringbuffer.

Definition at line 241 of file app_jack.c.

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 }
static void handle_jack_audio ( struct ast_channel chan,
struct jack_data jack_data,
struct ast_frame out_frame 
)
static

handle jack audio

Parameters
[in]chanThe Asterisk channel to write the frames to if no output frame is provided.
[in]jack_dataThis is the jack_data struct that contains the input ringbuffer that audio will be read from.
[out]out_frameIf this argument is non-NULL, then assuming there is enough data avilable in the ringbuffer, the audio in this frame will get replaced with audio from the input buffer. If there is not enough data available to read at this time, then the frame data gets zeroed out.

Read data from the input ringbuffer, which is the properly resampled audio that was read from the jack input port. Write it to the channel in 20 ms frames, or fill up an output frame instead if one is provided.

Definition at line 619 of file app_jack.c.

References ast_debug, AST_FRAME_VOICE, ast_write(), ast_frame::data, ast_frame::datalen, ast_frame::frametype, and ast_frame::samples.

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 }
#define ast_debug(level,...)
Log a DEBUG message.
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
Data structure associated with a single frame of data.
enum ast_frame_type frametype
static int handle_options ( struct jack_data jack_data,
const char *  __options_str 
)
static
Note
This must be done before calling init_jack_data().

Definition at line 707 of file app_jack.c.

References ast_app_parse_options(), ast_strdupa, and ast_string_field_set.

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 }
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
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
Structure used to handle boolean flags.
Definition: utils.h:199
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
static void handle_output ( void *  buf,
jack_nframes_t  nframes,
struct jack_data jack_data 
)
static

Handle jack output port.

Read nframes number of samples from the ringbuffer and write it out to the output port buffer.

Definition at line 304 of file app_jack.c.

References ast_debug.

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 }
#define ast_debug(level,...)
Log a DEBUG message.

Variable Documentation

const struct ast_datastore_info jack_hook_ds_info
static
Initial value:
= {
.type = "JACK_HOOK",
.destroy = jack_hook_ds_destroy,
}

Definition at line 826 of file app_jack.c.