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