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: 279949 $")
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_SAFE_BEGIN(&chan->audiohooks->spy_list, ah, list) {
00796 if (!strcmp(ah->source, source)) {
00797 count++;
00798 }
00799 }
00800 AST_LIST_TRAVERSE_SAFE_END;
00801 break;
00802 case AST_AUDIOHOOK_TYPE_WHISPER:
00803 AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->whisper_list, ah, list) {
00804 if (!strcmp(ah->source, source)) {
00805 count++;
00806 }
00807 }
00808 AST_LIST_TRAVERSE_SAFE_END;
00809 break;
00810 case AST_AUDIOHOOK_TYPE_MANIPULATE:
00811 AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->manipulate_list, ah, list) {
00812 if (!strcmp(ah->source, source)) {
00813 count++;
00814 }
00815 }
00816 AST_LIST_TRAVERSE_SAFE_END;
00817 break;
00818 default:
00819 ast_log(LOG_DEBUG, "Invalid audiohook type supplied, (%d)\n", type);
00820 return -1;
00821 }
00822
00823 return count;
00824 }
00825
00826
00827 int ast_channel_audiohook_count_by_source_running(struct ast_channel *chan, const char *source, enum ast_audiohook_type type)
00828 {
00829 int count = 0;
00830 struct ast_audiohook *ah = NULL;
00831 if (!chan->audiohooks)
00832 return -1;
00833
00834 switch (type) {
00835 case AST_AUDIOHOOK_TYPE_SPY:
00836 AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->spy_list, ah, list) {
00837 if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
00838 count++;
00839 }
00840 AST_LIST_TRAVERSE_SAFE_END;
00841 break;
00842 case AST_AUDIOHOOK_TYPE_WHISPER:
00843 AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->whisper_list, ah, list) {
00844 if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
00845 count++;
00846 }
00847 AST_LIST_TRAVERSE_SAFE_END;
00848 break;
00849 case AST_AUDIOHOOK_TYPE_MANIPULATE:
00850 AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->manipulate_list, ah, list) {
00851 if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
00852 count++;
00853 }
00854 AST_LIST_TRAVERSE_SAFE_END;
00855 break;
00856 default:
00857 ast_log(LOG_DEBUG, "Invalid audiohook type supplied, (%d)\n", type);
00858 return -1;
00859 }
00860 return count;
00861 }
00862
00863
00864 struct audiohook_volume {
00865 struct ast_audiohook audiohook;
00866 int read_adjustment;
00867 int write_adjustment;
00868 };
00869
00870
00871
00872
00873
00874 static void audiohook_volume_destroy(void *data)
00875 {
00876 struct audiohook_volume *audiohook_volume = data;
00877
00878
00879 ast_audiohook_destroy(&audiohook_volume->audiohook);
00880
00881
00882 ast_free(audiohook_volume);
00883
00884 return;
00885 }
00886
00887
00888 static const struct ast_datastore_info audiohook_volume_datastore = {
00889 .type = "Volume",
00890 .destroy = audiohook_volume_destroy,
00891 };
00892
00893
00894
00895
00896
00897
00898
00899
00900 static int audiohook_volume_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
00901 {
00902 struct ast_datastore *datastore = NULL;
00903 struct audiohook_volume *audiohook_volume = NULL;
00904 int *gain = NULL;
00905
00906
00907 if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) {
00908 return 0;
00909 }
00910
00911
00912 if (!(datastore = ast_channel_datastore_find(chan, &audiohook_volume_datastore, NULL))) {
00913 return 0;
00914 }
00915
00916 audiohook_volume = datastore->data;
00917
00918
00919 if (direction == AST_AUDIOHOOK_DIRECTION_READ) {
00920 gain = &audiohook_volume->read_adjustment;
00921 } else if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) {
00922 gain = &audiohook_volume->write_adjustment;
00923 }
00924
00925
00926 if (gain && *gain) {
00927 ast_frame_adjust_volume(frame, *gain);
00928 }
00929
00930 return 0;
00931 }
00932
00933
00934
00935
00936
00937
00938 static struct audiohook_volume *audiohook_volume_get(struct ast_channel *chan, int create)
00939 {
00940 struct ast_datastore *datastore = NULL;
00941 struct audiohook_volume *audiohook_volume = NULL;
00942
00943
00944 if ((datastore = ast_channel_datastore_find(chan, &audiohook_volume_datastore, NULL))) {
00945 return datastore->data;
00946 }
00947
00948
00949 if (!create || !(datastore = ast_datastore_alloc(&audiohook_volume_datastore, NULL))) {
00950 return NULL;
00951 }
00952
00953
00954 if (!(audiohook_volume = ast_calloc(1, sizeof(*audiohook_volume)))) {
00955 ast_datastore_free(datastore);
00956 return NULL;
00957 }
00958
00959
00960 ast_audiohook_init(&audiohook_volume->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Volume");
00961 audiohook_volume->audiohook.manipulate_callback = audiohook_volume_callback;
00962
00963
00964 datastore->data = audiohook_volume;
00965 ast_channel_datastore_add(chan, datastore);
00966
00967
00968 ast_audiohook_attach(chan, &audiohook_volume->audiohook);
00969
00970 return audiohook_volume;
00971 }
00972
00973
00974
00975
00976
00977
00978
00979 int ast_audiohook_volume_set(struct ast_channel *chan, enum ast_audiohook_direction direction, int volume)
00980 {
00981 struct audiohook_volume *audiohook_volume = NULL;
00982
00983
00984 if (!(audiohook_volume = audiohook_volume_get(chan, (volume ? 1 : 0)))) {
00985 return -1;
00986 }
00987
00988
00989 if (direction == AST_AUDIOHOOK_DIRECTION_READ || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
00990 audiohook_volume->read_adjustment = volume;
00991 }
00992 if (direction == AST_AUDIOHOOK_DIRECTION_WRITE || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
00993 audiohook_volume->write_adjustment = volume;
00994 }
00995
00996 return 0;
00997 }
00998
00999
01000
01001
01002
01003
01004 int ast_audiohook_volume_get(struct ast_channel *chan, enum ast_audiohook_direction direction)
01005 {
01006 struct audiohook_volume *audiohook_volume = NULL;
01007 int adjustment = 0;
01008
01009
01010 if (!(audiohook_volume = audiohook_volume_get(chan, 0))) {
01011 return 0;
01012 }
01013
01014
01015 if (direction == AST_AUDIOHOOK_DIRECTION_READ) {
01016 adjustment = audiohook_volume->read_adjustment;
01017 } else if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) {
01018 adjustment = audiohook_volume->write_adjustment;
01019 }
01020
01021 return adjustment;
01022 }
01023
01024
01025
01026
01027
01028
01029
01030 int ast_audiohook_volume_adjust(struct ast_channel *chan, enum ast_audiohook_direction direction, int volume)
01031 {
01032 struct audiohook_volume *audiohook_volume = NULL;
01033
01034
01035 if (!(audiohook_volume = audiohook_volume_get(chan, 1))) {
01036 return -1;
01037 }
01038
01039
01040 if (direction == AST_AUDIOHOOK_DIRECTION_READ || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
01041 audiohook_volume->read_adjustment += volume;
01042 }
01043 if (direction == AST_AUDIOHOOK_DIRECTION_WRITE || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
01044 audiohook_volume->write_adjustment += volume;
01045 }
01046
01047 return 0;
01048 }
01049
01050
01051
01052
01053
01054
01055
01056
01057 int ast_audiohook_set_mute(struct ast_channel *chan, const char *source, enum ast_audiohook_flags flag, int clear)
01058 {
01059 struct ast_audiohook *audiohook = NULL;
01060
01061 ast_channel_lock(chan);
01062
01063
01064 if (!chan->audiohooks) {
01065 ast_channel_unlock(chan);
01066 return -1;
01067 }
01068
01069 audiohook = find_audiohook_by_source(chan->audiohooks, source);
01070
01071 if (audiohook) {
01072 if (clear) {
01073 ast_clear_flag(audiohook, flag);
01074 } else {
01075 ast_set_flag(audiohook, flag);
01076 }
01077 }
01078
01079 ast_channel_unlock(chan);
01080
01081 return (audiohook ? 0 : -1);
01082 }