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: 279945 $")
00029
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include <signal.h>
00034 #include <errno.h>
00035 #include <unistd.h>
00036
00037 #include "asterisk/logger.h"
00038 #include "asterisk/channel.h"
00039 #include "asterisk/options.h"
00040 #include "asterisk/utils.h"
00041 #include "asterisk/lock.h"
00042 #include "asterisk/linkedlists.h"
00043 #include "asterisk/audiohook.h"
00044 #include "asterisk/slinfactory.h"
00045 #include "asterisk/frame.h"
00046 #include "asterisk/translate.h"
00047
00048 struct ast_audiohook_translate {
00049 struct ast_trans_pvt *trans_pvt;
00050 int format;
00051 };
00052
00053 struct ast_audiohook_list {
00054 struct ast_audiohook_translate in_translate[2];
00055 struct ast_audiohook_translate out_translate[2];
00056 AST_LIST_HEAD_NOLOCK(, ast_audiohook) spy_list;
00057 AST_LIST_HEAD_NOLOCK(, ast_audiohook) whisper_list;
00058 AST_LIST_HEAD_NOLOCK(, ast_audiohook) manipulate_list;
00059 };
00060
00061
00062
00063
00064
00065
00066
00067 int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source)
00068 {
00069
00070 audiohook->type = type;
00071 audiohook->source = source;
00072
00073
00074 ast_mutex_init(&audiohook->lock);
00075 ast_cond_init(&audiohook->trigger, NULL);
00076
00077
00078 switch (type) {
00079 case AST_AUDIOHOOK_TYPE_SPY:
00080 ast_slinfactory_init(&audiohook->read_factory);
00081 case AST_AUDIOHOOK_TYPE_WHISPER:
00082 ast_slinfactory_init(&audiohook->write_factory);
00083 break;
00084 default:
00085 break;
00086 }
00087
00088
00089 audiohook->status = AST_AUDIOHOOK_STATUS_NEW;
00090
00091 return 0;
00092 }
00093
00094
00095
00096
00097
00098 int ast_audiohook_destroy(struct ast_audiohook *audiohook)
00099 {
00100
00101 switch (audiohook->type) {
00102 case AST_AUDIOHOOK_TYPE_SPY:
00103 ast_slinfactory_destroy(&audiohook->read_factory);
00104 case AST_AUDIOHOOK_TYPE_WHISPER:
00105 ast_slinfactory_destroy(&audiohook->write_factory);
00106 break;
00107 default:
00108 break;
00109 }
00110
00111
00112 if (audiohook->trans_pvt)
00113 ast_translator_free_path(audiohook->trans_pvt);
00114
00115
00116 ast_cond_destroy(&audiohook->trigger);
00117 ast_mutex_destroy(&audiohook->lock);
00118
00119 return 0;
00120 }
00121
00122
00123
00124
00125
00126
00127
00128 int ast_audiohook_write_frame(struct ast_audiohook *audiohook, enum ast_audiohook_direction direction, struct ast_frame *frame)
00129 {
00130 struct ast_slinfactory *factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_factory : &audiohook->write_factory);
00131 struct ast_slinfactory *other_factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->write_factory : &audiohook->read_factory);
00132 struct timeval *time = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_time : &audiohook->write_time), previous_time = *time;
00133 int our_factory_samples;
00134 int our_factory_ms;
00135 int other_factory_samples;
00136 int other_factory_ms;
00137
00138
00139 *time = ast_tvnow();
00140
00141 our_factory_samples = ast_slinfactory_available(factory);
00142 our_factory_ms = ast_tvdiff_ms(*time, previous_time) + (our_factory_samples / 8);
00143 other_factory_samples = ast_slinfactory_available(other_factory);
00144 other_factory_ms = other_factory_samples / 8;
00145
00146
00147 if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC) && other_factory_samples && (our_factory_ms - other_factory_ms > AST_AUDIOHOOK_SYNC_TOLERANCE)) {
00148 if (option_debug)
00149 ast_log(LOG_DEBUG, "Flushing audiohook %p so it remains in sync\n", audiohook);
00150 ast_slinfactory_flush(factory);
00151 ast_slinfactory_flush(other_factory);
00152 }
00153
00154 if (ast_test_flag(audiohook, AST_AUDIOHOOK_SMALL_QUEUE) && (our_factory_samples > 640 || other_factory_samples > 640)) {
00155 if (option_debug) {
00156 ast_log(LOG_DEBUG, "Audiohook %p has stale audio in its factories. Flushing them both\n", audiohook);
00157 }
00158 ast_slinfactory_flush(factory);
00159 ast_slinfactory_flush(other_factory);
00160 }
00161
00162
00163 ast_slinfactory_feed(factory, frame);
00164
00165
00166 if ((ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_MODE) == AST_AUDIOHOOK_TRIGGER_READ) && (direction == AST_AUDIOHOOK_DIRECTION_READ)) {
00167 ast_cond_signal(&audiohook->trigger);
00168 } else if ((ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_MODE) == AST_AUDIOHOOK_TRIGGER_WRITE) && (direction == AST_AUDIOHOOK_DIRECTION_WRITE)) {
00169 ast_cond_signal(&audiohook->trigger);
00170 } else if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC)) {
00171 ast_cond_signal(&audiohook->trigger);
00172 }
00173
00174 return 0;
00175 }
00176
00177 static struct ast_frame *audiohook_read_frame_single(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction)
00178 {
00179 struct ast_slinfactory *factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_factory : &audiohook->write_factory);
00180 int vol = (direction == AST_AUDIOHOOK_DIRECTION_READ ? audiohook->options.read_volume : audiohook->options.write_volume);
00181 short buf[samples];
00182 struct ast_frame frame = {
00183 .frametype = AST_FRAME_VOICE,
00184 .subclass = AST_FORMAT_SLINEAR,
00185 .data = buf,
00186 .datalen = sizeof(buf),
00187 .samples = samples,
00188 };
00189
00190
00191 if (samples > ast_slinfactory_available(factory))
00192 return NULL;
00193
00194
00195 if (!ast_slinfactory_read(factory, buf, samples))
00196 return NULL;
00197
00198
00199 if (vol)
00200 ast_frame_adjust_volume(&frame, vol);
00201
00202 return ast_frdup(&frame);
00203 }
00204
00205 static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audiohook, size_t samples)
00206 {
00207 int i = 0, usable_read, usable_write;
00208 short buf1[samples], buf2[samples], *read_buf = NULL, *write_buf = NULL, *final_buf = NULL, *data1 = NULL, *data2 = NULL;
00209 struct ast_frame frame = {
00210 .frametype = AST_FRAME_VOICE,
00211 .subclass = AST_FORMAT_SLINEAR,
00212 .data = NULL,
00213 .datalen = sizeof(buf1),
00214 .samples = samples,
00215 };
00216
00217
00218 usable_read = (ast_slinfactory_available(&audiohook->read_factory) >= samples ? 1 : 0);
00219 usable_write = (ast_slinfactory_available(&audiohook->write_factory) >= samples ? 1 : 0);
00220
00221 if (!usable_read && !usable_write) {
00222
00223 if (option_debug)
00224 ast_log(LOG_DEBUG, "Read factory %p and write factory %p both fail to provide %zd samples\n", &audiohook->read_factory, &audiohook->write_factory, samples);
00225 return NULL;
00226 }
00227
00228
00229 if (usable_read && !usable_write && (ast_tvdiff_ms(ast_tvnow(), audiohook->write_time) < (samples/8)*2)) {
00230 if (option_debug > 2)
00231 ast_log(LOG_DEBUG, "Write factory %p was pretty quick last time, waiting for them.\n", &audiohook->write_factory);
00232 return NULL;
00233 }
00234
00235
00236 if (usable_write && !usable_read && (ast_tvdiff_ms(ast_tvnow(), audiohook->read_time) < (samples/8)*2)) {
00237 if (option_debug > 2)
00238 ast_log(LOG_DEBUG, "Read factory %p was pretty quick last time, waiting for them.\n", &audiohook->read_factory);
00239 return NULL;
00240 }
00241
00242
00243 if (usable_read) {
00244 if (ast_slinfactory_read(&audiohook->read_factory, buf1, samples)) {
00245 read_buf = buf1;
00246
00247 if (audiohook->options.read_volume) {
00248 int count = 0;
00249 short adjust_value = abs(audiohook->options.read_volume);
00250 for (count = 0; count < samples; count++) {
00251 if (audiohook->options.read_volume > 0)
00252 ast_slinear_saturated_multiply(&buf1[count], &adjust_value);
00253 else if (audiohook->options.read_volume < 0)
00254 ast_slinear_saturated_divide(&buf1[count], &adjust_value);
00255 }
00256 }
00257 }
00258 } else if (option_debug)
00259 ast_log(LOG_DEBUG, "Failed to get %zd samples from read factory %p\n", samples, &audiohook->read_factory);
00260
00261
00262 if (usable_write) {
00263 if (ast_slinfactory_read(&audiohook->write_factory, buf2, samples)) {
00264 write_buf = buf2;
00265
00266 if (audiohook->options.write_volume) {
00267 int count = 0;
00268 short adjust_value = abs(audiohook->options.write_volume);
00269 for (count = 0; count < samples; count++) {
00270 if (audiohook->options.write_volume > 0)
00271 ast_slinear_saturated_multiply(&buf2[count], &adjust_value);
00272 else if (audiohook->options.write_volume < 0)
00273 ast_slinear_saturated_divide(&buf2[count], &adjust_value);
00274 }
00275 }
00276 }
00277 } else if (option_debug)
00278 ast_log(LOG_DEBUG, "Failed to get %zd samples from write factory %p\n", samples, &audiohook->write_factory);
00279
00280
00281 if (!read_buf && !write_buf)
00282 return NULL;
00283 else if (read_buf && write_buf) {
00284 for (i = 0, data1 = read_buf, data2 = write_buf; i < samples; i++, data1++, data2++)
00285 ast_slinear_saturated_add(data1, data2);
00286 final_buf = buf1;
00287 } else if (read_buf)
00288 final_buf = buf1;
00289 else if (write_buf)
00290 final_buf = buf2;
00291
00292
00293 frame.data = final_buf;
00294
00295
00296 return ast_frdup(&frame);
00297 }
00298
00299
00300
00301
00302
00303
00304
00305
00306 struct ast_frame *ast_audiohook_read_frame(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, int format)
00307 {
00308 struct ast_frame *read_frame = NULL, *final_frame = NULL;
00309
00310 if (!(read_frame = (direction == AST_AUDIOHOOK_DIRECTION_BOTH ? audiohook_read_frame_both(audiohook, samples) : audiohook_read_frame_single(audiohook, samples, direction))))
00311 return NULL;
00312
00313
00314 if (format != AST_FORMAT_SLINEAR) {
00315
00316 if (audiohook->format != format) {
00317 if (audiohook->trans_pvt) {
00318 ast_translator_free_path(audiohook->trans_pvt);
00319 audiohook->trans_pvt = NULL;
00320 }
00321
00322 if (!(audiohook->trans_pvt = ast_translator_build_path(format, AST_FORMAT_SLINEAR))) {
00323 ast_frfree(read_frame);
00324 return NULL;
00325 }
00326 }
00327
00328 final_frame = ast_translate(audiohook->trans_pvt, read_frame, 1);
00329 } else {
00330 final_frame = read_frame;
00331 }
00332
00333 return final_frame;
00334 }
00335
00336
00337
00338
00339
00340
00341 int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
00342 {
00343 ast_channel_lock(chan);
00344
00345 if (!chan->audiohooks) {
00346
00347 if (!(chan->audiohooks = ast_calloc(1, sizeof(*chan->audiohooks)))) {
00348 ast_channel_unlock(chan);
00349 return -1;
00350 }
00351 AST_LIST_HEAD_INIT_NOLOCK(&chan->audiohooks->spy_list);
00352 AST_LIST_HEAD_INIT_NOLOCK(&chan->audiohooks->whisper_list);
00353 AST_LIST_HEAD_INIT_NOLOCK(&chan->audiohooks->manipulate_list);
00354 }
00355
00356
00357 if (audiohook->type == AST_AUDIOHOOK_TYPE_SPY)
00358 AST_LIST_INSERT_TAIL(&chan->audiohooks->spy_list, audiohook, list);
00359 else if (audiohook->type == AST_AUDIOHOOK_TYPE_WHISPER)
00360 AST_LIST_INSERT_TAIL(&chan->audiohooks->whisper_list, audiohook, list);
00361 else if (audiohook->type == AST_AUDIOHOOK_TYPE_MANIPULATE)
00362 AST_LIST_INSERT_TAIL(&chan->audiohooks->manipulate_list, audiohook, list);
00363
00364
00365 audiohook->status = AST_AUDIOHOOK_STATUS_RUNNING;
00366
00367 ast_channel_unlock(chan);
00368
00369 return 0;
00370 }
00371
00372
00373
00374
00375
00376 int ast_audiohook_detach(struct ast_audiohook *audiohook)
00377 {
00378 if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
00379 return 0;
00380
00381 audiohook->status = AST_AUDIOHOOK_STATUS_SHUTDOWN;
00382
00383 while (audiohook->status != AST_AUDIOHOOK_STATUS_DONE)
00384 ast_audiohook_trigger_wait(audiohook);
00385
00386 return 0;
00387 }
00388
00389
00390
00391
00392
00393 int ast_audiohook_detach_list(struct ast_audiohook_list *audiohook_list)
00394 {
00395 int i = 0;
00396 struct ast_audiohook *audiohook = NULL;
00397
00398
00399 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->spy_list, audiohook, list) {
00400 ast_audiohook_lock(audiohook);
00401 AST_LIST_REMOVE_CURRENT(&audiohook_list->spy_list, list);
00402 audiohook->status = AST_AUDIOHOOK_STATUS_DONE;
00403 ast_cond_signal(&audiohook->trigger);
00404 ast_audiohook_unlock(audiohook);
00405 }
00406 AST_LIST_TRAVERSE_SAFE_END
00407
00408
00409 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->whisper_list, audiohook, list) {
00410 ast_audiohook_lock(audiohook);
00411 AST_LIST_REMOVE_CURRENT(&audiohook_list->whisper_list, list);
00412 audiohook->status = AST_AUDIOHOOK_STATUS_DONE;
00413 ast_cond_signal(&audiohook->trigger);
00414 ast_audiohook_unlock(audiohook);
00415 }
00416 AST_LIST_TRAVERSE_SAFE_END
00417
00418
00419 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->manipulate_list, audiohook, list) {
00420 ast_audiohook_lock(audiohook);
00421 AST_LIST_REMOVE_CURRENT(&audiohook_list->manipulate_list, list);
00422 audiohook->status = AST_AUDIOHOOK_STATUS_DONE;
00423 ast_audiohook_unlock(audiohook);
00424 audiohook->manipulate_callback(audiohook, NULL, NULL, 0);
00425 }
00426 AST_LIST_TRAVERSE_SAFE_END
00427
00428
00429 for (i = 0; i < 2; i++) {
00430 if (audiohook_list->in_translate[i].trans_pvt)
00431 ast_translator_free_path(audiohook_list->in_translate[i].trans_pvt);
00432 if (audiohook_list->out_translate[i].trans_pvt)
00433 ast_translator_free_path(audiohook_list->out_translate[i].trans_pvt);
00434 }
00435
00436
00437 ast_free(audiohook_list);
00438
00439 return 0;
00440 }
00441
00442 static struct ast_audiohook *find_audiohook_by_source(struct ast_audiohook_list *audiohook_list, const char *source)
00443 {
00444 struct ast_audiohook *audiohook = NULL;
00445
00446 AST_LIST_TRAVERSE(&audiohook_list->spy_list, audiohook, list) {
00447 if (!strcasecmp(audiohook->source, source))
00448 return audiohook;
00449 }
00450
00451 AST_LIST_TRAVERSE(&audiohook_list->whisper_list, audiohook, list) {
00452 if (!strcasecmp(audiohook->source, source))
00453 return audiohook;
00454 }
00455
00456 AST_LIST_TRAVERSE(&audiohook_list->manipulate_list, audiohook, list) {
00457 if (!strcasecmp(audiohook->source, source))
00458 return audiohook;
00459 }
00460
00461 return NULL;
00462 }
00463
00464 void ast_audiohook_move_by_source (struct ast_channel *old_chan, struct ast_channel *new_chan, const char *source)
00465 {
00466 struct ast_audiohook *audiohook;
00467
00468 if (!old_chan->audiohooks || !(audiohook = find_audiohook_by_source(old_chan->audiohooks, source))) {
00469 return;
00470 }
00471
00472
00473
00474
00475
00476
00477 ast_audiohook_lock(audiohook);
00478 ast_audiohook_remove(old_chan, audiohook);
00479 ast_audiohook_attach(new_chan, audiohook);
00480 ast_audiohook_unlock(audiohook);
00481 }
00482
00483
00484
00485
00486
00487
00488 int ast_audiohook_detach_source(struct ast_channel *chan, const char *source)
00489 {
00490 struct ast_audiohook *audiohook = NULL;
00491
00492 ast_channel_lock(chan);
00493
00494
00495 if (!chan->audiohooks) {
00496 ast_channel_unlock(chan);
00497 return -1;
00498 }
00499
00500 audiohook = find_audiohook_by_source(chan->audiohooks, source);
00501
00502 ast_channel_unlock(chan);
00503
00504 if (audiohook && audiohook->status != AST_AUDIOHOOK_STATUS_DONE)
00505 audiohook->status = AST_AUDIOHOOK_STATUS_SHUTDOWN;
00506
00507 return (audiohook ? 0 : -1);
00508 }
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520 int ast_audiohook_remove(struct ast_channel *chan, struct ast_audiohook *audiohook)
00521 {
00522 ast_channel_lock(chan);
00523
00524 if (!chan->audiohooks) {
00525 ast_channel_unlock(chan);
00526 return -1;
00527 }
00528
00529 if (audiohook->type == AST_AUDIOHOOK_TYPE_SPY)
00530 AST_LIST_REMOVE(&chan->audiohooks->spy_list, audiohook, list);
00531 else if (audiohook->type == AST_AUDIOHOOK_TYPE_WHISPER)
00532 AST_LIST_REMOVE(&chan->audiohooks->whisper_list, audiohook, list);
00533 else if (audiohook->type == AST_AUDIOHOOK_TYPE_MANIPULATE)
00534 AST_LIST_REMOVE(&chan->audiohooks->manipulate_list, audiohook, list);
00535
00536 ast_audiohook_lock(audiohook);
00537 audiohook->status = AST_AUDIOHOOK_STATUS_DONE;
00538 ast_cond_signal(&audiohook->trigger);
00539 ast_audiohook_unlock(audiohook);
00540
00541 ast_channel_unlock(chan);
00542
00543 return 0;
00544 }
00545
00546
00547
00548
00549
00550
00551
00552
00553 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)
00554 {
00555 struct ast_audiohook *audiohook = NULL;
00556
00557 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->manipulate_list, audiohook, list) {
00558 ast_audiohook_lock(audiohook);
00559 if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
00560 AST_LIST_REMOVE_CURRENT(&audiohook_list->manipulate_list, list);
00561 audiohook->status = AST_AUDIOHOOK_STATUS_DONE;
00562 ast_audiohook_unlock(audiohook);
00563 audiohook->manipulate_callback(audiohook, NULL, NULL, 0);
00564 continue;
00565 }
00566 if (ast_test_flag(audiohook, AST_AUDIOHOOK_WANTS_DTMF))
00567 audiohook->manipulate_callback(audiohook, chan, frame, direction);
00568 ast_audiohook_unlock(audiohook);
00569 }
00570 AST_LIST_TRAVERSE_SAFE_END
00571
00572 return frame;
00573 }
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604 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)
00605 {
00606 struct ast_audiohook_translate *in_translate = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook_list->in_translate[0] : &audiohook_list->in_translate[1]);
00607 struct ast_audiohook_translate *out_translate = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook_list->out_translate[0] : &audiohook_list->out_translate[1]);
00608 struct ast_frame *start_frame = frame, *middle_frame = frame, *end_frame = frame;
00609 struct ast_audiohook *audiohook = NULL;
00610 int samples = frame->samples;
00611
00612
00613
00614 if (frame->subclass != AST_FORMAT_SLINEAR) {
00615 if (in_translate->format != frame->subclass) {
00616 if (in_translate->trans_pvt)
00617 ast_translator_free_path(in_translate->trans_pvt);
00618 if (!(in_translate->trans_pvt = ast_translator_build_path(AST_FORMAT_SLINEAR, frame->subclass)))
00619 return frame;
00620 in_translate->format = frame->subclass;
00621 }
00622 if (!(middle_frame = ast_translate(in_translate->trans_pvt, frame, 0)))
00623 return frame;
00624 samples = middle_frame->samples;
00625 }
00626
00627
00628
00629 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->spy_list, audiohook, list) {
00630 ast_audiohook_lock(audiohook);
00631 if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
00632 AST_LIST_REMOVE_CURRENT(&audiohook_list->spy_list, list);
00633 audiohook->status = AST_AUDIOHOOK_STATUS_DONE;
00634 ast_cond_signal(&audiohook->trigger);
00635 ast_audiohook_unlock(audiohook);
00636 continue;
00637 }
00638 ast_audiohook_write_frame(audiohook, direction, middle_frame);
00639 ast_audiohook_unlock(audiohook);
00640 }
00641 AST_LIST_TRAVERSE_SAFE_END
00642
00643
00644 if (direction == AST_AUDIOHOOK_DIRECTION_WRITE && !AST_LIST_EMPTY(&audiohook_list->whisper_list)) {
00645 int i = 0;
00646 short read_buf[samples], combine_buf[samples], *data1 = NULL, *data2 = NULL;
00647 memset(&combine_buf, 0, sizeof(combine_buf));
00648 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->whisper_list, audiohook, list) {
00649 ast_audiohook_lock(audiohook);
00650 if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
00651 AST_LIST_REMOVE_CURRENT(&audiohook_list->whisper_list, list);
00652 audiohook->status = AST_AUDIOHOOK_STATUS_DONE;
00653 ast_cond_signal(&audiohook->trigger);
00654 ast_audiohook_unlock(audiohook);
00655 continue;
00656 }
00657 if (ast_slinfactory_available(&audiohook->write_factory) >= samples && ast_slinfactory_read(&audiohook->write_factory, read_buf, samples)) {
00658
00659 for (i = 0, data1 = combine_buf, data2 = read_buf; i < samples; i++, data1++, data2++)
00660 ast_slinear_saturated_add(data1, data2);
00661 }
00662 ast_audiohook_unlock(audiohook);
00663 }
00664 AST_LIST_TRAVERSE_SAFE_END
00665
00666 for (i = 0, data1 = middle_frame->data, data2 = combine_buf; i < samples; i++, data1++, data2++)
00667 ast_slinear_saturated_add(data1, data2);
00668 end_frame = middle_frame;
00669 }
00670
00671
00672 if (!AST_LIST_EMPTY(&audiohook_list->manipulate_list)) {
00673 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->manipulate_list, audiohook, list) {
00674 ast_audiohook_lock(audiohook);
00675 if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
00676 AST_LIST_REMOVE_CURRENT(&audiohook_list->manipulate_list, list);
00677 audiohook->status = AST_AUDIOHOOK_STATUS_DONE;
00678 ast_audiohook_unlock(audiohook);
00679
00680 audiohook->manipulate_callback(audiohook, chan, NULL, direction);
00681 continue;
00682 }
00683
00684 if (audiohook->manipulate_callback(audiohook, chan, middle_frame, direction)) {
00685
00686
00687
00688
00689
00690 }
00691 ast_audiohook_unlock(audiohook);
00692 }
00693 AST_LIST_TRAVERSE_SAFE_END
00694 end_frame = middle_frame;
00695 }
00696
00697
00698 if (middle_frame == end_frame) {
00699
00700 if (end_frame->subclass != start_frame->subclass) {
00701 if (out_translate->format != start_frame->subclass) {
00702 if (out_translate->trans_pvt)
00703 ast_translator_free_path(out_translate->trans_pvt);
00704 if (!(out_translate->trans_pvt = ast_translator_build_path(start_frame->subclass, AST_FORMAT_SLINEAR))) {
00705
00706 ast_frfree(middle_frame);
00707 return start_frame;
00708 }
00709 out_translate->format = start_frame->subclass;
00710 }
00711
00712 if (!(end_frame = ast_translate(out_translate->trans_pvt, middle_frame, 0))) {
00713
00714 ast_frfree(middle_frame);
00715 return start_frame;
00716 }
00717
00718 ast_frfree(middle_frame);
00719 }
00720 } else {
00721
00722 ast_frfree(middle_frame);
00723 }
00724
00725 return end_frame;
00726 }
00727
00728 int ast_audiohook_write_list_empty(struct ast_audiohook_list *audiohook_list)
00729 {
00730 if (AST_LIST_EMPTY(&audiohook_list->spy_list) &&
00731 AST_LIST_EMPTY(&audiohook_list->whisper_list) &&
00732 AST_LIST_EMPTY(&audiohook_list->manipulate_list)) {
00733
00734 return 1;
00735 }
00736 return 0;
00737 }
00738
00739
00740
00741
00742
00743
00744
00745
00746 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)
00747 {
00748
00749 if (frame->frametype == AST_FRAME_VOICE)
00750 return audio_audiohook_write_list(chan, audiohook_list, direction, frame);
00751 else if (frame->frametype == AST_FRAME_DTMF)
00752 return dtmf_audiohook_write_list(chan, audiohook_list, direction, frame);
00753 else
00754 return frame;
00755 }
00756
00757
00758
00759
00760 void ast_audiohook_trigger_wait(struct ast_audiohook *audiohook)
00761 {
00762 struct timeval tv;
00763 struct timespec ts;
00764
00765 tv = ast_tvadd(ast_tvnow(), ast_samp2tv(50000, 1000));
00766 ts.tv_sec = tv.tv_sec;
00767 ts.tv_nsec = tv.tv_usec * 1000;
00768
00769 ast_cond_timedwait(&audiohook->trigger, &audiohook->lock, &ts);
00770
00771 return;
00772 }