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