00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 #include "asterisk.h"
00043
00044 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 140567 $")
00045
00046 #include <limits.h>
00047
00048 #include <jack/jack.h>
00049 #include <jack/ringbuffer.h>
00050
00051 #include <libresample.h>
00052
00053 #include "asterisk/module.h"
00054 #include "asterisk/channel.h"
00055 #include "asterisk/strings.h"
00056 #include "asterisk/lock.h"
00057 #include "asterisk/app.h"
00058 #include "asterisk/pbx.h"
00059 #include "asterisk/audiohook.h"
00060
00061 #define RESAMPLE_QUALITY 1
00062
00063 #define RINGBUFFER_SIZE 16384
00064
00065
00066 #define COMMON_OPTIONS \
00067 " s(<name>) - Connect to the specified jack server name.\n" \
00068 " i(<name>) - Connect the output port that gets created to the specified\n" \
00069 " jack input port.\n" \
00070 " o(<name>) - Connect the input port that gets created to the specified\n" \
00071 " jack output port.\n" \
00072 " n - Do not automatically start the JACK server if it is not already\n" \
00073 " running.\n"
00074
00075 static char *jack_app = "JACK";
00076 static char *jack_synopsis =
00077 "JACK (Jack Audio Connection Kit) Application";
00078 static char *jack_desc =
00079 "JACK([options])\n"
00080 " When this application is executed, two jack ports will be created; one input\n"
00081 "and one output. Other applications can be hooked up to these ports to access\n"
00082 "the audio coming from, or being sent to the channel.\n"
00083 " Valid options:\n"
00084 COMMON_OPTIONS
00085 "";
00086
00087 struct jack_data {
00088 AST_DECLARE_STRING_FIELDS(
00089 AST_STRING_FIELD(server_name);
00090 AST_STRING_FIELD(connect_input_port);
00091 AST_STRING_FIELD(connect_output_port);
00092 );
00093 jack_client_t *client;
00094 jack_port_t *input_port;
00095 jack_port_t *output_port;
00096 jack_ringbuffer_t *input_rb;
00097 jack_ringbuffer_t *output_rb;
00098 void *output_resampler;
00099 double output_resample_factor;
00100 void *input_resampler;
00101 double input_resample_factor;
00102 unsigned int stop:1;
00103 unsigned int has_audiohook:1;
00104 unsigned int no_start_server:1;
00105
00106 struct ast_audiohook audiohook;
00107 };
00108
00109 static const struct {
00110 jack_status_t status;
00111 const char *str;
00112 } jack_status_table[] = {
00113 { JackFailure, "Failure" },
00114 { JackInvalidOption, "Invalid Option" },
00115 { JackNameNotUnique, "Name Not Unique" },
00116 { JackServerStarted, "Server Started" },
00117 { JackServerFailed, "Server Failed" },
00118 { JackServerError, "Server Error" },
00119 { JackNoSuchClient, "No Such Client" },
00120 { JackLoadFailure, "Load Failure" },
00121 { JackInitFailure, "Init Failure" },
00122 { JackShmFailure, "Shared Memory Access Failure" },
00123 { JackVersionError, "Version Mismatch" },
00124 };
00125
00126 static const char *jack_status_to_str(jack_status_t status)
00127 {
00128 int i;
00129
00130 for (i = 0; i < ARRAY_LEN(jack_status_table); i++) {
00131 if (jack_status_table[i].status == status)
00132 return jack_status_table[i].str;
00133 }
00134
00135 return "Unknown Error";
00136 }
00137
00138 static void log_jack_status(const char *prefix, jack_status_t status)
00139 {
00140 struct ast_str *str = ast_str_alloca(512);
00141 int i, first = 0;
00142
00143 for (i = 0; i < (sizeof(status) * 8); i++) {
00144 if (!(status & (1 << i)))
00145 continue;
00146
00147 if (!first) {
00148 ast_str_set(&str, 0, "%s", jack_status_to_str((1 << i)));
00149 first = 1;
00150 } else
00151 ast_str_append(&str, 0, ", %s", jack_status_to_str((1 << i)));
00152 }
00153
00154 ast_log(LOG_NOTICE, "%s: %s\n", prefix, str->str);
00155 }
00156
00157 static int alloc_resampler(struct jack_data *jack_data, int input)
00158 {
00159 double from_srate, to_srate, jack_srate;
00160 void **resampler;
00161 double *resample_factor;
00162
00163 if (input && jack_data->input_resampler)
00164 return 0;
00165
00166 if (!input && jack_data->output_resampler)
00167 return 0;
00168
00169 jack_srate = jack_get_sample_rate(jack_data->client);
00170
00171
00172
00173 to_srate = input ? 8000.0 : jack_srate;
00174 from_srate = input ? jack_srate : 8000.0;
00175
00176 resample_factor = input ? &jack_data->input_resample_factor :
00177 &jack_data->output_resample_factor;
00178
00179 if (from_srate == to_srate) {
00180
00181
00182 *resample_factor = 1.0;
00183 return 0;
00184 }
00185
00186 *resample_factor = to_srate / from_srate;
00187
00188 resampler = input ? &jack_data->input_resampler :
00189 &jack_data->output_resampler;
00190
00191 if (!(*resampler = resample_open(RESAMPLE_QUALITY,
00192 *resample_factor, *resample_factor))) {
00193 ast_log(LOG_ERROR, "Failed to open %s resampler\n",
00194 input ? "input" : "output");
00195 return -1;
00196 }
00197
00198 return 0;
00199 }
00200
00201
00202
00203
00204
00205
00206
00207 static void handle_input(void *buf, jack_nframes_t nframes,
00208 struct jack_data *jack_data)
00209 {
00210 short s_buf[nframes];
00211 float *in_buf = buf;
00212 size_t res;
00213 int i;
00214 size_t write_len = sizeof(s_buf);
00215
00216 if (jack_data->input_resampler) {
00217 int total_in_buf_used = 0;
00218 int total_out_buf_used = 0;
00219 float f_buf[nframes + 1];
00220
00221 memset(f_buf, 0, sizeof(f_buf));
00222
00223 while (total_in_buf_used < nframes) {
00224 int in_buf_used;
00225 int out_buf_used;
00226
00227 out_buf_used = resample_process(jack_data->input_resampler,
00228 jack_data->input_resample_factor,
00229 &in_buf[total_in_buf_used], nframes - total_in_buf_used,
00230 0, &in_buf_used,
00231 &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used);
00232
00233 if (out_buf_used < 0)
00234 break;
00235
00236 total_out_buf_used += out_buf_used;
00237 total_in_buf_used += in_buf_used;
00238
00239 if (total_out_buf_used == ARRAY_LEN(f_buf)) {
00240 ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size, "
00241 "nframes '%d', total_out_buf_used '%d'\n", nframes, total_out_buf_used);
00242 break;
00243 }
00244 }
00245
00246 for (i = 0; i < total_out_buf_used; i++)
00247 s_buf[i] = f_buf[i] * (SHRT_MAX / 1.0);
00248
00249 write_len = total_out_buf_used * sizeof(int16_t);
00250 } else {
00251
00252
00253 for (i = 0; i < nframes; i++)
00254 s_buf[i] = in_buf[i] * (SHRT_MAX / 1.0);
00255 }
00256
00257 res = jack_ringbuffer_write(jack_data->input_rb, (const char *) s_buf, write_len);
00258 if (res != write_len) {
00259 ast_debug(2, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
00260 (int) sizeof(s_buf), (int) res);
00261 }
00262 }
00263
00264
00265
00266
00267
00268
00269
00270 static void handle_output(void *buf, jack_nframes_t nframes,
00271 struct jack_data *jack_data)
00272 {
00273 size_t res, len;
00274
00275 len = nframes * sizeof(float);
00276
00277 res = jack_ringbuffer_read(jack_data->output_rb, buf, len);
00278
00279 if (len != res) {
00280 ast_debug(2, "Wanted %d bytes to send to the output port, "
00281 "but only got %d\n", (int) len, (int) res);
00282 }
00283 }
00284
00285 static int jack_process(jack_nframes_t nframes, void *arg)
00286 {
00287 struct jack_data *jack_data = arg;
00288 void *input_port_buf, *output_port_buf;
00289
00290 if (!jack_data->input_resample_factor)
00291 alloc_resampler(jack_data, 1);
00292
00293 input_port_buf = jack_port_get_buffer(jack_data->input_port, nframes);
00294 handle_input(input_port_buf, nframes, jack_data);
00295
00296 output_port_buf = jack_port_get_buffer(jack_data->output_port, nframes);
00297 handle_output(output_port_buf, nframes, jack_data);
00298
00299 return 0;
00300 }
00301
00302 static void jack_shutdown(void *arg)
00303 {
00304 struct jack_data *jack_data = arg;
00305
00306 jack_data->stop = 1;
00307 }
00308
00309 static struct jack_data *destroy_jack_data(struct jack_data *jack_data)
00310 {
00311 if (jack_data->input_port) {
00312 jack_port_unregister(jack_data->client, jack_data->input_port);
00313 jack_data->input_port = NULL;
00314 }
00315
00316 if (jack_data->output_port) {
00317 jack_port_unregister(jack_data->client, jack_data->output_port);
00318 jack_data->output_port = NULL;
00319 }
00320
00321 if (jack_data->client) {
00322 jack_client_close(jack_data->client);
00323 jack_data->client = NULL;
00324 }
00325
00326 if (jack_data->input_rb) {
00327 jack_ringbuffer_free(jack_data->input_rb);
00328 jack_data->input_rb = NULL;
00329 }
00330
00331 if (jack_data->output_rb) {
00332 jack_ringbuffer_free(jack_data->output_rb);
00333 jack_data->output_rb = NULL;
00334 }
00335
00336 if (jack_data->output_resampler) {
00337 resample_close(jack_data->output_resampler);
00338 jack_data->output_resampler = NULL;
00339 }
00340
00341 if (jack_data->input_resampler) {
00342 resample_close(jack_data->input_resampler);
00343 jack_data->input_resampler = NULL;
00344 }
00345
00346 if (jack_data->has_audiohook)
00347 ast_audiohook_destroy(&jack_data->audiohook);
00348
00349 ast_string_field_free_memory(jack_data);
00350
00351 ast_free(jack_data);
00352
00353 return NULL;
00354 }
00355
00356 static int init_jack_data(struct ast_channel *chan, struct jack_data *jack_data)
00357 {
00358 const char *chan_name;
00359 jack_status_t status = 0;
00360 jack_options_t jack_options = JackNullOption;
00361
00362 ast_channel_lock(chan);
00363 chan_name = ast_strdupa(chan->name);
00364 ast_channel_unlock(chan);
00365
00366 if (!(jack_data->output_rb = jack_ringbuffer_create(RINGBUFFER_SIZE)))
00367 return -1;
00368
00369 if (!(jack_data->input_rb = jack_ringbuffer_create(RINGBUFFER_SIZE)))
00370 return -1;
00371
00372 if (jack_data->no_start_server)
00373 jack_options |= JackNoStartServer;
00374
00375 if (!ast_strlen_zero(jack_data->server_name)) {
00376 jack_options |= JackServerName;
00377 jack_data->client = jack_client_open(chan_name, jack_options, &status,
00378 jack_data->server_name);
00379 } else {
00380 jack_data->client = jack_client_open(chan_name, jack_options, &status);
00381 }
00382
00383 if (status)
00384 log_jack_status("Client Open Status", status);
00385
00386 if (!jack_data->client)
00387 return -1;
00388
00389 jack_data->input_port = jack_port_register(jack_data->client, "input",
00390 JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0);
00391 if (!jack_data->input_port) {
00392 ast_log(LOG_ERROR, "Failed to create input port for jack port\n");
00393 return -1;
00394 }
00395
00396 jack_data->output_port = jack_port_register(jack_data->client, "output",
00397 JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0);
00398 if (!jack_data->output_port) {
00399 ast_log(LOG_ERROR, "Failed to create output port for jack port\n");
00400 return -1;
00401 }
00402
00403 if (jack_set_process_callback(jack_data->client, jack_process, jack_data)) {
00404 ast_log(LOG_ERROR, "Failed to register process callback with jack client\n");
00405 return -1;
00406 }
00407
00408 jack_on_shutdown(jack_data->client, jack_shutdown, jack_data);
00409
00410 if (jack_activate(jack_data->client)) {
00411 ast_log(LOG_ERROR, "Unable to activate jack client\n");
00412 return -1;
00413 }
00414
00415 while (!ast_strlen_zero(jack_data->connect_input_port)) {
00416 const char **ports;
00417 int i;
00418
00419 ports = jack_get_ports(jack_data->client, jack_data->connect_input_port,
00420 NULL, JackPortIsInput);
00421
00422 if (!ports) {
00423 ast_log(LOG_ERROR, "No input port matching '%s' was found\n",
00424 jack_data->connect_input_port);
00425 break;
00426 }
00427
00428 for (i = 0; ports[i]; i++) {
00429 ast_debug(1, "Found port '%s' that matched specified input port '%s'\n",
00430 ports[i], jack_data->connect_input_port);
00431 }
00432
00433 if (jack_connect(jack_data->client, jack_port_name(jack_data->output_port), ports[0])) {
00434 ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0],
00435 jack_port_name(jack_data->output_port));
00436 } else {
00437 ast_debug(1, "Connected '%s' to '%s'\n", ports[0],
00438 jack_port_name(jack_data->output_port));
00439 }
00440
00441 free((void *) ports);
00442
00443 break;
00444 }
00445
00446 while (!ast_strlen_zero(jack_data->connect_output_port)) {
00447 const char **ports;
00448 int i;
00449
00450 ports = jack_get_ports(jack_data->client, jack_data->connect_output_port,
00451 NULL, JackPortIsOutput);
00452
00453 if (!ports) {
00454 ast_log(LOG_ERROR, "No output port matching '%s' was found\n",
00455 jack_data->connect_output_port);
00456 break;
00457 }
00458
00459 for (i = 0; ports[i]; i++) {
00460 ast_debug(1, "Found port '%s' that matched specified output port '%s'\n",
00461 ports[i], jack_data->connect_output_port);
00462 }
00463
00464 if (jack_connect(jack_data->client, ports[0], jack_port_name(jack_data->input_port))) {
00465 ast_log(LOG_ERROR, "Failed to connect '%s' to '%s'\n", ports[0],
00466 jack_port_name(jack_data->input_port));
00467 } else {
00468 ast_debug(1, "Connected '%s' to '%s'\n", ports[0],
00469 jack_port_name(jack_data->input_port));
00470 }
00471
00472 free((void *) ports);
00473
00474 break;
00475 }
00476
00477 return 0;
00478 }
00479
00480 static int queue_voice_frame(struct jack_data *jack_data, struct ast_frame *f)
00481 {
00482 float f_buf[f->samples * 8];
00483 size_t f_buf_used = 0;
00484 int i;
00485 int16_t *s_buf = f->data;
00486 size_t res;
00487
00488 memset(f_buf, 0, sizeof(f_buf));
00489
00490 if (!jack_data->output_resample_factor)
00491 alloc_resampler(jack_data, 0);
00492
00493 if (jack_data->output_resampler) {
00494 float in_buf[f->samples];
00495 int total_in_buf_used = 0;
00496 int total_out_buf_used = 0;
00497
00498 memset(in_buf, 0, sizeof(in_buf));
00499
00500 for (i = 0; i < f->samples; i++)
00501 in_buf[i] = s_buf[i] * (1.0 / SHRT_MAX);
00502
00503 while (total_in_buf_used < ARRAY_LEN(in_buf)) {
00504 int in_buf_used;
00505 int out_buf_used;
00506
00507 out_buf_used = resample_process(jack_data->output_resampler,
00508 jack_data->output_resample_factor,
00509 &in_buf[total_in_buf_used], ARRAY_LEN(in_buf) - total_in_buf_used,
00510 0, &in_buf_used,
00511 &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used);
00512
00513 if (out_buf_used < 0)
00514 break;
00515
00516 total_out_buf_used += out_buf_used;
00517 total_in_buf_used += in_buf_used;
00518
00519 if (total_out_buf_used == ARRAY_LEN(f_buf)) {
00520 ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size\n");
00521 break;
00522 }
00523 }
00524
00525 f_buf_used = total_out_buf_used;
00526 if (f_buf_used > ARRAY_LEN(f_buf))
00527 f_buf_used = ARRAY_LEN(f_buf);
00528 } else {
00529
00530
00531 for (i = 0; i < f->samples; i++)
00532 f_buf[i] = s_buf[i] * (1.0 / SHRT_MAX);
00533
00534 f_buf_used = f->samples;
00535 }
00536
00537 res = jack_ringbuffer_write(jack_data->output_rb, (const char *) f_buf, f_buf_used * sizeof(float));
00538 if (res != (f_buf_used * sizeof(float))) {
00539 ast_debug(2, "Tried to write %d bytes to the ringbuffer, but only wrote %d\n",
00540 (int) (f_buf_used * sizeof(float)), (int) res);
00541 }
00542
00543 return 0;
00544 }
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565 static void handle_jack_audio(struct ast_channel *chan, struct jack_data *jack_data,
00566 struct ast_frame *out_frame)
00567 {
00568 short buf[160];
00569 struct ast_frame f = {
00570 .frametype = AST_FRAME_VOICE,
00571 .subclass = AST_FORMAT_SLINEAR,
00572 .src = "JACK",
00573 .data = buf,
00574 .datalen = sizeof(buf),
00575 .samples = ARRAY_LEN(buf),
00576 };
00577
00578 for (;;) {
00579 size_t res, read_len;
00580 char *read_buf;
00581
00582 read_len = out_frame ? out_frame->datalen : sizeof(buf);
00583 read_buf = out_frame ? out_frame->data : buf;
00584
00585 res = jack_ringbuffer_read_space(jack_data->input_rb);
00586
00587 if (res < read_len) {
00588
00589 if (out_frame) {
00590 ast_debug(1, "Sending an empty frame for the JACK_HOOK\n");
00591 memset(out_frame->data, 0, out_frame->datalen);
00592 }
00593 break;
00594 }
00595
00596 res = jack_ringbuffer_read(jack_data->input_rb, (char *) read_buf, read_len);
00597
00598 if (res < read_len) {
00599 ast_log(LOG_ERROR, "Error reading from ringbuffer, even though it said there was enough data\n");
00600 break;
00601 }
00602
00603 if (out_frame) {
00604
00605
00606 break;
00607 }
00608
00609 ast_write(chan, &f);
00610 }
00611 }
00612
00613 enum {
00614 OPT_SERVER_NAME = (1 << 0),
00615 OPT_INPUT_PORT = (1 << 1),
00616 OPT_OUTPUT_PORT = (1 << 2),
00617 OPT_NOSTART_SERVER = (1 << 3),
00618 };
00619
00620 enum {
00621 OPT_ARG_SERVER_NAME,
00622 OPT_ARG_INPUT_PORT,
00623 OPT_ARG_OUTPUT_PORT,
00624
00625 OPT_ARG_ARRAY_SIZE,
00626 };
00627
00628 AST_APP_OPTIONS(jack_exec_options, BEGIN_OPTIONS
00629 AST_APP_OPTION_ARG('s', OPT_SERVER_NAME, OPT_ARG_SERVER_NAME),
00630 AST_APP_OPTION_ARG('i', OPT_INPUT_PORT, OPT_ARG_INPUT_PORT),
00631 AST_APP_OPTION_ARG('o', OPT_OUTPUT_PORT, OPT_ARG_OUTPUT_PORT),
00632 AST_APP_OPTION('n', OPT_NOSTART_SERVER),
00633 END_OPTIONS );
00634
00635 static struct jack_data *jack_data_alloc(void)
00636 {
00637 struct jack_data *jack_data;
00638
00639 if (!(jack_data = ast_calloc(1, sizeof(*jack_data))))
00640 return NULL;
00641
00642 if (ast_string_field_init(jack_data, 32)) {
00643 ast_free(jack_data);
00644 return NULL;
00645 }
00646
00647 return jack_data;
00648 }
00649
00650
00651
00652
00653 static int handle_options(struct jack_data *jack_data, const char *__options_str)
00654 {
00655 struct ast_flags options = { 0, };
00656 char *option_args[OPT_ARG_ARRAY_SIZE];
00657 char *options_str;
00658
00659 options_str = ast_strdupa(__options_str);
00660
00661 ast_app_parse_options(jack_exec_options, &options, option_args, options_str);
00662
00663 if (ast_test_flag(&options, OPT_SERVER_NAME)) {
00664 if (!ast_strlen_zero(option_args[OPT_ARG_SERVER_NAME]))
00665 ast_string_field_set(jack_data, server_name, option_args[OPT_ARG_SERVER_NAME]);
00666 else {
00667 ast_log(LOG_ERROR, "A server name must be provided with the s() option\n");
00668 return -1;
00669 }
00670 }
00671
00672 if (ast_test_flag(&options, OPT_INPUT_PORT)) {
00673 if (!ast_strlen_zero(option_args[OPT_ARG_INPUT_PORT]))
00674 ast_string_field_set(jack_data, connect_input_port, option_args[OPT_ARG_INPUT_PORT]);
00675 else {
00676 ast_log(LOG_ERROR, "A name must be provided with the i() option\n");
00677 return -1;
00678 }
00679 }
00680
00681 if (ast_test_flag(&options, OPT_OUTPUT_PORT)) {
00682 if (!ast_strlen_zero(option_args[OPT_ARG_OUTPUT_PORT]))
00683 ast_string_field_set(jack_data, connect_output_port, option_args[OPT_ARG_OUTPUT_PORT]);
00684 else {
00685 ast_log(LOG_ERROR, "A name must be provided with the o() option\n");
00686 return -1;
00687 }
00688 }
00689
00690 jack_data->no_start_server = ast_test_flag(&options, OPT_NOSTART_SERVER) ? 1 : 0;
00691
00692 return 0;
00693 }
00694
00695 static int jack_exec(struct ast_channel *chan, void *data)
00696 {
00697 struct jack_data *jack_data;
00698 AST_DECLARE_APP_ARGS(args,
00699 AST_APP_ARG(options);
00700 );
00701
00702 if (!(jack_data = jack_data_alloc()))
00703 return -1;
00704
00705 args.options = data;
00706
00707 if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options)) {
00708 destroy_jack_data(jack_data);
00709 return -1;
00710 }
00711
00712 if (init_jack_data(chan, jack_data)) {
00713 destroy_jack_data(jack_data);
00714 return -1;
00715 }
00716
00717 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
00718 destroy_jack_data(jack_data);
00719 return -1;
00720 }
00721
00722 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
00723 destroy_jack_data(jack_data);
00724 return -1;
00725 }
00726
00727 while (!jack_data->stop) {
00728 struct ast_frame *f;
00729
00730 ast_waitfor(chan, -1);
00731
00732 f = ast_read(chan);
00733 if (!f) {
00734 jack_data->stop = 1;
00735 continue;
00736 }
00737
00738 switch (f->frametype) {
00739 case AST_FRAME_CONTROL:
00740 if (f->subclass == AST_CONTROL_HANGUP)
00741 jack_data->stop = 1;
00742 break;
00743 case AST_FRAME_VOICE:
00744 queue_voice_frame(jack_data, f);
00745 default:
00746 break;
00747 }
00748
00749 ast_frfree(f);
00750
00751 handle_jack_audio(chan, jack_data, NULL);
00752 }
00753
00754 jack_data = destroy_jack_data(jack_data);
00755
00756 return 0;
00757 }
00758
00759 static void jack_hook_ds_destroy(void *data)
00760 {
00761 struct jack_data *jack_data = data;
00762
00763 destroy_jack_data(jack_data);
00764 }
00765
00766 static const struct ast_datastore_info jack_hook_ds_info = {
00767 .type = "JACK_HOOK",
00768 .destroy = jack_hook_ds_destroy,
00769 };
00770
00771 static int jack_hook_callback(struct ast_audiohook *audiohook, struct ast_channel *chan,
00772 struct ast_frame *frame, enum ast_audiohook_direction direction)
00773 {
00774 struct ast_datastore *datastore;
00775 struct jack_data *jack_data;
00776
00777 if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
00778 return 0;
00779
00780 if (direction != AST_AUDIOHOOK_DIRECTION_READ)
00781 return 0;
00782
00783 if (frame->frametype != AST_FRAME_VOICE)
00784 return 0;
00785
00786 if (frame->subclass != AST_FORMAT_SLINEAR) {
00787 ast_log(LOG_WARNING, "Expected frame in SLINEAR for the audiohook, but got format %d\n",
00788 frame->subclass);
00789 return 0;
00790 }
00791
00792 ast_channel_lock(chan);
00793
00794 if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
00795 ast_log(LOG_ERROR, "JACK_HOOK datastore not found for '%s'\n", chan->name);
00796 ast_channel_unlock(chan);
00797 return -1;
00798 }
00799
00800 jack_data = datastore->data;
00801
00802 queue_voice_frame(jack_data, frame);
00803
00804 handle_jack_audio(chan, jack_data, frame);
00805
00806 ast_channel_unlock(chan);
00807
00808 return 0;
00809 }
00810
00811 static int enable_jack_hook(struct ast_channel *chan, char *data)
00812 {
00813 struct ast_datastore *datastore;
00814 struct jack_data *jack_data = NULL;
00815 AST_DECLARE_APP_ARGS(args,
00816 AST_APP_ARG(mode);
00817 AST_APP_ARG(options);
00818 );
00819
00820 AST_STANDARD_APP_ARGS(args, data);
00821
00822 ast_channel_lock(chan);
00823
00824 if ((datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
00825 ast_log(LOG_ERROR, "JACK_HOOK already enabled for '%s'\n", chan->name);
00826 goto return_error;
00827 }
00828
00829 if (ast_strlen_zero(args.mode) || strcasecmp(args.mode, "manipulate")) {
00830 ast_log(LOG_ERROR, "'%s' is not a supported mode. Only manipulate is supported.\n",
00831 S_OR(args.mode, "<none>"));
00832 goto return_error;
00833 }
00834
00835 if (!(jack_data = jack_data_alloc()))
00836 goto return_error;
00837
00838 if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options))
00839 goto return_error;
00840
00841 if (init_jack_data(chan, jack_data))
00842 goto return_error;
00843
00844 if (!(datastore = ast_channel_datastore_alloc(&jack_hook_ds_info, NULL)))
00845 goto return_error;
00846
00847 jack_data->has_audiohook = 1;
00848 ast_audiohook_init(&jack_data->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "JACK_HOOK");
00849 jack_data->audiohook.manipulate_callback = jack_hook_callback;
00850
00851 datastore->data = jack_data;
00852
00853 if (ast_audiohook_attach(chan, &jack_data->audiohook))
00854 goto return_error;
00855
00856 if (ast_channel_datastore_add(chan, datastore))
00857 goto return_error;
00858
00859 ast_channel_unlock(chan);
00860
00861 return 0;
00862
00863 return_error:
00864 ast_channel_unlock(chan);
00865
00866 if (jack_data)
00867 destroy_jack_data(jack_data);
00868
00869 return -1;
00870 }
00871
00872 static int disable_jack_hook(struct ast_channel *chan)
00873 {
00874 struct ast_datastore *datastore;
00875 struct jack_data *jack_data;
00876
00877 ast_channel_lock(chan);
00878
00879 if (!(datastore = ast_channel_datastore_find(chan, &jack_hook_ds_info, NULL))) {
00880 ast_channel_unlock(chan);
00881 ast_log(LOG_WARNING, "No JACK_HOOK found to disable\n");
00882 return -1;
00883 }
00884
00885 ast_channel_datastore_remove(chan, datastore);
00886
00887 jack_data = datastore->data;
00888 ast_audiohook_detach(&jack_data->audiohook);
00889
00890
00891
00892
00893 ast_channel_datastore_free(datastore);
00894
00895 ast_channel_unlock(chan);
00896
00897 return 0;
00898 }
00899
00900 static int jack_hook_write(struct ast_channel *chan, const char *cmd, char *data,
00901 const char *value)
00902 {
00903 int res;
00904
00905 if (!strcasecmp(value, "on"))
00906 res = enable_jack_hook(chan, data);
00907 else if (!strcasecmp(value, "off"))
00908 res = disable_jack_hook(chan);
00909 else {
00910 ast_log(LOG_ERROR, "'%s' is not a valid value for JACK_HOOK()\n", value);
00911 res = -1;
00912 }
00913
00914 return res;
00915 }
00916
00917 static struct ast_custom_function jack_hook_function = {
00918 .name = "JACK_HOOK",
00919 .synopsis = "Enable a jack hook on a channel",
00920 .syntax = "JACK_HOOK(<mode>,[options])",
00921 .desc =
00922 " The JACK_HOOK allows turning on or off jack connectivity to this channel.\n"
00923 "When the JACK_HOOK is turned on, jack ports will get created that allow\n"
00924 "access to the audio stream for this channel. The mode specifies which mode\n"
00925 "this hook should run in. A mode must be specified when turning the JACK_HOOK.\n"
00926 "on. However, all arguments are optional when turning it off.\n"
00927 "\n"
00928 " Valid modes are:\n"
00929 #if 0
00930
00931 " spy - Create a read-only audio hook. Only an output jack port will\n"
00932 " get created.\n"
00933 " whisper - Create a write-only audio hook. Only an input jack port will\n"
00934 " get created.\n"
00935 #endif
00936 " manipulate - Create a read/write audio hook. Both an input and an output\n"
00937 " jack port will get created. Audio from the channel will be\n"
00938 " sent out the output port and will be replaced by the audio\n"
00939 " coming in on the input port as it gets passed on.\n"
00940 "\n"
00941 " Valid options are:\n"
00942 COMMON_OPTIONS
00943 "\n"
00944 " Examples:\n"
00945 " To turn on the JACK_HOOK,\n"
00946 " Set(JACK_HOOK(manipulate,i(pure_data_0:input0)o(pure_data_0:output0))=on)\n"
00947 " To turn off the JACK_HOOK,\n"
00948 " Set(JACK_HOOK()=off)\n"
00949 "",
00950 .write = jack_hook_write,
00951 };
00952
00953 static int unload_module(void)
00954 {
00955 int res;
00956
00957 res = ast_unregister_application(jack_app);
00958 res |= ast_custom_function_unregister(&jack_hook_function);
00959
00960 return res;
00961 }
00962
00963 static int load_module(void)
00964 {
00965 if (ast_register_application(jack_app, jack_exec, jack_synopsis, jack_desc))
00966 return AST_MODULE_LOAD_DECLINE;
00967
00968 if (ast_custom_function_register(&jack_hook_function)) {
00969 ast_unregister_application(jack_app);
00970 return AST_MODULE_LOAD_DECLINE;
00971 }
00972
00973 return AST_MODULE_LOAD_SUCCESS;
00974 }
00975
00976 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "JACK Interface");