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: 349289 $")
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 if (ast_audiohook_write_list_empty(audiohook_list))
00626 return end_frame;
00627
00628
00629
00630 if (frame->subclass.codec != AST_FORMAT_SLINEAR) {
00631 if (in_translate->format != frame->subclass.codec) {
00632 if (in_translate->trans_pvt)
00633 ast_translator_free_path(in_translate->trans_pvt);
00634 if (!(in_translate->trans_pvt = ast_translator_build_path(AST_FORMAT_SLINEAR, frame->subclass.codec)))
00635 return frame;
00636 in_translate->format = frame->subclass.codec;
00637 }
00638 if (!(middle_frame = ast_translate(in_translate->trans_pvt, frame, 0)))
00639 return frame;
00640 samples = middle_frame->samples;
00641 }
00642
00643
00644
00645 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->spy_list, audiohook, list) {
00646 ast_audiohook_lock(audiohook);
00647 if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
00648 AST_LIST_REMOVE_CURRENT(list);
00649 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00650 ast_audiohook_unlock(audiohook);
00651 continue;
00652 }
00653 ast_audiohook_write_frame(audiohook, direction, middle_frame);
00654 ast_audiohook_unlock(audiohook);
00655 }
00656 AST_LIST_TRAVERSE_SAFE_END;
00657
00658
00659 if (direction == AST_AUDIOHOOK_DIRECTION_WRITE && !AST_LIST_EMPTY(&audiohook_list->whisper_list)) {
00660 int i = 0;
00661 short read_buf[samples], combine_buf[samples], *data1 = NULL, *data2 = NULL;
00662 memset(&combine_buf, 0, sizeof(combine_buf));
00663 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->whisper_list, audiohook, list) {
00664 ast_audiohook_lock(audiohook);
00665 if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
00666 AST_LIST_REMOVE_CURRENT(list);
00667 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00668 ast_audiohook_unlock(audiohook);
00669 continue;
00670 }
00671 if (ast_slinfactory_available(&audiohook->write_factory) >= samples && ast_slinfactory_read(&audiohook->write_factory, read_buf, samples)) {
00672
00673 for (i = 0, data1 = combine_buf, data2 = read_buf; i < samples; i++, data1++, data2++)
00674 ast_slinear_saturated_add(data1, data2);
00675 }
00676 ast_audiohook_unlock(audiohook);
00677 }
00678 AST_LIST_TRAVERSE_SAFE_END;
00679
00680 for (i = 0, data1 = middle_frame->data.ptr, data2 = combine_buf; i < samples; i++, data1++, data2++)
00681 ast_slinear_saturated_add(data1, data2);
00682 end_frame = middle_frame;
00683 }
00684
00685
00686 if (!AST_LIST_EMPTY(&audiohook_list->manipulate_list)) {
00687 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->manipulate_list, audiohook, list) {
00688 ast_audiohook_lock(audiohook);
00689 if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
00690 AST_LIST_REMOVE_CURRENT(list);
00691 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00692 ast_audiohook_unlock(audiohook);
00693
00694 audiohook->manipulate_callback(audiohook, chan, NULL, direction);
00695 continue;
00696 }
00697
00698 if (audiohook->manipulate_callback(audiohook, chan, middle_frame, direction)) {
00699
00700
00701
00702
00703
00704 }
00705 ast_audiohook_unlock(audiohook);
00706 }
00707 AST_LIST_TRAVERSE_SAFE_END;
00708 end_frame = middle_frame;
00709 }
00710
00711
00712 if (middle_frame == end_frame) {
00713
00714 if (end_frame->subclass.codec != start_frame->subclass.codec) {
00715 if (out_translate->format != start_frame->subclass.codec) {
00716 if (out_translate->trans_pvt)
00717 ast_translator_free_path(out_translate->trans_pvt);
00718 if (!(out_translate->trans_pvt = ast_translator_build_path(start_frame->subclass.codec, AST_FORMAT_SLINEAR))) {
00719
00720 ast_frfree(middle_frame);
00721 return start_frame;
00722 }
00723 out_translate->format = start_frame->subclass.codec;
00724 }
00725
00726 if (!(end_frame = ast_translate(out_translate->trans_pvt, middle_frame, 0))) {
00727
00728 ast_frfree(middle_frame);
00729 return start_frame;
00730 }
00731
00732 ast_frfree(middle_frame);
00733 }
00734 } else {
00735
00736 ast_frfree(middle_frame);
00737 }
00738
00739 return end_frame;
00740 }
00741
00742 int ast_audiohook_write_list_empty(struct ast_audiohook_list *audiohook_list)
00743 {
00744 if (AST_LIST_EMPTY(&audiohook_list->spy_list) &&
00745 AST_LIST_EMPTY(&audiohook_list->whisper_list) &&
00746 AST_LIST_EMPTY(&audiohook_list->manipulate_list)) {
00747
00748 return 1;
00749 }
00750 return 0;
00751 }
00752
00753
00754
00755
00756
00757
00758
00759
00760 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)
00761 {
00762
00763 if (frame->frametype == AST_FRAME_VOICE)
00764 return audio_audiohook_write_list(chan, audiohook_list, direction, frame);
00765 else if (frame->frametype == AST_FRAME_DTMF)
00766 return dtmf_audiohook_write_list(chan, audiohook_list, direction, frame);
00767 else
00768 return frame;
00769 }
00770
00771
00772
00773
00774 void ast_audiohook_trigger_wait(struct ast_audiohook *audiohook)
00775 {
00776 struct timeval wait;
00777 struct timespec ts;
00778
00779 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(50000, 1000));
00780 ts.tv_sec = wait.tv_sec;
00781 ts.tv_nsec = wait.tv_usec * 1000;
00782
00783 ast_cond_timedwait(&audiohook->trigger, &audiohook->lock, &ts);
00784
00785 return;
00786 }
00787
00788
00789 int ast_channel_audiohook_count_by_source(struct ast_channel *chan, const char *source, enum ast_audiohook_type type)
00790 {
00791 int count = 0;
00792 struct ast_audiohook *ah = NULL;
00793
00794 if (!chan->audiohooks)
00795 return -1;
00796
00797 switch (type) {
00798 case AST_AUDIOHOOK_TYPE_SPY:
00799 AST_LIST_TRAVERSE(&chan->audiohooks->spy_list, ah, list) {
00800 if (!strcmp(ah->source, source)) {
00801 count++;
00802 }
00803 }
00804 break;
00805 case AST_AUDIOHOOK_TYPE_WHISPER:
00806 AST_LIST_TRAVERSE(&chan->audiohooks->whisper_list, ah, list) {
00807 if (!strcmp(ah->source, source)) {
00808 count++;
00809 }
00810 }
00811 break;
00812 case AST_AUDIOHOOK_TYPE_MANIPULATE:
00813 AST_LIST_TRAVERSE(&chan->audiohooks->manipulate_list, ah, list) {
00814 if (!strcmp(ah->source, source)) {
00815 count++;
00816 }
00817 }
00818 break;
00819 default:
00820 ast_log(LOG_DEBUG, "Invalid audiohook type supplied, (%d)\n", type);
00821 return -1;
00822 }
00823
00824 return count;
00825 }
00826
00827
00828 int ast_channel_audiohook_count_by_source_running(struct ast_channel *chan, const char *source, enum ast_audiohook_type type)
00829 {
00830 int count = 0;
00831 struct ast_audiohook *ah = NULL;
00832 if (!chan->audiohooks)
00833 return -1;
00834
00835 switch (type) {
00836 case AST_AUDIOHOOK_TYPE_SPY:
00837 AST_LIST_TRAVERSE(&chan->audiohooks->spy_list, ah, list) {
00838 if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
00839 count++;
00840 }
00841 break;
00842 case AST_AUDIOHOOK_TYPE_WHISPER:
00843 AST_LIST_TRAVERSE(&chan->audiohooks->whisper_list, ah, list) {
00844 if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
00845 count++;
00846 }
00847 break;
00848 case AST_AUDIOHOOK_TYPE_MANIPULATE:
00849 AST_LIST_TRAVERSE(&chan->audiohooks->manipulate_list, ah, list) {
00850 if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
00851 count++;
00852 }
00853 break;
00854 default:
00855 ast_log(LOG_DEBUG, "Invalid audiohook type supplied, (%d)\n", type);
00856 return -1;
00857 }
00858 return count;
00859 }
00860
00861
00862 struct audiohook_volume {
00863 struct ast_audiohook audiohook;
00864 int read_adjustment;
00865 int write_adjustment;
00866 };
00867
00868
00869
00870
00871
00872 static void audiohook_volume_destroy(void *data)
00873 {
00874 struct audiohook_volume *audiohook_volume = data;
00875
00876
00877 ast_audiohook_destroy(&audiohook_volume->audiohook);
00878
00879
00880 ast_free(audiohook_volume);
00881
00882 return;
00883 }
00884
00885
00886 static const struct ast_datastore_info audiohook_volume_datastore = {
00887 .type = "Volume",
00888 .destroy = audiohook_volume_destroy,
00889 };
00890
00891
00892
00893
00894
00895
00896
00897
00898 static int audiohook_volume_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
00899 {
00900 struct ast_datastore *datastore = NULL;
00901 struct audiohook_volume *audiohook_volume = NULL;
00902 int *gain = NULL;
00903
00904
00905 if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) {
00906 return 0;
00907 }
00908
00909
00910 if (!(datastore = ast_channel_datastore_find(chan, &audiohook_volume_datastore, NULL))) {
00911 return 0;
00912 }
00913
00914 audiohook_volume = datastore->data;
00915
00916
00917 if (direction == AST_AUDIOHOOK_DIRECTION_READ) {
00918 gain = &audiohook_volume->read_adjustment;
00919 } else if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) {
00920 gain = &audiohook_volume->write_adjustment;
00921 }
00922
00923
00924 if (gain && *gain) {
00925 ast_frame_adjust_volume(frame, *gain);
00926 }
00927
00928 return 0;
00929 }
00930
00931
00932
00933
00934
00935
00936 static struct audiohook_volume *audiohook_volume_get(struct ast_channel *chan, int create)
00937 {
00938 struct ast_datastore *datastore = NULL;
00939 struct audiohook_volume *audiohook_volume = NULL;
00940
00941
00942 if ((datastore = ast_channel_datastore_find(chan, &audiohook_volume_datastore, NULL))) {
00943 return datastore->data;
00944 }
00945
00946
00947 if (!create || !(datastore = ast_datastore_alloc(&audiohook_volume_datastore, NULL))) {
00948 return NULL;
00949 }
00950
00951
00952 if (!(audiohook_volume = ast_calloc(1, sizeof(*audiohook_volume)))) {
00953 ast_datastore_free(datastore);
00954 return NULL;
00955 }
00956
00957
00958 ast_audiohook_init(&audiohook_volume->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Volume");
00959 audiohook_volume->audiohook.manipulate_callback = audiohook_volume_callback;
00960
00961
00962 datastore->data = audiohook_volume;
00963 ast_channel_datastore_add(chan, datastore);
00964
00965
00966 ast_audiohook_attach(chan, &audiohook_volume->audiohook);
00967
00968 return audiohook_volume;
00969 }
00970
00971
00972
00973
00974
00975
00976
00977 int ast_audiohook_volume_set(struct ast_channel *chan, enum ast_audiohook_direction direction, int volume)
00978 {
00979 struct audiohook_volume *audiohook_volume = NULL;
00980
00981
00982 if (!(audiohook_volume = audiohook_volume_get(chan, (volume ? 1 : 0)))) {
00983 return -1;
00984 }
00985
00986
00987 if (direction == AST_AUDIOHOOK_DIRECTION_READ || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
00988 audiohook_volume->read_adjustment = volume;
00989 }
00990 if (direction == AST_AUDIOHOOK_DIRECTION_WRITE || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
00991 audiohook_volume->write_adjustment = volume;
00992 }
00993
00994 return 0;
00995 }
00996
00997
00998
00999
01000
01001
01002 int ast_audiohook_volume_get(struct ast_channel *chan, enum ast_audiohook_direction direction)
01003 {
01004 struct audiohook_volume *audiohook_volume = NULL;
01005 int adjustment = 0;
01006
01007
01008 if (!(audiohook_volume = audiohook_volume_get(chan, 0))) {
01009 return 0;
01010 }
01011
01012
01013 if (direction == AST_AUDIOHOOK_DIRECTION_READ) {
01014 adjustment = audiohook_volume->read_adjustment;
01015 } else if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) {
01016 adjustment = audiohook_volume->write_adjustment;
01017 }
01018
01019 return adjustment;
01020 }
01021
01022
01023
01024
01025
01026
01027
01028 int ast_audiohook_volume_adjust(struct ast_channel *chan, enum ast_audiohook_direction direction, int volume)
01029 {
01030 struct audiohook_volume *audiohook_volume = NULL;
01031
01032
01033 if (!(audiohook_volume = audiohook_volume_get(chan, 1))) {
01034 return -1;
01035 }
01036
01037
01038 if (direction == AST_AUDIOHOOK_DIRECTION_READ || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
01039 audiohook_volume->read_adjustment += volume;
01040 }
01041 if (direction == AST_AUDIOHOOK_DIRECTION_WRITE || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
01042 audiohook_volume->write_adjustment += volume;
01043 }
01044
01045 return 0;
01046 }
01047
01048
01049
01050
01051
01052
01053
01054
01055 int ast_audiohook_set_mute(struct ast_channel *chan, const char *source, enum ast_audiohook_flags flag, int clear)
01056 {
01057 struct ast_audiohook *audiohook = NULL;
01058
01059 ast_channel_lock(chan);
01060
01061
01062 if (!chan->audiohooks) {
01063 ast_channel_unlock(chan);
01064 return -1;
01065 }
01066
01067 audiohook = find_audiohook_by_source(chan->audiohooks, source);
01068
01069 if (audiohook) {
01070 if (clear) {
01071 ast_clear_flag(audiohook, flag);
01072 } else {
01073 ast_set_flag(audiohook, flag);
01074 }
01075 }
01076
01077 ast_channel_unlock(chan);
01078
01079 return (audiohook ? 0 : -1);
01080 }