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 #include "asterisk.h"
00027
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 316265 $")
00029
00030 #include <signal.h>
00031
00032 #include "asterisk/channel.h"
00033 #include "asterisk/utils.h"
00034 #include "asterisk/lock.h"
00035 #include "asterisk/linkedlists.h"
00036 #include "asterisk/audiohook.h"
00037 #include "asterisk/slinfactory.h"
00038 #include "asterisk/frame.h"
00039 #include "asterisk/translate.h"
00040
00041 struct ast_audiohook_translate {
00042 struct ast_trans_pvt *trans_pvt;
00043 format_t format;
00044 };
00045
00046 struct ast_audiohook_list {
00047 struct ast_audiohook_translate in_translate[2];
00048 struct ast_audiohook_translate out_translate[2];
00049 AST_LIST_HEAD_NOLOCK(, ast_audiohook) spy_list;
00050 AST_LIST_HEAD_NOLOCK(, ast_audiohook) whisper_list;
00051 AST_LIST_HEAD_NOLOCK(, ast_audiohook) manipulate_list;
00052 };
00053
00054
00055
00056
00057
00058
00059
00060 int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source)
00061 {
00062
00063 audiohook->type = type;
00064 audiohook->source = source;
00065
00066
00067 ast_mutex_init(&audiohook->lock);
00068 ast_cond_init(&audiohook->trigger, NULL);
00069
00070
00071 switch (type) {
00072 case AST_AUDIOHOOK_TYPE_SPY:
00073 ast_slinfactory_init(&audiohook->read_factory);
00074 case AST_AUDIOHOOK_TYPE_WHISPER:
00075 ast_slinfactory_init(&audiohook->write_factory);
00076 break;
00077 default:
00078 break;
00079 }
00080
00081
00082 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_NEW);
00083
00084 return 0;
00085 }
00086
00087
00088
00089
00090
00091 int ast_audiohook_destroy(struct ast_audiohook *audiohook)
00092 {
00093
00094 switch (audiohook->type) {
00095 case AST_AUDIOHOOK_TYPE_SPY:
00096 ast_slinfactory_destroy(&audiohook->read_factory);
00097 case AST_AUDIOHOOK_TYPE_WHISPER:
00098 ast_slinfactory_destroy(&audiohook->write_factory);
00099 break;
00100 default:
00101 break;
00102 }
00103
00104
00105 if (audiohook->trans_pvt)
00106 ast_translator_free_path(audiohook->trans_pvt);
00107
00108
00109 ast_cond_destroy(&audiohook->trigger);
00110 ast_mutex_destroy(&audiohook->lock);
00111
00112 return 0;
00113 }
00114
00115
00116
00117
00118
00119
00120
00121 int ast_audiohook_write_frame(struct ast_audiohook *audiohook, enum ast_audiohook_direction direction, struct ast_frame *frame)
00122 {
00123 struct ast_slinfactory *factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_factory : &audiohook->write_factory);
00124 struct ast_slinfactory *other_factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->write_factory : &audiohook->read_factory);
00125 struct timeval *rwtime = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_time : &audiohook->write_time), previous_time = *rwtime;
00126 int our_factory_samples;
00127 int our_factory_ms;
00128 int other_factory_samples;
00129 int other_factory_ms;
00130 int muteme = 0;
00131
00132
00133 *rwtime = ast_tvnow();
00134
00135 our_factory_samples = ast_slinfactory_available(factory);
00136 our_factory_ms = ast_tvdiff_ms(*rwtime, previous_time) + (our_factory_samples / 8);
00137 other_factory_samples = ast_slinfactory_available(other_factory);
00138 other_factory_ms = other_factory_samples / 8;
00139
00140 if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC) && other_factory_samples && (our_factory_ms - other_factory_ms > AST_AUDIOHOOK_SYNC_TOLERANCE)) {
00141 if (option_debug)
00142 ast_log(LOG_DEBUG, "Flushing audiohook %p so it remains in sync\n", audiohook);
00143 ast_slinfactory_flush(factory);
00144 ast_slinfactory_flush(other_factory);
00145 }
00146
00147 if (ast_test_flag(audiohook, AST_AUDIOHOOK_SMALL_QUEUE) && (our_factory_samples > 640 || other_factory_samples > 640)) {
00148 if (option_debug) {
00149 ast_log(LOG_DEBUG, "Audiohook %p has stale audio in its factories. Flushing them both\n", audiohook);
00150 }
00151 ast_slinfactory_flush(factory);
00152 ast_slinfactory_flush(other_factory);
00153 }
00154
00155
00156 if ((ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_READ) && (direction == AST_AUDIOHOOK_DIRECTION_READ)) ||
00157 (ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_WRITE) && (direction == AST_AUDIOHOOK_DIRECTION_WRITE)) ||
00158 (ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE) == (AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE))) {
00159 muteme = 1;
00160 }
00161
00162 if (muteme && frame->datalen > 0) {
00163 ast_frame_clear(frame);
00164 }
00165
00166
00167 ast_slinfactory_feed(factory, frame);
00168
00169
00170 if ((ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_MODE) == AST_AUDIOHOOK_TRIGGER_READ) && (direction == AST_AUDIOHOOK_DIRECTION_READ)) {
00171 ast_cond_signal(&audiohook->trigger);
00172 } else if ((ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_MODE) == AST_AUDIOHOOK_TRIGGER_WRITE) && (direction == AST_AUDIOHOOK_DIRECTION_WRITE)) {
00173 ast_cond_signal(&audiohook->trigger);
00174 } else if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC)) {
00175 ast_cond_signal(&audiohook->trigger);
00176 }
00177
00178 return 0;
00179 }
00180
00181 static struct ast_frame *audiohook_read_frame_single(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction)
00182 {
00183 struct ast_slinfactory *factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_factory : &audiohook->write_factory);
00184 int vol = (direction == AST_AUDIOHOOK_DIRECTION_READ ? audiohook->options.read_volume : audiohook->options.write_volume);
00185 short buf[samples];
00186 struct ast_frame frame = {
00187 .frametype = AST_FRAME_VOICE,
00188 .subclass.codec = AST_FORMAT_SLINEAR,
00189 .data.ptr = buf,
00190 .datalen = sizeof(buf),
00191 .samples = samples,
00192 };
00193
00194
00195 if (samples > ast_slinfactory_available(factory))
00196 return NULL;
00197
00198
00199 if (!ast_slinfactory_read(factory, buf, samples))
00200 return NULL;
00201
00202
00203 if (vol)
00204 ast_frame_adjust_volume(&frame, vol);
00205
00206 return ast_frdup(&frame);
00207 }
00208
00209 static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audiohook, size_t samples)
00210 {
00211 int i = 0, usable_read, usable_write;
00212 short buf1[samples], buf2[samples], *read_buf = NULL, *write_buf = NULL, *final_buf = NULL, *data1 = NULL, *data2 = NULL;
00213 struct ast_frame frame = {
00214 .frametype = AST_FRAME_VOICE,
00215 .subclass.codec = AST_FORMAT_SLINEAR,
00216 .data.ptr = NULL,
00217 .datalen = sizeof(buf1),
00218 .samples = samples,
00219 };
00220
00221
00222 usable_read = (ast_slinfactory_available(&audiohook->read_factory) >= samples ? 1 : 0);
00223 usable_write = (ast_slinfactory_available(&audiohook->write_factory) >= samples ? 1 : 0);
00224
00225 if (!usable_read && !usable_write) {
00226
00227 ast_debug(1, "Read factory %p and write factory %p both fail to provide %zd samples\n", &audiohook->read_factory, &audiohook->write_factory, samples);
00228 return NULL;
00229 }
00230
00231
00232 if (usable_read && !usable_write && (ast_tvdiff_ms(ast_tvnow(), audiohook->write_time) < (samples/8)*2)) {
00233 ast_debug(3, "Write factory %p was pretty quick last time, waiting for them.\n", &audiohook->write_factory);
00234 return NULL;
00235 }
00236
00237
00238 if (usable_write && !usable_read && (ast_tvdiff_ms(ast_tvnow(), audiohook->read_time) < (samples/8)*2)) {
00239 ast_debug(3, "Read factory %p was pretty quick last time, waiting for them.\n", &audiohook->read_factory);
00240 return NULL;
00241 }
00242
00243
00244 if (usable_read) {
00245 if (ast_slinfactory_read(&audiohook->read_factory, buf1, samples)) {
00246 read_buf = buf1;
00247
00248 if (audiohook->options.read_volume) {
00249 int count = 0;
00250 short adjust_value = abs(audiohook->options.read_volume);
00251 for (count = 0; count < samples; count++) {
00252 if (audiohook->options.read_volume > 0)
00253 ast_slinear_saturated_multiply(&buf1[count], &adjust_value);
00254 else if (audiohook->options.read_volume < 0)
00255 ast_slinear_saturated_divide(&buf1[count], &adjust_value);
00256 }
00257 }
00258 }
00259 } else if (option_debug)
00260 ast_log(LOG_DEBUG, "Failed to get %d samples from read factory %p\n", (int)samples, &audiohook->read_factory);
00261
00262
00263 if (usable_write) {
00264 if (ast_slinfactory_read(&audiohook->write_factory, buf2, samples)) {
00265 write_buf = buf2;
00266
00267 if (audiohook->options.write_volume) {
00268 int count = 0;
00269 short adjust_value = abs(audiohook->options.write_volume);
00270 for (count = 0; count < samples; count++) {
00271 if (audiohook->options.write_volume > 0)
00272 ast_slinear_saturated_multiply(&buf2[count], &adjust_value);
00273 else if (audiohook->options.write_volume < 0)
00274 ast_slinear_saturated_divide(&buf2[count], &adjust_value);
00275 }
00276 }
00277 }
00278 } else if (option_debug)
00279 ast_log(LOG_DEBUG, "Failed to get %d samples from write factory %p\n", (int)samples, &audiohook->write_factory);
00280
00281
00282 if (!read_buf && !write_buf)
00283 return NULL;
00284 else if (read_buf && write_buf) {
00285 for (i = 0, data1 = read_buf, data2 = write_buf; i < samples; i++, data1++, data2++)
00286 ast_slinear_saturated_add(data1, data2);
00287 final_buf = buf1;
00288 } else if (read_buf)
00289 final_buf = buf1;
00290 else if (write_buf)
00291 final_buf = buf2;
00292
00293
00294 frame.data.ptr = final_buf;
00295
00296
00297 return ast_frdup(&frame);
00298 }
00299
00300
00301
00302
00303
00304
00305
00306
00307 struct ast_frame *ast_audiohook_read_frame(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, format_t format)
00308 {
00309 struct ast_frame *read_frame = NULL, *final_frame = NULL;
00310
00311 if (!(read_frame = (direction == AST_AUDIOHOOK_DIRECTION_BOTH ? audiohook_read_frame_both(audiohook, samples) : audiohook_read_frame_single(audiohook, samples, direction))))
00312 return NULL;
00313
00314
00315 if (format != AST_FORMAT_SLINEAR) {
00316
00317 if (audiohook->format != format) {
00318 if (audiohook->trans_pvt) {
00319 ast_translator_free_path(audiohook->trans_pvt);
00320 audiohook->trans_pvt = NULL;
00321 }
00322
00323 if (!(audiohook->trans_pvt = ast_translator_build_path(format, AST_FORMAT_SLINEAR))) {
00324 ast_frfree(read_frame);
00325 return NULL;
00326 }
00327 }
00328
00329 final_frame = ast_translate(audiohook->trans_pvt, read_frame, 1);
00330 } else {
00331 final_frame = read_frame;
00332 }
00333
00334 return final_frame;
00335 }
00336
00337
00338
00339
00340
00341
00342 int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
00343 {
00344 ast_channel_lock(chan);
00345
00346 if (!chan->audiohooks) {
00347
00348 if (!(chan->audiohooks = ast_calloc(1, sizeof(*chan->audiohooks)))) {
00349 ast_channel_unlock(chan);
00350 return -1;
00351 }
00352 AST_LIST_HEAD_INIT_NOLOCK(&chan->audiohooks->spy_list);
00353 AST_LIST_HEAD_INIT_NOLOCK(&chan->audiohooks->whisper_list);
00354 AST_LIST_HEAD_INIT_NOLOCK(&chan->audiohooks->manipulate_list);
00355 }
00356
00357
00358 if (audiohook->type == AST_AUDIOHOOK_TYPE_SPY)
00359 AST_LIST_INSERT_TAIL(&chan->audiohooks->spy_list, audiohook, list);
00360 else if (audiohook->type == AST_AUDIOHOOK_TYPE_WHISPER)
00361 AST_LIST_INSERT_TAIL(&chan->audiohooks->whisper_list, audiohook, list);
00362 else if (audiohook->type == AST_AUDIOHOOK_TYPE_MANIPULATE)
00363 AST_LIST_INSERT_TAIL(&chan->audiohooks->manipulate_list, audiohook, list);
00364
00365
00366 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_RUNNING);
00367
00368 ast_channel_unlock(chan);
00369
00370 return 0;
00371 }
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381 void ast_audiohook_update_status(struct ast_audiohook *audiohook, enum ast_audiohook_status status)
00382 {
00383 ast_audiohook_lock(audiohook);
00384 if (audiohook->status != AST_AUDIOHOOK_STATUS_DONE) {
00385 audiohook->status = status;
00386 ast_cond_signal(&audiohook->trigger);
00387 }
00388 ast_audiohook_unlock(audiohook);
00389 }
00390
00391
00392
00393
00394
00395 int ast_audiohook_detach(struct ast_audiohook *audiohook)
00396 {
00397 if (audiohook->status == AST_AUDIOHOOK_STATUS_NEW || audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
00398 return 0;
00399
00400 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_SHUTDOWN);
00401
00402 while (audiohook->status != AST_AUDIOHOOK_STATUS_DONE)
00403 ast_audiohook_trigger_wait(audiohook);
00404
00405 return 0;
00406 }
00407
00408
00409
00410
00411
00412 int ast_audiohook_detach_list(struct ast_audiohook_list *audiohook_list)
00413 {
00414 int i = 0;
00415 struct ast_audiohook *audiohook = NULL;
00416
00417
00418 while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->spy_list, list))) {
00419 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00420 }
00421
00422
00423 while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->whisper_list, list))) {
00424 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00425 }
00426
00427
00428 while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->manipulate_list, list))) {
00429 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00430 audiohook->manipulate_callback(audiohook, NULL, NULL, 0);
00431 }
00432
00433
00434 for (i = 0; i < 2; i++) {
00435 if (audiohook_list->in_translate[i].trans_pvt)
00436 ast_translator_free_path(audiohook_list->in_translate[i].trans_pvt);
00437 if (audiohook_list->out_translate[i].trans_pvt)
00438 ast_translator_free_path(audiohook_list->out_translate[i].trans_pvt);
00439 }
00440
00441
00442 ast_free(audiohook_list);
00443
00444 return 0;
00445 }
00446
00447
00448
00449
00450
00451
00452 static struct ast_audiohook *find_audiohook_by_source(struct ast_audiohook_list *audiohook_list, const char *source)
00453 {
00454 struct ast_audiohook *audiohook = NULL;
00455
00456 AST_LIST_TRAVERSE(&audiohook_list->spy_list, audiohook, list) {
00457 if (!strcasecmp(audiohook->source, source))
00458 return audiohook;
00459 }
00460
00461 AST_LIST_TRAVERSE(&audiohook_list->whisper_list, audiohook, list) {
00462 if (!strcasecmp(audiohook->source, source))
00463 return audiohook;
00464 }
00465
00466 AST_LIST_TRAVERSE(&audiohook_list->manipulate_list, audiohook, list) {
00467 if (!strcasecmp(audiohook->source, source))
00468 return audiohook;
00469 }
00470
00471 return NULL;
00472 }
00473
00474 void ast_audiohook_move_by_source(struct ast_channel *old_chan, struct ast_channel *new_chan, const char *source)
00475 {
00476 struct ast_audiohook *audiohook;
00477 enum ast_audiohook_status oldstatus;
00478
00479 if (!old_chan->audiohooks || !(audiohook = find_audiohook_by_source(old_chan->audiohooks, source))) {
00480 return;
00481 }
00482
00483
00484
00485
00486
00487
00488 ast_audiohook_lock(audiohook);
00489 oldstatus = audiohook->status;
00490
00491 ast_audiohook_remove(old_chan, audiohook);
00492 ast_audiohook_attach(new_chan, audiohook);
00493
00494 audiohook->status = oldstatus;
00495 ast_audiohook_unlock(audiohook);
00496 }
00497
00498
00499
00500
00501
00502
00503 int ast_audiohook_detach_source(struct ast_channel *chan, const char *source)
00504 {
00505 struct ast_audiohook *audiohook = NULL;
00506
00507 ast_channel_lock(chan);
00508
00509
00510 if (!chan->audiohooks) {
00511 ast_channel_unlock(chan);
00512 return -1;
00513 }
00514
00515 audiohook = find_audiohook_by_source(chan->audiohooks, source);
00516
00517 ast_channel_unlock(chan);
00518
00519 if (audiohook && audiohook->status != AST_AUDIOHOOK_STATUS_DONE)
00520 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_SHUTDOWN);
00521
00522 return (audiohook ? 0 : -1);
00523 }
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535 int ast_audiohook_remove(struct ast_channel *chan, struct ast_audiohook *audiohook)
00536 {
00537 ast_channel_lock(chan);
00538
00539 if (!chan->audiohooks) {
00540 ast_channel_unlock(chan);
00541 return -1;
00542 }
00543
00544 if (audiohook->type == AST_AUDIOHOOK_TYPE_SPY)
00545 AST_LIST_REMOVE(&chan->audiohooks->spy_list, audiohook, list);
00546 else if (audiohook->type == AST_AUDIOHOOK_TYPE_WHISPER)
00547 AST_LIST_REMOVE(&chan->audiohooks->whisper_list, audiohook, list);
00548 else if (audiohook->type == AST_AUDIOHOOK_TYPE_MANIPULATE)
00549 AST_LIST_REMOVE(&chan->audiohooks->manipulate_list, audiohook, list);
00550
00551 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00552
00553 ast_channel_unlock(chan);
00554
00555 return 0;
00556 }
00557
00558
00559
00560
00561
00562
00563
00564
00565 static struct ast_frame *dtmf_audiohook_write_list(struct ast_channel *chan, struct ast_audiohook_list *audiohook_list, enum ast_audiohook_direction direction, struct ast_frame *frame)
00566 {
00567 struct ast_audiohook *audiohook = NULL;
00568
00569 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->manipulate_list, audiohook, list) {
00570 ast_audiohook_lock(audiohook);
00571 if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
00572 AST_LIST_REMOVE_CURRENT(list);
00573 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00574 ast_audiohook_unlock(audiohook);
00575 audiohook->manipulate_callback(audiohook, NULL, NULL, 0);
00576 continue;
00577 }
00578 if (ast_test_flag(audiohook, AST_AUDIOHOOK_WANTS_DTMF))
00579 audiohook->manipulate_callback(audiohook, chan, frame, direction);
00580 ast_audiohook_unlock(audiohook);
00581 }
00582 AST_LIST_TRAVERSE_SAFE_END;
00583
00584 return frame;
00585 }
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616 static struct ast_frame *audio_audiohook_write_list(struct ast_channel *chan, struct ast_audiohook_list *audiohook_list, enum ast_audiohook_direction direction, struct ast_frame *frame)
00617 {
00618 struct ast_audiohook_translate *in_translate = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook_list->in_translate[0] : &audiohook_list->in_translate[1]);
00619 struct ast_audiohook_translate *out_translate = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook_list->out_translate[0] : &audiohook_list->out_translate[1]);
00620 struct ast_frame *start_frame = frame, *middle_frame = frame, *end_frame = frame;
00621 struct ast_audiohook *audiohook = NULL;
00622 int samples = frame->samples;
00623
00624
00625
00626 if (frame->subclass.codec != AST_FORMAT_SLINEAR) {
00627 if (in_translate->format != frame->subclass.codec) {
00628 if (in_translate->trans_pvt)
00629 ast_translator_free_path(in_translate->trans_pvt);
00630 if (!(in_translate->trans_pvt = ast_translator_build_path(AST_FORMAT_SLINEAR, frame->subclass.codec)))
00631 return frame;
00632 in_translate->format = frame->subclass.codec;
00633 }
00634 if (!(middle_frame = ast_translate(in_translate->trans_pvt, frame, 0)))
00635 return frame;
00636 samples = middle_frame->samples;
00637 }
00638
00639
00640
00641 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->spy_list, audiohook, list) {
00642 ast_audiohook_lock(audiohook);
00643 if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
00644 AST_LIST_REMOVE_CURRENT(list);
00645 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00646 ast_audiohook_unlock(audiohook);
00647 continue;
00648 }
00649 ast_audiohook_write_frame(audiohook, direction, middle_frame);
00650 ast_audiohook_unlock(audiohook);
00651 }
00652 AST_LIST_TRAVERSE_SAFE_END;
00653
00654
00655 if (direction == AST_AUDIOHOOK_DIRECTION_WRITE && !AST_LIST_EMPTY(&audiohook_list->whisper_list)) {
00656 int i = 0;
00657 short read_buf[samples], combine_buf[samples], *data1 = NULL, *data2 = NULL;
00658 memset(&combine_buf, 0, sizeof(combine_buf));
00659 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->whisper_list, audiohook, list) {
00660 ast_audiohook_lock(audiohook);
00661 if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
00662 AST_LIST_REMOVE_CURRENT(list);
00663 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00664 ast_audiohook_unlock(audiohook);
00665 continue;
00666 }
00667 if (ast_slinfactory_available(&audiohook->write_factory) >= samples && ast_slinfactory_read(&audiohook->write_factory, read_buf, samples)) {
00668
00669 for (i = 0, data1 = combine_buf, data2 = read_buf; i < samples; i++, data1++, data2++)
00670 ast_slinear_saturated_add(data1, data2);
00671 }
00672 ast_audiohook_unlock(audiohook);
00673 }
00674 AST_LIST_TRAVERSE_SAFE_END;
00675
00676 for (i = 0, data1 = middle_frame->data.ptr, data2 = combine_buf; i < samples; i++, data1++, data2++)
00677 ast_slinear_saturated_add(data1, data2);
00678 end_frame = middle_frame;
00679 }
00680
00681
00682 if (!AST_LIST_EMPTY(&audiohook_list->manipulate_list)) {
00683 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->manipulate_list, audiohook, list) {
00684 ast_audiohook_lock(audiohook);
00685 if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
00686 AST_LIST_REMOVE_CURRENT(list);
00687 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00688 ast_audiohook_unlock(audiohook);
00689
00690 audiohook->manipulate_callback(audiohook, chan, NULL, direction);
00691 continue;
00692 }
00693
00694 if (audiohook->manipulate_callback(audiohook, chan, middle_frame, direction)) {
00695
00696
00697
00698
00699
00700 }
00701 ast_audiohook_unlock(audiohook);
00702 }
00703 AST_LIST_TRAVERSE_SAFE_END;
00704 end_frame = middle_frame;
00705 }
00706
00707
00708 if (middle_frame == end_frame) {
00709
00710 if (end_frame->subclass.codec != start_frame->subclass.codec) {
00711 if (out_translate->format != start_frame->subclass.codec) {
00712 if (out_translate->trans_pvt)
00713 ast_translator_free_path(out_translate->trans_pvt);
00714 if (!(out_translate->trans_pvt = ast_translator_build_path(start_frame->subclass.codec, AST_FORMAT_SLINEAR))) {
00715
00716 ast_frfree(middle_frame);
00717 return start_frame;
00718 }
00719 out_translate->format = start_frame->subclass.codec;
00720 }
00721
00722 if (!(end_frame = ast_translate(out_translate->trans_pvt, middle_frame, 0))) {
00723
00724 ast_frfree(middle_frame);
00725 return start_frame;
00726 }
00727
00728 ast_frfree(middle_frame);
00729 }
00730 } else {
00731
00732 ast_frfree(middle_frame);
00733 }
00734
00735 return end_frame;
00736 }
00737
00738 int ast_audiohook_write_list_empty(struct ast_audiohook_list *audiohook_list)
00739 {
00740 if (AST_LIST_EMPTY(&audiohook_list->spy_list) &&
00741 AST_LIST_EMPTY(&audiohook_list->whisper_list) &&
00742 AST_LIST_EMPTY(&audiohook_list->manipulate_list)) {
00743
00744 return 1;
00745 }
00746 return 0;
00747 }
00748
00749
00750
00751
00752
00753
00754
00755
00756 struct ast_frame *ast_audiohook_write_list(struct ast_channel *chan, struct ast_audiohook_list *audiohook_list, enum ast_audiohook_direction direction, struct ast_frame *frame)
00757 {
00758
00759 if (frame->frametype == AST_FRAME_VOICE)
00760 return audio_audiohook_write_list(chan, audiohook_list, direction, frame);
00761 else if (frame->frametype == AST_FRAME_DTMF)
00762 return dtmf_audiohook_write_list(chan, audiohook_list, direction, frame);
00763 else
00764 return frame;
00765 }
00766
00767
00768
00769
00770 void ast_audiohook_trigger_wait(struct ast_audiohook *audiohook)
00771 {
00772 struct timeval wait;
00773 struct timespec ts;
00774
00775 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(50000, 1000));
00776 ts.tv_sec = wait.tv_sec;
00777 ts.tv_nsec = wait.tv_usec * 1000;
00778
00779 ast_cond_timedwait(&audiohook->trigger, &audiohook->lock, &ts);
00780
00781 return;
00782 }
00783
00784
00785 int ast_channel_audiohook_count_by_source(struct ast_channel *chan, const char *source, enum ast_audiohook_type type)
00786 {
00787 int count = 0;
00788 struct ast_audiohook *ah = NULL;
00789
00790 if (!chan->audiohooks)
00791 return -1;
00792
00793 switch (type) {
00794 case AST_AUDIOHOOK_TYPE_SPY:
00795 AST_LIST_TRAVERSE(&chan->audiohooks->spy_list, ah, list) {
00796 if (!strcmp(ah->source, source)) {
00797 count++;
00798 }
00799 }
00800 break;
00801 case AST_AUDIOHOOK_TYPE_WHISPER:
00802 AST_LIST_TRAVERSE(&chan->audiohooks->whisper_list, ah, list) {
00803 if (!strcmp(ah->source, source)) {
00804 count++;
00805 }
00806 }
00807 break;
00808 case AST_AUDIOHOOK_TYPE_MANIPULATE:
00809 AST_LIST_TRAVERSE(&chan->audiohooks->manipulate_list, ah, list) {
00810 if (!strcmp(ah->source, source)) {
00811 count++;
00812 }
00813 }
00814 break;
00815 default:
00816 ast_log(LOG_DEBUG, "Invalid audiohook type supplied, (%d)\n", type);
00817 return -1;
00818 }
00819
00820 return count;
00821 }
00822
00823
00824 int ast_channel_audiohook_count_by_source_running(struct ast_channel *chan, const char *source, enum ast_audiohook_type type)
00825 {
00826 int count = 0;
00827 struct ast_audiohook *ah = NULL;
00828 if (!chan->audiohooks)
00829 return -1;
00830
00831 switch (type) {
00832 case AST_AUDIOHOOK_TYPE_SPY:
00833 AST_LIST_TRAVERSE(&chan->audiohooks->spy_list, ah, list) {
00834 if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
00835 count++;
00836 }
00837 break;
00838 case AST_AUDIOHOOK_TYPE_WHISPER:
00839 AST_LIST_TRAVERSE(&chan->audiohooks->whisper_list, ah, list) {
00840 if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
00841 count++;
00842 }
00843 break;
00844 case AST_AUDIOHOOK_TYPE_MANIPULATE:
00845 AST_LIST_TRAVERSE(&chan->audiohooks->manipulate_list, ah, list) {
00846 if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
00847 count++;
00848 }
00849 break;
00850 default:
00851 ast_log(LOG_DEBUG, "Invalid audiohook type supplied, (%d)\n", type);
00852 return -1;
00853 }
00854 return count;
00855 }
00856
00857
00858 struct audiohook_volume {
00859 struct ast_audiohook audiohook;
00860 int read_adjustment;
00861 int write_adjustment;
00862 };
00863
00864
00865
00866
00867
00868 static void audiohook_volume_destroy(void *data)
00869 {
00870 struct audiohook_volume *audiohook_volume = data;
00871
00872
00873 ast_audiohook_destroy(&audiohook_volume->audiohook);
00874
00875
00876 ast_free(audiohook_volume);
00877
00878 return;
00879 }
00880
00881
00882 static const struct ast_datastore_info audiohook_volume_datastore = {
00883 .type = "Volume",
00884 .destroy = audiohook_volume_destroy,
00885 };
00886
00887
00888
00889
00890
00891
00892
00893
00894 static int audiohook_volume_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
00895 {
00896 struct ast_datastore *datastore = NULL;
00897 struct audiohook_volume *audiohook_volume = NULL;
00898 int *gain = NULL;
00899
00900
00901 if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) {
00902 return 0;
00903 }
00904
00905
00906 if (!(datastore = ast_channel_datastore_find(chan, &audiohook_volume_datastore, NULL))) {
00907 return 0;
00908 }
00909
00910 audiohook_volume = datastore->data;
00911
00912
00913 if (direction == AST_AUDIOHOOK_DIRECTION_READ) {
00914 gain = &audiohook_volume->read_adjustment;
00915 } else if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) {
00916 gain = &audiohook_volume->write_adjustment;
00917 }
00918
00919
00920 if (gain && *gain) {
00921 ast_frame_adjust_volume(frame, *gain);
00922 }
00923
00924 return 0;
00925 }
00926
00927
00928
00929
00930
00931
00932 static struct audiohook_volume *audiohook_volume_get(struct ast_channel *chan, int create)
00933 {
00934 struct ast_datastore *datastore = NULL;
00935 struct audiohook_volume *audiohook_volume = NULL;
00936
00937
00938 if ((datastore = ast_channel_datastore_find(chan, &audiohook_volume_datastore, NULL))) {
00939 return datastore->data;
00940 }
00941
00942
00943 if (!create || !(datastore = ast_datastore_alloc(&audiohook_volume_datastore, NULL))) {
00944 return NULL;
00945 }
00946
00947
00948 if (!(audiohook_volume = ast_calloc(1, sizeof(*audiohook_volume)))) {
00949 ast_datastore_free(datastore);
00950 return NULL;
00951 }
00952
00953
00954 ast_audiohook_init(&audiohook_volume->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Volume");
00955 audiohook_volume->audiohook.manipulate_callback = audiohook_volume_callback;
00956
00957
00958 datastore->data = audiohook_volume;
00959 ast_channel_datastore_add(chan, datastore);
00960
00961
00962 ast_audiohook_attach(chan, &audiohook_volume->audiohook);
00963
00964 return audiohook_volume;
00965 }
00966
00967
00968
00969
00970
00971
00972
00973 int ast_audiohook_volume_set(struct ast_channel *chan, enum ast_audiohook_direction direction, int volume)
00974 {
00975 struct audiohook_volume *audiohook_volume = NULL;
00976
00977
00978 if (!(audiohook_volume = audiohook_volume_get(chan, (volume ? 1 : 0)))) {
00979 return -1;
00980 }
00981
00982
00983 if (direction == AST_AUDIOHOOK_DIRECTION_READ || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
00984 audiohook_volume->read_adjustment = volume;
00985 }
00986 if (direction == AST_AUDIOHOOK_DIRECTION_WRITE || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
00987 audiohook_volume->write_adjustment = volume;
00988 }
00989
00990 return 0;
00991 }
00992
00993
00994
00995
00996
00997
00998 int ast_audiohook_volume_get(struct ast_channel *chan, enum ast_audiohook_direction direction)
00999 {
01000 struct audiohook_volume *audiohook_volume = NULL;
01001 int adjustment = 0;
01002
01003
01004 if (!(audiohook_volume = audiohook_volume_get(chan, 0))) {
01005 return 0;
01006 }
01007
01008
01009 if (direction == AST_AUDIOHOOK_DIRECTION_READ) {
01010 adjustment = audiohook_volume->read_adjustment;
01011 } else if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) {
01012 adjustment = audiohook_volume->write_adjustment;
01013 }
01014
01015 return adjustment;
01016 }
01017
01018
01019
01020
01021
01022
01023
01024 int ast_audiohook_volume_adjust(struct ast_channel *chan, enum ast_audiohook_direction direction, int volume)
01025 {
01026 struct audiohook_volume *audiohook_volume = NULL;
01027
01028
01029 if (!(audiohook_volume = audiohook_volume_get(chan, 1))) {
01030 return -1;
01031 }
01032
01033
01034 if (direction == AST_AUDIOHOOK_DIRECTION_READ || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
01035 audiohook_volume->read_adjustment += volume;
01036 }
01037 if (direction == AST_AUDIOHOOK_DIRECTION_WRITE || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
01038 audiohook_volume->write_adjustment += volume;
01039 }
01040
01041 return 0;
01042 }
01043
01044
01045
01046
01047
01048
01049
01050
01051 int ast_audiohook_set_mute(struct ast_channel *chan, const char *source, enum ast_audiohook_flags flag, int clear)
01052 {
01053 struct ast_audiohook *audiohook = NULL;
01054
01055 ast_channel_lock(chan);
01056
01057
01058 if (!chan->audiohooks) {
01059 ast_channel_unlock(chan);
01060 return -1;
01061 }
01062
01063 audiohook = find_audiohook_by_source(chan->audiohooks, source);
01064
01065 if (audiohook) {
01066 if (clear) {
01067 ast_clear_flag(audiohook, flag);
01068 } else {
01069 ast_set_flag(audiohook, flag);
01070 }
01071 }
01072
01073 ast_channel_unlock(chan);
01074
01075 return (audiohook ? 0 : -1);
01076 }