Asterisk - The Open Source Telephony Project  18.5.0
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"
Include dependency graph for app_jack.c:

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. More...
 
#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.

Macro Definition Documentation

◆ COMMON_OPTIONS

#define COMMON_OPTIONS

Common options between the Jack() app and JACK_HOOK() function.

Definition at line 67 of file app_jack.c.

◆ RESAMPLE_QUALITY

#define RESAMPLE_QUALITY   1

Definition at line 61 of file app_jack.c.

Referenced by alloc_resampler().

◆ RINGBUFFER_FRAME_CAPACITY

#define RINGBUFFER_FRAME_CAPACITY   100

Definition at line 64 of file app_jack.c.

Referenced by init_jack_data().

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
OPT_SERVER_NAME 
OPT_INPUT_PORT 
OPT_OUTPUT_PORT 
OPT_NOSTART_SERVER 
OPT_CLIENT_NAME 

Definition at line 669 of file app_jack.c.

669  {
670  OPT_SERVER_NAME = (1 << 0),
671  OPT_INPUT_PORT = (1 << 1),
672  OPT_OUTPUT_PORT = (1 << 2),
673  OPT_NOSTART_SERVER = (1 << 3),
674  OPT_CLIENT_NAME = (1 << 4),
675 };

◆ anonymous enum

anonymous enum
Enumerator
OPT_ARG_SERVER_NAME 
OPT_ARG_INPUT_PORT 
OPT_ARG_OUTPUT_PORT 
OPT_ARG_CLIENT_NAME 
OPT_ARG_ARRAY_SIZE 

Definition at line 677 of file app_jack.c.

Function Documentation

◆ alloc_resampler()

static int alloc_resampler ( struct jack_data jack_data,
int  input 
)
static

Definition at line 193 of file app_jack.c.

References ast_log, jack_data::audiohook_rate, jack_data::client, jack_data::input_resample_factor, jack_data::input_resampler, LOG_ERROR, jack_data::output_resample_factor, jack_data::output_resampler, and RESAMPLE_QUALITY.

Referenced by jack_process(), and queue_voice_frame().

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 }
void * output_resampler
Definition: app_jack.c:134
#define RESAMPLE_QUALITY
Definition: app_jack.c:61
static int input(yyscan_t yyscanner)
Definition: ast_expr2f.c:1584
void * input_resampler
Definition: app_jack.c:136
#define ast_log
Definition: astobj2.c:42
jack_client_t * client
Definition: app_jack.c:126
#define LOG_ERROR
Definition: logger.h:285
double input_resample_factor
Definition: app_jack.c:137
double output_resample_factor
Definition: app_jack.c:135
unsigned int audiohook_rate
Definition: app_jack.c:132

◆ AST_MODULE_INFO_STANDARD_EXTENDED()

AST_MODULE_INFO_STANDARD_EXTENDED ( ASTERISK_GPL_KEY  ,
"JACK Interface"   
)

Referenced by load_module().

◆ destroy_jack_data()

static struct jack_data* destroy_jack_data ( struct jack_data jack_data)
static

Definition at line 343 of file app_jack.c.

References ast_audiohook_destroy(), ast_free, ast_string_field_free_memory, jack_data::audiohook, jack_data::client, jack_data::has_audiohook, jack_data::input_port, jack_data::input_rb, jack_data::input_resampler, NULL, jack_data::output_port, jack_data::output_rb, and jack_data::output_resampler.

Referenced by enable_jack_hook(), jack_exec(), and jack_hook_ds_destroy().

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 }
unsigned int has_audiohook
Definition: app_jack.c:139
void * output_resampler
Definition: app_jack.c:134
#define NULL
Definition: resample.c:96
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition: audiohook.c:133
jack_port_t * output_port
Definition: app_jack.c:128
jack_port_t * input_port
Definition: app_jack.c:127
void * input_resampler
Definition: app_jack.c:136
jack_client_t * client
Definition: app_jack.c:126
jack_ringbuffer_t * input_rb
Definition: app_jack.c:129
jack_ringbuffer_t * output_rb
Definition: app_jack.c:130
#define ast_free(a)
Definition: astmm.h:182
struct ast_audiohook audiohook
Definition: app_jack.c:142
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:368

◆ disable_jack_hook()

static int disable_jack_hook ( struct ast_channel chan)
static

Definition at line 942 of file app_jack.c.

References ast_audiohook_detach(), ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, ast_datastore_free(), ast_log, jack_data::audiohook, ast_datastore::data, LOG_WARNING, and NULL.

Referenced by jack_hook_write().

943 {
944  struct ast_datastore *datastore;
945  struct jack_data *jack_data;
946 
947  ast_channel_lock(chan);
948 
949  if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
950  ast_channel_unlock(chan);
951  ast_log(LOG_WARNING, "No JACK_HOOK found to disable\n");
952  return -1;
953  }
954 
955  ast_channel_datastore_remove(chan, datastore);
956 
957  jack_data = datastore->data;
958  ast_audiohook_detach(&jack_data->audiohook);
959 
960  /* Keep the channel locked while we destroy the datastore, so that we can
961  * ensure that all of the jack stuff is stopped just in case another frame
962  * tries to come through the audiohook callback. */
963  ast_datastore_free(datastore);
964 
965  ast_channel_unlock(chan);
966 
967  return 0;
968 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define LOG_WARNING
Definition: logger.h:274
Structure for a data store object.
Definition: datastore.h:68
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:2404
#define NULL
Definition: resample.c:96
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
#define ast_log
Definition: astobj2.c:42
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
Definition: audiohook.c:579
#define ast_channel_unlock(chan)
Definition: channel.h:2946
void * data
Definition: datastore.h:70
static const struct ast_datastore_info jack_hook_ds_info
Definition: app_jack.c:828
struct ast_audiohook audiohook
Definition: app_jack.c:142
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2399

◆ enable_jack_hook()

static int enable_jack_hook ( struct ast_channel chan,
char *  data 
)
static

Definition at line 875 of file app_jack.c.

References args, AST_APP_ARG, ast_audiohook_attach(), ast_audiohook_init(), AST_AUDIOHOOK_MANIPULATE_ALL_RATES, AST_AUDIOHOOK_TYPE_MANIPULATE, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_datastore_alloc, ast_datastore_free(), AST_DECLARE_APP_ARGS, ast_log, AST_STANDARD_APP_ARGS, ast_strlen_zero, jack_data::audiohook, ast_datastore::data, destroy_jack_data(), handle_options(), jack_data::has_audiohook, init_jack_data(), jack_data_alloc(), jack_hook_callback(), LOG_ERROR, ast_audiohook::manipulate_callback, NULL, options, and S_OR.

Referenced by jack_hook_write().

876 {
877  struct ast_datastore *datastore;
878  struct jack_data *jack_data = NULL;
880  AST_APP_ARG(mode);
882  );
883 
885 
886  ast_channel_lock(chan);
887 
888  if ((datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
889  ast_log(LOG_ERROR, "JACK_HOOK already enabled for '%s'\n", ast_channel_name(chan));
890  goto return_error;
891  }
892 
893  if (ast_strlen_zero(args.mode) || strcasecmp(args.mode, "manipulate")) {
894  ast_log(LOG_ERROR, "'%s' is not a supported mode. Only manipulate is supported.\n",
895  S_OR(args.mode, "<none>"));
896  goto return_error;
897  }
898 
899  if (!(jack_data = jack_data_alloc()))
900  goto return_error;
901 
902  if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options))
903  goto return_error;
904 
905  if (init_jack_data(chan, jack_data))
906  goto return_error;
907 
908  if (!(datastore = ast_datastore_alloc(&jack_hook_ds_info, NULL)))
909  goto return_error;
910 
911  jack_data->has_audiohook = 1;
914 
915  datastore->data = jack_data;
916 
917  if (ast_audiohook_attach(chan, &jack_data->audiohook))
918  goto return_error;
919 
920  if (ast_channel_datastore_add(chan, datastore))
921  goto return_error;
922 
923  ast_channel_unlock(chan);
924 
925  return 0;
926 
927 return_error:
928  ast_channel_unlock(chan);
929 
930  if (jack_data) {
931  destroy_jack_data(jack_data);
932  }
933 
934  if (datastore) {
935  datastore->data = NULL;
936  ast_datastore_free(datastore);
937  }
938 
939  return -1;
940 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
unsigned int has_audiohook
Definition: app_jack.c:139
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
static int handle_options(struct jack_data *jack_data, const char *__options_str)
Definition: app_jack.c:709
static int init_jack_data(struct ast_channel *chan, struct jack_data *jack_data)
Definition: app_jack.c:390
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition: audiohook.c:501
Structure for a data store object.
Definition: datastore.h:68
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:2404
const char * args
#define NULL
Definition: resample.c:96
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
#define ast_strlen_zero(foo)
Definition: strings.h:52
ast_audiohook_manipulate_callback manipulate_callback
Definition: audiohook.h:117
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:108
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
Definition: logger.h:285
static struct jack_data * destroy_jack_data(struct jack_data *jack_data)
Definition: app_jack.c:343
#define ast_channel_unlock(chan)
Definition: channel.h:2946
static int jack_hook_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
Definition: app_jack.c:833
void * data
Definition: datastore.h:70
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
const char * ast_channel_name(const struct ast_channel *chan)
static struct jack_data * jack_data_alloc(void)
Definition: app_jack.c:695
static const struct ast_datastore_info jack_hook_ds_info
Definition: app_jack.c:828
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:89
static struct test_options options
struct ast_audiohook audiohook
Definition: app_jack.c:142
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2390
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.

◆ handle_input()

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.

References ARRAY_LEN, ast_log, buf, jack_data::input_rb, jack_data::input_resample_factor, jack_data::input_resampler, LOG_ERROR, and LOG_WARNING.

Referenced by jack_process().

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 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
short int16_t
Definition: db.h:59
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define LOG_WARNING
Definition: logger.h:274
void * input_resampler
Definition: app_jack.c:136
#define ast_log
Definition: astobj2.c:42
jack_ringbuffer_t * input_rb
Definition: app_jack.c:129
#define LOG_ERROR
Definition: logger.h:285
double input_resample_factor
Definition: app_jack.c:137

◆ handle_jack_audio()

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.

Returns
Nothing.

Definition at line 621 of file app_jack.c.

References ARRAY_LEN, ast_debug, AST_FRAME_VOICE, ast_log, ast_write(), jack_data::audiohook_format, buf, ast_frame::data, ast_frame::datalen, jack_data::frame_datalen, ast_frame::frametype, jack_data::input_rb, LOG_ERROR, ast_frame::ptr, and ast_frame::samples.

Referenced by jack_exec(), and jack_hook_callback().

623 {
624  short buf[jack_data->frame_datalen];
625  struct ast_frame f = {
627  .subclass.format = jack_data->audiohook_format,
628  .src = "JACK",
629  .data.ptr = buf,
630  .datalen = sizeof(buf),
631  .samples = ARRAY_LEN(buf),
632  };
633 
634  for (;;) {
635  size_t res, read_len;
636  char *read_buf;
637 
638  read_len = out_frame ? out_frame->datalen : sizeof(buf);
639  read_buf = out_frame ? out_frame->data.ptr : buf;
640 
641  res = jack_ringbuffer_read_space(jack_data->input_rb);
642 
643  if (res < read_len) {
644  /* Not enough data ready for another frame, move on ... */
645  if (out_frame) {
646  ast_debug(1, "Sending an empty frame for the JACK_HOOK\n");
647  memset(out_frame->data.ptr, 0, out_frame->datalen);
648  }
649  break;
650  }
651 
652  res = jack_ringbuffer_read(jack_data->input_rb, (char *) read_buf, read_len);
653 
654  if (res < read_len) {
655  ast_log(LOG_ERROR, "Error reading from ringbuffer, even though it said there was enough data\n");
656  break;
657  }
658 
659  if (out_frame) {
660  /* If an output frame was provided, then we just want to fill up the
661  * buffer in that frame and return. */
662  break;
663  }
664 
665  ast_write(chan, &f);
666  }
667 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
jack_ringbuffer_t * input_rb
Definition: app_jack.c:129
#define LOG_ERROR
Definition: logger.h:285
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:5189
Data structure associated with a single frame of data.
unsigned int frame_datalen
Definition: app_jack.c:133
union ast_frame::@263 data
enum ast_frame_type frametype
struct ast_format * audiohook_format
Definition: app_jack.c:131

◆ handle_options()

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 709 of file app_jack.c.

References ast_app_parse_options(), ast_log, ast_strdupa, ast_string_field_set, ast_strlen_zero, ast_test_flag, jack_data::client_name, jack_data::connect_input_port, jack_data::connect_output_port, jack_exec_options, LOG_ERROR, jack_data::no_start_server, OPT_ARG_ARRAY_SIZE, OPT_ARG_CLIENT_NAME, OPT_ARG_INPUT_PORT, OPT_ARG_OUTPUT_PORT, OPT_ARG_SERVER_NAME, OPT_CLIENT_NAME, OPT_INPUT_PORT, OPT_NOSTART_SERVER, OPT_OUTPUT_PORT, OPT_SERVER_NAME, and jack_data::server_name.

Referenced by enable_jack_hook(), and jack_exec().

710 {
711  struct ast_flags options = { 0, };
713  char *options_str;
714 
715  options_str = ast_strdupa(__options_str);
716 
717  ast_app_parse_options(jack_exec_options, &options, option_args, options_str);
718 
719  if (ast_test_flag(&options, OPT_SERVER_NAME)) {
720  if (!ast_strlen_zero(option_args[OPT_ARG_SERVER_NAME]))
721  ast_string_field_set(jack_data, server_name, option_args[OPT_ARG_SERVER_NAME]);
722  else {
723  ast_log(LOG_ERROR, "A server name must be provided with the s() option\n");
724  return -1;
725  }
726  }
727 
728  if (ast_test_flag(&options, OPT_CLIENT_NAME)) {
729  if (!ast_strlen_zero(option_args[OPT_ARG_CLIENT_NAME]))
730  ast_string_field_set(jack_data, client_name, option_args[OPT_ARG_CLIENT_NAME]);
731  else {
732  ast_log(LOG_ERROR, "A client name must be provided with the c() option\n");
733  return -1;
734  }
735  }
736 
737  if (ast_test_flag(&options, OPT_INPUT_PORT)) {
738  if (!ast_strlen_zero(option_args[OPT_ARG_INPUT_PORT]))
739  ast_string_field_set(jack_data, connect_input_port, option_args[OPT_ARG_INPUT_PORT]);
740  else {
741  ast_log(LOG_ERROR, "A name must be provided with the i() option\n");
742  return -1;
743  }
744  }
745 
746  if (ast_test_flag(&options, OPT_OUTPUT_PORT)) {
747  if (!ast_strlen_zero(option_args[OPT_ARG_OUTPUT_PORT]))
748  ast_string_field_set(jack_data, connect_output_port, option_args[OPT_ARG_OUTPUT_PORT]);
749  else {
750  ast_log(LOG_ERROR, "A name must be provided with the o() option\n");
751  return -1;
752  }
753  }
754 
755  jack_data->no_start_server = ast_test_flag(&options, OPT_NOSTART_SERVER) ? 1 : 0;
756 
757  return 0;
758 }
#define ast_test_flag(p, flag)
Definition: utils.h:63
unsigned int no_start_server
Definition: app_jack.c:140
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
static const struct ast_app_option jack_exec_options[128]
Definition: app_jack.c:693
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
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:2906
#define LOG_ERROR
Definition: logger.h:285
Structure used to handle boolean flags.
Definition: utils.h:199
option_args
Definition: app_skel.c:141
static struct test_options options
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514

◆ handle_output()

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, len(), and jack_data::output_rb.

Referenced by jack_process().

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 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
jack_ringbuffer_t * output_rb
Definition: app_jack.c:130
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)

◆ init_jack_data()

static int init_jack_data ( struct ast_channel chan,
struct jack_data jack_data 
)
static

Definition at line 390 of file app_jack.c.

References ast_channel_lock, ast_channel_name(), ast_channel_readformat(), ast_channel_unlock, ast_debug, ast_format_cache_get_slin_by_rate(), ast_format_get_name(), ast_format_get_sample_rate(), ast_log, ast_strdupa, ast_strlen_zero, jack_data::audiohook_format, jack_data::audiohook_rate, jack_data::client, jack_data::client_name, jack_data::connect_input_port, jack_data::connect_output_port, jack_data::frame_datalen, jack_data::input_port, jack_data::input_rb, jack_process(), jack_shutdown(), LOG_ERROR, log_jack_status(), jack_data::no_start_server, NULL, jack_data::output_port, jack_data::output_rb, RINGBUFFER_FRAME_CAPACITY, jack_data::server_name, and status.

Referenced by enable_jack_hook(), and jack_exec().

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  */
404  jack_data->audiohook_format = ast_format_cache_get_slin_by_rate(channel_rate);
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 }
const ast_string_field connect_input_port
Definition: app_jack.c:125
#define ast_channel_lock(chan)
Definition: channel.h:2945
static void log_jack_status(const char *prefix, jack_status_t status)
Definition: app_jack.c:174
unsigned int no_start_server
Definition: app_jack.c:140
static void jack_shutdown(void *arg)
Definition: app_jack.c:336
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
#define NULL
Definition: resample.c:96
jack_port_t * output_port
Definition: app_jack.c:128
#define ast_strlen_zero(foo)
Definition: strings.h:52
jack_port_t * input_port
Definition: app_jack.c:127
struct ast_format * ast_channel_readformat(struct ast_channel *chan)
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
jack_client_t * client
Definition: app_jack.c:126
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
jack_ringbuffer_t * input_rb
Definition: app_jack.c:129
jack_ringbuffer_t * output_rb
Definition: app_jack.c:130
const ast_string_field server_name
Definition: app_jack.c:125
#define LOG_ERROR
Definition: logger.h:285
const ast_string_field client_name
Definition: app_jack.c:125
#define ast_channel_unlock(chan)
Definition: channel.h:2946
static int jack_process(jack_nframes_t nframes, void *arg)
Definition: app_jack.c:319
#define RINGBUFFER_FRAME_CAPACITY
Definition: app_jack.c:64
const char * ast_channel_name(const struct ast_channel *chan)
unsigned int audiohook_rate
Definition: app_jack.c:132
unsigned int ast_format_get_sample_rate(const struct ast_format *format)
Get the sample rate of a media format.
Definition: format.c:379
unsigned int frame_datalen
Definition: app_jack.c:133
const ast_string_field connect_output_port
Definition: app_jack.c:125
struct ast_format * audiohook_format
Definition: app_jack.c:131
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:520
jack_status_t status
Definition: app_jack.c:146

◆ jack_data_alloc()

static struct jack_data* jack_data_alloc ( void  )
static

Definition at line 695 of file app_jack.c.

References ast_calloc_with_stringfields, and NULL.

Referenced by enable_jack_hook(), and jack_exec().

696 {
697  struct jack_data *jack_data;
698 
699  if (!(jack_data = ast_calloc_with_stringfields(1, struct jack_data, 32))) {
700  return NULL;
701  }
702 
703  return jack_data;
704 }
#define ast_calloc_with_stringfields(n, type, size)
Allocate a structure with embedded stringfields in a single allocation.
Definition: stringfields.h:426
#define NULL
Definition: resample.c:96

◆ jack_exec()

static int jack_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 760 of file app_jack.c.

References AST_CONTROL_HANGUP, AST_FRAME_CONTROL, AST_FRAME_VOICE, ast_frfree, ast_read(), ast_set_read_format(), ast_set_write_format(), ast_strlen_zero, ast_waitfor(), jack_data::audiohook_format, destroy_jack_data(), ast_frame::frametype, handle_jack_audio(), handle_options(), init_jack_data(), ast_frame_subclass::integer, jack_data_alloc(), NULL, queue_voice_frame(), jack_data::stop, and ast_frame::subclass.

Referenced by load_module().

761 {
762  struct jack_data *jack_data;
763 
764  if (!(jack_data = jack_data_alloc()))
765  return -1;
766 
767  if (!ast_strlen_zero(data) && handle_options(jack_data, data)) {
768  destroy_jack_data(jack_data);
769  return -1;
770  }
771 
772  if (init_jack_data(chan, jack_data)) {
773  destroy_jack_data(jack_data);
774  return -1;
775  }
776 
777  if (ast_set_read_format(chan, jack_data->audiohook_format)) {
778  destroy_jack_data(jack_data);
779  return -1;
780  }
781 
782  if (ast_set_write_format(chan, jack_data->audiohook_format)) {
783  destroy_jack_data(jack_data);
784  return -1;
785  }
786 
787  while (!jack_data->stop) {
788  struct ast_frame *f;
789 
790  if (ast_waitfor(chan, -1) < 0) {
791  break;
792  }
793 
794  f = ast_read(chan);
795  if (!f) {
796  jack_data->stop = 1;
797  continue;
798  }
799 
800  switch (f->frametype) {
801  case AST_FRAME_CONTROL:
803  jack_data->stop = 1;
804  break;
805  case AST_FRAME_VOICE:
806  queue_voice_frame(jack_data, f);
807  default:
808  break;
809  }
810 
811  ast_frfree(f);
812 
813  handle_jack_audio(chan, jack_data, NULL);
814  }
815 
816  jack_data = destroy_jack_data(jack_data);
817 
818  return 0;
819 }
static int handle_options(struct jack_data *jack_data, const char *__options_str)
Definition: app_jack.c:709
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4302
unsigned int stop
Definition: app_jack.c:138
static int init_jack_data(struct ast_channel *chan, struct jack_data *jack_data)
Definition: app_jack.c:390
#define NULL
Definition: resample.c:96
struct ast_frame_subclass subclass
#define ast_strlen_zero(foo)
Definition: strings.h:52
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition: channel.c:5849
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5890
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:621
static struct jack_data * destroy_jack_data(struct jack_data *jack_data)
Definition: app_jack.c:343
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3171
#define ast_frfree(fr)
Data structure associated with a single frame of data.
static struct jack_data * jack_data_alloc(void)
Definition: app_jack.c:695
static int queue_voice_frame(struct jack_data *jack_data, struct ast_frame *f)
Definition: app_jack.c:537
enum ast_frame_type frametype
struct ast_format * audiohook_format
Definition: app_jack.c:131

◆ jack_hook_callback()

static int jack_hook_callback ( struct ast_audiohook audiohook,
struct ast_channel chan,
struct ast_frame frame,
enum ast_audiohook_direction  direction 
)
static

Definition at line 833 of file app_jack.c.

References AST_AUDIOHOOK_DIRECTION_READ, AST_AUDIOHOOK_STATUS_DONE, ast_channel_datastore_find(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_format_cmp(), AST_FORMAT_CMP_NOT_EQUAL, ast_format_get_name(), AST_FRAME_VOICE, ast_log, jack_data::audiohook_format, ast_datastore::data, ast_frame_subclass::format, ast_frame::frametype, handle_jack_audio(), LOG_ERROR, LOG_WARNING, NULL, queue_voice_frame(), ast_audiohook::status, and ast_frame::subclass.

Referenced by enable_jack_hook().

835 {
836  struct ast_datastore *datastore;
837  struct jack_data *jack_data;
838 
839  if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
840  return 0;
841 
843  return 0;
844 
845  if (frame->frametype != AST_FRAME_VOICE)
846  return 0;
847 
848  ast_channel_lock(chan);
849 
850  if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
851  ast_log(LOG_ERROR, "JACK_HOOK datastore not found for '%s'\n", ast_channel_name(chan));
852  ast_channel_unlock(chan);
853  return -1;
854  }
855 
856  jack_data = datastore->data;
857 
859  ast_log(LOG_WARNING, "Expected frame in %s for the audiohook, but got format %s\n",
862  ast_channel_unlock(chan);
863  return 0;
864  }
865 
866  queue_voice_frame(jack_data, frame);
867 
868  handle_jack_audio(chan, jack_data, frame);
869 
870  ast_channel_unlock(chan);
871 
872  return 0;
873 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define LOG_WARNING
Definition: logger.h:274
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:68
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:2404
#define NULL
Definition: resample.c:96
struct ast_frame_subclass subclass
#define ast_log
Definition: astobj2.c:42
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
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:621
#define LOG_ERROR
Definition: logger.h:285
#define ast_channel_unlock(chan)
Definition: channel.h:2946
void * data
Definition: datastore.h:70
const char * ast_channel_name(const struct ast_channel *chan)
static const struct ast_datastore_info jack_hook_ds_info
Definition: app_jack.c:828
static int queue_voice_frame(struct jack_data *jack_data, struct ast_frame *f)
Definition: app_jack.c:537
enum ast_audiohook_status status
Definition: audiohook.h:107
enum ast_frame_type frametype
struct ast_format * format
direction
struct ast_format * audiohook_format
Definition: app_jack.c:131

◆ jack_hook_ds_destroy()

static void jack_hook_ds_destroy ( void *  data)
static

Definition at line 821 of file app_jack.c.

References destroy_jack_data().

822 {
823  struct jack_data *jack_data = data;
824 
825  destroy_jack_data(jack_data);
826 }
static struct jack_data * destroy_jack_data(struct jack_data *jack_data)
Definition: app_jack.c:343

◆ jack_hook_write()

static int jack_hook_write ( struct ast_channel chan,
const char *  cmd,
char *  data,
const char *  value 
)
static

Definition at line 970 of file app_jack.c.

References ast_log, disable_jack_hook(), enable_jack_hook(), LOG_ERROR, and LOG_WARNING.

972 {
973  int res;
974 
975  if (!chan) {
976  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
977  return -1;
978  }
979 
980  if (!strcasecmp(value, "on"))
981  res = enable_jack_hook(chan, data);
982  else if (!strcasecmp(value, "off"))
983  res = disable_jack_hook(chan);
984  else {
985  ast_log(LOG_ERROR, "'%s' is not a valid value for JACK_HOOK()\n", value);
986  res = -1;
987  }
988 
989  return res;
990 }
#define LOG_WARNING
Definition: logger.h:274
int value
Definition: syslog.c:37
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
Definition: logger.h:285
static int disable_jack_hook(struct ast_channel *chan)
Definition: app_jack.c:942
static int enable_jack_hook(struct ast_channel *chan, char *data)
Definition: app_jack.c:875

◆ jack_process()

static int jack_process ( jack_nframes_t  nframes,
void *  arg 
)
static

Definition at line 319 of file app_jack.c.

References alloc_resampler(), handle_input(), handle_output(), jack_data::input_port, jack_data::input_resample_factor, and jack_data::output_port.

Referenced by init_jack_data().

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 }
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 void handle_output(void *buf, jack_nframes_t nframes, struct jack_data *jack_data)
Handle jack output port.
Definition: app_jack.c:304
jack_port_t * output_port
Definition: app_jack.c:128
jack_port_t * input_port
Definition: app_jack.c:127
static int alloc_resampler(struct jack_data *jack_data, int input)
Definition: app_jack.c:193
double input_resample_factor
Definition: app_jack.c:137

◆ jack_shutdown()

static void jack_shutdown ( void *  arg)
static

Definition at line 336 of file app_jack.c.

References jack_data::stop.

Referenced by init_jack_data().

337 {
338  struct jack_data *jack_data = arg;
339 
340  jack_data->stop = 1;
341 }
unsigned int stop
Definition: app_jack.c:138

◆ jack_status_to_str()

static const char* jack_status_to_str ( jack_status_t  status)
static

Definition at line 162 of file app_jack.c.

References ARRAY_LEN, and jack_status_table.

Referenced by log_jack_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 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static const struct @29 jack_status_table[]
jack_status_t status
Definition: app_jack.c:146

◆ load_module()

static int load_module ( void  )
static

Definition at line 1038 of file app_jack.c.

References ast_custom_function_register, AST_MODULE_INFO_STANDARD_EXTENDED(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_register_application_xml, ast_unregister_application(), ASTERISK_GPL_KEY, jack_app, and jack_exec().

1039 {
1041  return AST_MODULE_LOAD_DECLINE;
1042  }
1043 
1046  return AST_MODULE_LOAD_DECLINE;
1047  }
1048 
1049  return AST_MODULE_LOAD_SUCCESS;
1050 }
static const char jack_app[]
Definition: app_jack.c:117
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
static int jack_exec(struct ast_channel *chan, const char *data)
Definition: app_jack.c:760
static struct ast_custom_function jack_hook_function
Definition: app_jack.c:992
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1508
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626

◆ log_jack_status()

static void log_jack_status ( const char *  prefix,
jack_status_t  status 
)
static

Definition at line 174 of file app_jack.c.

References ast_log, ast_str_alloca, ast_str_append(), ast_str_buffer(), ast_str_set(), first, jack_status_to_str(), LOG_NOTICE, status, and str.

Referenced by init_jack_data().

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 }
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
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:1091
static const char * jack_status_to_str(jack_status_t status)
Definition: app_jack.c:162
#define ast_str_alloca(init_len)
Definition: strings.h:800
const char * str
Definition: app_jack.c:147
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:1065
#define ast_log
Definition: astobj2.c:42
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
struct sla_ringing_trunk * first
Definition: app_meetme.c:1092
#define LOG_NOTICE
Definition: logger.h:263
jack_status_t status
Definition: app_jack.c:146
static char prefix[MAX_PREFIX]
Definition: http.c:141

◆ queue_voice_frame()

static int queue_voice_frame ( struct jack_data jack_data,
struct ast_frame f 
)
static

Definition at line 537 of file app_jack.c.

References alloc_resampler(), ARRAY_LEN, ast_log, ast_frame::data, LOG_ERROR, LOG_WARNING, jack_data::output_rb, jack_data::output_resample_factor, jack_data::output_resampler, ast_frame::ptr, and ast_frame::samples.

Referenced by jack_exec(), and jack_hook_callback().

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 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
void * output_resampler
Definition: app_jack.c:134
short int16_t
Definition: db.h:59
#define LOG_WARNING
Definition: logger.h:274
#define ast_log
Definition: astobj2.c:42
static int alloc_resampler(struct jack_data *jack_data, int input)
Definition: app_jack.c:193
jack_ringbuffer_t * output_rb
Definition: app_jack.c:130
#define LOG_ERROR
Definition: logger.h:285
double output_resample_factor
Definition: app_jack.c:135
union ast_frame::@263 data

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1028 of file app_jack.c.

References ast_custom_function_unregister(), ast_unregister_application(), and jack_app.

1029 {
1030  int res;
1031 
1034 
1035  return res;
1036 }
static const char jack_app[]
Definition: app_jack.c:117
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
static struct ast_custom_function jack_hook_function
Definition: app_jack.c:992

Variable Documentation

◆ jack_app

const char jack_app[] = "JACK"
static

Definition at line 117 of file app_jack.c.

Referenced by load_module(), and unload_module().

◆ jack_exec_options

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

Definition at line 693 of file app_jack.c.

Referenced by handle_options().

◆ jack_hook_ds_info

const struct ast_datastore_info jack_hook_ds_info
static
Initial value:
= {
.type = "JACK_HOOK",
}
static void jack_hook_ds_destroy(void *data)
Definition: app_jack.c:821

Definition at line 828 of file app_jack.c.

◆ jack_hook_function

struct ast_custom_function jack_hook_function
static

Definition at line 992 of file app_jack.c.

◆ jack_status_table

const { ... } jack_status_table[]

Referenced by jack_status_to_str().

◆ status

jack_status_t status
Examples:
/usr/src/asterisk-18.5.0/include/asterisk/logger.h, and /usr/src/asterisk-18.5.0/main/app.c.

Definition at line 146 of file app_jack.c.

Referenced by __ast_pbx_run(), __bt_curdel(), __bt_delete(), __bt_get(), __bt_put(), __bt_seq(), __bt_sync(), __rec_close(), __rec_delete(), __rec_get(), __rec_iput(), __rec_put(), __rec_seq(), __rec_sync(), __rtp_recvfrom(), __rtp_sendto(), _child_handler(), _iax2_show_peers_one(), _sip_show_peer(), _sip_show_peers_one(), _stun_show_status(), acf_odbc_read(), acf_odbc_write(), action_extensionstate(), agent_function_read(), agi_exec_full(), answer(), ast_audiohook_update_status(), ast_rtp_ice_add_cand(), ast_rtp_ice_turn_request(), ast_rtp_on_ice_tx_pkt(), ast_rtp_on_turn_rx_rtcp_data(), ast_rtp_on_turn_rx_rtp_data(), ast_safe_system(), ast_sip_format_contact_ami(), ast_sip_get_contact_short_status_label(), ast_sip_get_contact_status_label(), ast_sip_send_response(), ast_sip_session_terminate(), ast_srtp_change_source(), ast_srtp_create(), ast_unreal_hangup(), callerid_read(), callerid_write(), canary_exit(), chanavail_exec(), change_favorite_icon(), channel_fax_cb(), channel_set_intercept_mode(), cli_contact_print_body(), complete_dpreply(), connectedline_read(), connectedline_write(), contact_apply_handler(), contact_remove_unreachable(), dbm_delete(), dbm_fetch(), dbm_firstkey(), dbm_nextkey(), digest_create_request_with_auth(), diversion_incoming_response(), dundi_show_peers(), filestream_destructor(), format_ami_contactlist_handler(), get_buddy_status(), handle_cc_notify(), handle_cdr_pgsql_status(), handle_cli_cdr_mysql_status(), handle_cli_iax2_show_peer(), handle_cli_realtime_mysql_status(), handle_open_receive_channel_ack_message(), handle_outgoing_response(), hsearch(), ice_create(), init_jack_data(), join_queue(), load_pjsip(), log_jack_status(), mbl_status_exec(), meetme_stasis_cb(), options_incoming_request(), ospauth_exec(), ospfinished_exec(), osplookup_exec(), ospnext_exec(), parse_status(), party_id_read(), party_id_write(), party_name_read(), party_name_write(), party_number_read(), party_number_write(), party_subaddress_read(), party_subaddress_write(), permanent_uri_handler(), publish_load_message(), qualify_contact_cb(), queue_exec(), qupd_exec(), read_exec(), readexten_exec(), rec_rdelete(), redirecting_read(), redirecting_write(), refresh_all_favorite(), registration_client_send(), reload_module(), ring_entry(), rtp_transport_wide_cc_feedback_status_append(), run_ras(), safe_exec_wait(), sdp_search(), send_expansion_icon(), send_favorite(), send_icon(), send_manager_peer_status(), send_options_response(), send_response(), sendtext_exec(), sendurl_exec(), setup_outbound_invite_auth(), shaun_of_the_dead(), show_entry_history(), sip_options_set_contact_status(), sip_publisher_service_queue(), system_create_resolver_and_set_nameservers(), system_registry_to_ami(), transfer_exec(), transport_create(), update_client_state_status(), update_status(), vm_allocate_dh(), wait_for_answer(), wait_our_turn(), xfer_client_on_evsub_state(), xmpp_pak_presence(), xmpp_pak_s10n(), and xpidf_generate_body_content().

◆ str

const char* str
Examples:
/usr/src/asterisk-18.5.0/include/asterisk/strings.h, and /usr/src/asterisk-18.5.0/main/app.c.

Definition at line 147 of file app_jack.c.

Referenced by _free_port_cfg(), acf_cut_exec(), add_hintdevice(), add_required_respheader(), anti_injection(), aoc_charge_type_str(), aoc_charged_item_str(), aoc_rate_type_str(), aoc_scale_str(), aoc_type_of_totaling_str(), aoc_volume_unit_str(), aocmessage_get_unit_entry(), ast_ari_callback(), ast_ari_validate_date(), ast_ari_websocket_session_write(), ast_begins_with(), ast_category_get_templates(), ast_cc_agent_set_interfaces_chanvar(), ast_dump_locks(), ast_func_read(), ast_hashtab_hash_string(), ast_hashtab_hash_string_nocase(), ast_hashtab_hash_string_sax(), ast_include_rename(), ast_json_vstringf(), ast_log_show_lock(), ast_parse_digest(), ast_set_cc_interfaces_chanvar(), ast_sip_global_default_outbound_endpoint(), ast_skip_blanks(), ast_sockaddr_split_hostport(), ast_sockaddr_stringify_fmt(), ast_sockaddr_stringify_port(), ast_str_to_lower(), ast_str_to_upper(), ast_tcptls_server_start(), AST_TEST_DEFINE(), ast_trim_blanks(), build_nonce(), build_user_routes(), candidate_exten_advance(), cc_extension_monitor_init(), cc_generic_agent_start_monitoring(), check_mime(), check_tcptls_cert_name(), cli_print_body(), collect_names_cb(), contacts_to_str(), custom_log(), dbl_list_expect_reverse(), delayed_method2str(), dial_handle_playtones(), do_magic_pickup(), ext_cmp_exten_strlen(), filter_leading_space_from_exprs(), filter_newlines(), find_realtime(), format_log_json(), format_str_append_auth(), function_fieldnum_helper(), function_fieldqty_helper(), sip_to_pjsip::get_bind(), get_content(), handle_getvariablefull(), handle_playtones(), handle_show_locks(), handle_show_translation_path(), handle_tcptls_connection(), hash_string(), iax_parse_ies(), init_appendbuf(), jack_str(), jingle_new(), list_item_to_str(), load_modules(), localnet_to_str(), localnet_to_vl_append(), log_jack_status(), mansession_cmp_fn(), match_to_str(), match_to_var_list_append(), misdn_cfg_get(), misdn_cfg_get_config_string(), misdn_cfg_get_next_port(), misdn_cfg_get_ports_string(), misdn_cfg_is_group_method(), misdn_cfg_is_port_valid(), misdn_to_str_plan(), misdn_to_str_pres(), misdn_to_str_screen(), misdn_to_str_ton(), named_callgroups_to_str(), named_pickupgroups_to_str(), new_find_extension(), ParsingContext::next_stack(), parse_cdata(), pbx_retrieve_variable(), pp_each_extension_helper(), process_text_line(), pvalWordSetString(), pvt_cause_cmp_fn(), SqlConfigParser::read(), read_mf_digits(), read_sf_digits(), readwavheader(), regex(), remove_spaces_before_equals(), replace(), res_sdp_crypto_parse_offer(), rtcp_payload_type2str(), security_event_stasis_cb(), sendtext_exec(), set_var_to_str(), sip_endpoint_identifier_type2str(), sip_outbound_registration_status_str(), sip_subscription_to_ami(), smdi_ifaces_cmp_fn(), smdi_mwi_q_cmp_fn(), stasis_app_message_handler(), str_is_negative(), strreplace(), substitute_escapes(), syslog_log(), test_2way_function(), test_chan_function(), test_chan_integer(), test_chan_integer_accessor(), test_chan_string(), test_chan_variable(), test_expected_result(), tls_method_to_str(), transmit_info_with_aoc(), transform::unicode(), ustmtext(), variable_count_cmp_fn(), vm_allocate_dh(), astconfigparser::write_dicts(), and write_html_escaped().