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