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