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: 279946 $")
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 int 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
00131
00132 *rwtime = ast_tvnow();
00133
00134 our_factory_samples = ast_slinfactory_available(factory);
00135 our_factory_ms = ast_tvdiff_ms(*rwtime, previous_time) + (our_factory_samples / 8);
00136 other_factory_samples = ast_slinfactory_available(other_factory);
00137 other_factory_ms = other_factory_samples / 8;
00138
00139 if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC) && other_factory_samples && (our_factory_ms - other_factory_ms > AST_AUDIOHOOK_SYNC_TOLERANCE)) {
00140 if (option_debug)
00141 ast_log(LOG_DEBUG, "Flushing audiohook %p so it remains in sync\n", audiohook);
00142 ast_slinfactory_flush(factory);
00143 ast_slinfactory_flush(other_factory);
00144 }
00145
00146 if (ast_test_flag(audiohook, AST_AUDIOHOOK_SMALL_QUEUE) && (our_factory_samples > 640 || other_factory_samples > 640)) {
00147 if (option_debug) {
00148 ast_log(LOG_DEBUG, "Audiohook %p has stale audio in its factories. Flushing them both\n", audiohook);
00149 }
00150 ast_slinfactory_flush(factory);
00151 ast_slinfactory_flush(other_factory);
00152 }
00153
00154
00155 ast_slinfactory_feed(factory, frame);
00156
00157
00158 if ((ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_MODE) == AST_AUDIOHOOK_TRIGGER_READ) && (direction == AST_AUDIOHOOK_DIRECTION_READ)) {
00159 ast_cond_signal(&audiohook->trigger);
00160 } else if ((ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_MODE) == AST_AUDIOHOOK_TRIGGER_WRITE) && (direction == AST_AUDIOHOOK_DIRECTION_WRITE)) {
00161 ast_cond_signal(&audiohook->trigger);
00162 } else if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC)) {
00163 ast_cond_signal(&audiohook->trigger);
00164 }
00165
00166 return 0;
00167 }
00168
00169 static struct ast_frame *audiohook_read_frame_single(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction)
00170 {
00171 struct ast_slinfactory *factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_factory : &audiohook->write_factory);
00172 int vol = (direction == AST_AUDIOHOOK_DIRECTION_READ ? audiohook->options.read_volume : audiohook->options.write_volume);
00173 short buf[samples];
00174 struct ast_frame frame = {
00175 .frametype = AST_FRAME_VOICE,
00176 .subclass = AST_FORMAT_SLINEAR,
00177 .data.ptr = buf,
00178 .datalen = sizeof(buf),
00179 .samples = samples,
00180 };
00181
00182
00183 if (samples > ast_slinfactory_available(factory))
00184 return NULL;
00185
00186
00187 if (!ast_slinfactory_read(factory, buf, samples))
00188 return NULL;
00189
00190
00191 if (vol)
00192 ast_frame_adjust_volume(&frame, vol);
00193
00194 return ast_frdup(&frame);
00195 }
00196
00197 static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audiohook, size_t samples)
00198 {
00199 int i = 0, usable_read, usable_write;
00200 short buf1[samples], buf2[samples], *read_buf = NULL, *write_buf = NULL, *final_buf = NULL, *data1 = NULL, *data2 = NULL;
00201 struct ast_frame frame = {
00202 .frametype = AST_FRAME_VOICE,
00203 .subclass = AST_FORMAT_SLINEAR,
00204 .data.ptr = NULL,
00205 .datalen = sizeof(buf1),
00206 .samples = samples,
00207 };
00208
00209
00210 usable_read = (ast_slinfactory_available(&audiohook->read_factory) >= samples ? 1 : 0);
00211 usable_write = (ast_slinfactory_available(&audiohook->write_factory) >= samples ? 1 : 0);
00212
00213 if (!usable_read && !usable_write) {
00214
00215 ast_debug(1, "Read factory %p and write factory %p both fail to provide %zd samples\n", &audiohook->read_factory, &audiohook->write_factory, samples);
00216 return NULL;
00217 }
00218
00219
00220 if (usable_read && !usable_write && (ast_tvdiff_ms(ast_tvnow(), audiohook->write_time) < (samples/8)*2)) {
00221 ast_debug(3, "Write factory %p was pretty quick last time, waiting for them.\n", &audiohook->write_factory);
00222 return NULL;
00223 }
00224
00225
00226 if (usable_write && !usable_read && (ast_tvdiff_ms(ast_tvnow(), audiohook->read_time) < (samples/8)*2)) {
00227 ast_debug(3, "Read factory %p was pretty quick last time, waiting for them.\n", &audiohook->read_factory);
00228 return NULL;
00229 }
00230
00231
00232 if (usable_read) {
00233 if (ast_slinfactory_read(&audiohook->read_factory, buf1, samples)) {
00234 read_buf = buf1;
00235
00236 if (audiohook->options.read_volume) {
00237 int count = 0;
00238 short adjust_value = abs(audiohook->options.read_volume);
00239 for (count = 0; count < samples; count++) {
00240 if (audiohook->options.read_volume > 0)
00241 ast_slinear_saturated_multiply(&buf1[count], &adjust_value);
00242 else if (audiohook->options.read_volume < 0)
00243 ast_slinear_saturated_divide(&buf1[count], &adjust_value);
00244 }
00245 }
00246 }
00247 } else if (option_debug)
00248 ast_log(LOG_DEBUG, "Failed to get %d samples from read factory %p\n", (int)samples, &audiohook->read_factory);
00249
00250
00251 if (usable_write) {
00252 if (ast_slinfactory_read(&audiohook->write_factory, buf2, samples)) {
00253 write_buf = buf2;
00254
00255 if (audiohook->options.write_volume) {
00256 int count = 0;
00257 short adjust_value = abs(audiohook->options.write_volume);
00258 for (count = 0; count < samples; count++) {
00259 if (audiohook->options.write_volume > 0)
00260 ast_slinear_saturated_multiply(&buf2[count], &adjust_value);
00261 else if (audiohook->options.write_volume < 0)
00262 ast_slinear_saturated_divide(&buf2[count], &adjust_value);
00263 }
00264 }
00265 }
00266 } else if (option_debug)
00267 ast_log(LOG_DEBUG, "Failed to get %d samples from write factory %p\n", (int)samples, &audiohook->write_factory);
00268
00269
00270 if (!read_buf && !write_buf)
00271 return NULL;
00272 else if (read_buf && write_buf) {
00273 for (i = 0, data1 = read_buf, data2 = write_buf; i < samples; i++, data1++, data2++)
00274 ast_slinear_saturated_add(data1, data2);
00275 final_buf = buf1;
00276 } else if (read_buf)
00277 final_buf = buf1;
00278 else if (write_buf)
00279 final_buf = buf2;
00280
00281
00282 frame.data.ptr = final_buf;
00283
00284
00285 return ast_frdup(&frame);
00286 }
00287
00288
00289
00290
00291
00292
00293
00294
00295 struct ast_frame *ast_audiohook_read_frame(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, int format)
00296 {
00297 struct ast_frame *read_frame = NULL, *final_frame = NULL;
00298
00299 if (!(read_frame = (direction == AST_AUDIOHOOK_DIRECTION_BOTH ? audiohook_read_frame_both(audiohook, samples) : audiohook_read_frame_single(audiohook, samples, direction))))
00300 return NULL;
00301
00302
00303 if (format != AST_FORMAT_SLINEAR) {
00304
00305 if (audiohook->format != format) {
00306 if (audiohook->trans_pvt) {
00307 ast_translator_free_path(audiohook->trans_pvt);
00308 audiohook->trans_pvt = NULL;
00309 }
00310
00311 if (!(audiohook->trans_pvt = ast_translator_build_path(format, AST_FORMAT_SLINEAR))) {
00312 ast_frfree(read_frame);
00313 return NULL;
00314 }
00315 }
00316
00317 final_frame = ast_translate(audiohook->trans_pvt, read_frame, 1);
00318 } else {
00319 final_frame = read_frame;
00320 }
00321
00322 return final_frame;
00323 }
00324
00325
00326
00327
00328
00329
00330 int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
00331 {
00332 ast_channel_lock(chan);
00333
00334 if (!chan->audiohooks) {
00335
00336 if (!(chan->audiohooks = ast_calloc(1, sizeof(*chan->audiohooks)))) {
00337 ast_channel_unlock(chan);
00338 return -1;
00339 }
00340 AST_LIST_HEAD_INIT_NOLOCK(&chan->audiohooks->spy_list);
00341 AST_LIST_HEAD_INIT_NOLOCK(&chan->audiohooks->whisper_list);
00342 AST_LIST_HEAD_INIT_NOLOCK(&chan->audiohooks->manipulate_list);
00343 }
00344
00345
00346 if (audiohook->type == AST_AUDIOHOOK_TYPE_SPY)
00347 AST_LIST_INSERT_TAIL(&chan->audiohooks->spy_list, audiohook, list);
00348 else if (audiohook->type == AST_AUDIOHOOK_TYPE_WHISPER)
00349 AST_LIST_INSERT_TAIL(&chan->audiohooks->whisper_list, audiohook, list);
00350 else if (audiohook->type == AST_AUDIOHOOK_TYPE_MANIPULATE)
00351 AST_LIST_INSERT_TAIL(&chan->audiohooks->manipulate_list, audiohook, list);
00352
00353
00354 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_RUNNING);
00355
00356 ast_channel_unlock(chan);
00357
00358 return 0;
00359 }
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369 void ast_audiohook_update_status(struct ast_audiohook *audiohook, enum ast_audiohook_status status)
00370 {
00371 ast_audiohook_lock(audiohook);
00372 if (audiohook->status != AST_AUDIOHOOK_STATUS_DONE) {
00373 audiohook->status = status;
00374 ast_cond_signal(&audiohook->trigger);
00375 }
00376 ast_audiohook_unlock(audiohook);
00377 }
00378
00379
00380
00381
00382
00383 int ast_audiohook_detach(struct ast_audiohook *audiohook)
00384 {
00385 if (audiohook->status == AST_AUDIOHOOK_STATUS_NEW || audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
00386 return 0;
00387
00388 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_SHUTDOWN);
00389
00390 while (audiohook->status != AST_AUDIOHOOK_STATUS_DONE)
00391 ast_audiohook_trigger_wait(audiohook);
00392
00393 return 0;
00394 }
00395
00396
00397
00398
00399
00400 int ast_audiohook_detach_list(struct ast_audiohook_list *audiohook_list)
00401 {
00402 int i = 0;
00403 struct ast_audiohook *audiohook = NULL;
00404
00405
00406 while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->spy_list, list))) {
00407 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00408 }
00409
00410
00411 while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->whisper_list, list))) {
00412 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00413 }
00414
00415
00416 while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->manipulate_list, list))) {
00417 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00418 audiohook->manipulate_callback(audiohook, NULL, NULL, 0);
00419 }
00420
00421
00422 for (i = 0; i < 2; i++) {
00423 if (audiohook_list->in_translate[i].trans_pvt)
00424 ast_translator_free_path(audiohook_list->in_translate[i].trans_pvt);
00425 if (audiohook_list->out_translate[i].trans_pvt)
00426 ast_translator_free_path(audiohook_list->out_translate[i].trans_pvt);
00427 }
00428
00429
00430 ast_free(audiohook_list);
00431
00432 return 0;
00433 }
00434
00435
00436
00437
00438
00439
00440 static struct ast_audiohook *find_audiohook_by_source(struct ast_audiohook_list *audiohook_list, const char *source)
00441 {
00442 struct ast_audiohook *audiohook = NULL;
00443
00444 AST_LIST_TRAVERSE(&audiohook_list->spy_list, audiohook, list) {
00445 if (!strcasecmp(audiohook->source, source))
00446 return audiohook;
00447 }
00448
00449 AST_LIST_TRAVERSE(&audiohook_list->whisper_list, audiohook, list) {
00450 if (!strcasecmp(audiohook->source, source))
00451 return audiohook;
00452 }
00453
00454 AST_LIST_TRAVERSE(&audiohook_list->manipulate_list, audiohook, list) {
00455 if (!strcasecmp(audiohook->source, source))
00456 return audiohook;
00457 }
00458
00459 return NULL;
00460 }
00461
00462 void ast_audiohook_move_by_source(struct ast_channel *old_chan, struct ast_channel *new_chan, const char *source)
00463 {
00464 struct ast_audiohook *audiohook;
00465 enum ast_audiohook_status oldstatus;
00466
00467 if (!old_chan->audiohooks || !(audiohook = find_audiohook_by_source(old_chan->audiohooks, source))) {
00468 return;
00469 }
00470
00471
00472
00473
00474
00475
00476 ast_audiohook_lock(audiohook);
00477 oldstatus = audiohook->status;
00478
00479 ast_audiohook_remove(old_chan, audiohook);
00480 ast_audiohook_attach(new_chan, audiohook);
00481
00482 audiohook->status = oldstatus;
00483 ast_audiohook_unlock(audiohook);
00484 }
00485
00486
00487
00488
00489
00490
00491 int ast_audiohook_detach_source(struct ast_channel *chan, const char *source)
00492 {
00493 struct ast_audiohook *audiohook = NULL;
00494
00495 ast_channel_lock(chan);
00496
00497
00498 if (!chan->audiohooks) {
00499 ast_channel_unlock(chan);
00500 return -1;
00501 }
00502
00503 audiohook = find_audiohook_by_source(chan->audiohooks, source);
00504
00505 ast_channel_unlock(chan);
00506
00507 if (audiohook && audiohook->status != AST_AUDIOHOOK_STATUS_DONE)
00508 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_SHUTDOWN);
00509
00510 return (audiohook ? 0 : -1);
00511 }
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523 int ast_audiohook_remove(struct ast_channel *chan, struct ast_audiohook *audiohook)
00524 {
00525 ast_channel_lock(chan);
00526
00527 if (!chan->audiohooks) {
00528 ast_channel_unlock(chan);
00529 return -1;
00530 }
00531
00532 if (audiohook->type == AST_AUDIOHOOK_TYPE_SPY)
00533 AST_LIST_REMOVE(&chan->audiohooks->spy_list, audiohook, list);
00534 else if (audiohook->type == AST_AUDIOHOOK_TYPE_WHISPER)
00535 AST_LIST_REMOVE(&chan->audiohooks->whisper_list, audiohook, list);
00536 else if (audiohook->type == AST_AUDIOHOOK_TYPE_MANIPULATE)
00537 AST_LIST_REMOVE(&chan->audiohooks->manipulate_list, audiohook, list);
00538
00539 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
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(list);
00561 ast_audiohook_update_status(audiohook, 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(list);
00633 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00634 ast_audiohook_unlock(audiohook);
00635 continue;
00636 }
00637 ast_audiohook_write_frame(audiohook, direction, middle_frame);
00638 ast_audiohook_unlock(audiohook);
00639 }
00640 AST_LIST_TRAVERSE_SAFE_END;
00641
00642
00643 if (direction == AST_AUDIOHOOK_DIRECTION_WRITE && !AST_LIST_EMPTY(&audiohook_list->whisper_list)) {
00644 int i = 0;
00645 short read_buf[samples], combine_buf[samples], *data1 = NULL, *data2 = NULL;
00646 memset(&combine_buf, 0, sizeof(combine_buf));
00647 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->whisper_list, audiohook, list) {
00648 ast_audiohook_lock(audiohook);
00649 if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
00650 AST_LIST_REMOVE_CURRENT(list);
00651 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00652 ast_audiohook_unlock(audiohook);
00653 continue;
00654 }
00655 if (ast_slinfactory_available(&audiohook->write_factory) >= samples && ast_slinfactory_read(&audiohook->write_factory, read_buf, samples)) {
00656
00657 for (i = 0, data1 = combine_buf, data2 = read_buf; i < samples; i++, data1++, data2++)
00658 ast_slinear_saturated_add(data1, data2);
00659 }
00660 ast_audiohook_unlock(audiohook);
00661 }
00662 AST_LIST_TRAVERSE_SAFE_END;
00663
00664 for (i = 0, data1 = middle_frame->data.ptr, data2 = combine_buf; i < samples; i++, data1++, data2++)
00665 ast_slinear_saturated_add(data1, data2);
00666 end_frame = middle_frame;
00667 }
00668
00669
00670 if (!AST_LIST_EMPTY(&audiohook_list->manipulate_list)) {
00671 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->manipulate_list, audiohook, list) {
00672 ast_audiohook_lock(audiohook);
00673 if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
00674 AST_LIST_REMOVE_CURRENT(list);
00675 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00676 ast_audiohook_unlock(audiohook);
00677
00678 audiohook->manipulate_callback(audiohook, chan, NULL, direction);
00679 continue;
00680 }
00681
00682 if (audiohook->manipulate_callback(audiohook, chan, middle_frame, direction)) {
00683
00684
00685
00686
00687
00688 }
00689 ast_audiohook_unlock(audiohook);
00690 }
00691 AST_LIST_TRAVERSE_SAFE_END;
00692 end_frame = middle_frame;
00693 }
00694
00695
00696 if (middle_frame == end_frame) {
00697
00698 if (end_frame->subclass != start_frame->subclass) {
00699 if (out_translate->format != start_frame->subclass) {
00700 if (out_translate->trans_pvt)
00701 ast_translator_free_path(out_translate->trans_pvt);
00702 if (!(out_translate->trans_pvt = ast_translator_build_path(start_frame->subclass, AST_FORMAT_SLINEAR))) {
00703
00704 ast_frfree(middle_frame);
00705 return start_frame;
00706 }
00707 out_translate->format = start_frame->subclass;
00708 }
00709
00710 if (!(end_frame = ast_translate(out_translate->trans_pvt, middle_frame, 0))) {
00711
00712 ast_frfree(middle_frame);
00713 return start_frame;
00714 }
00715
00716 ast_frfree(middle_frame);
00717 }
00718 } else {
00719
00720 ast_frfree(middle_frame);
00721 }
00722
00723 return end_frame;
00724 }
00725
00726 int ast_audiohook_write_list_empty(struct ast_audiohook_list *audiohook_list)
00727 {
00728 if (AST_LIST_EMPTY(&audiohook_list->spy_list) &&
00729 AST_LIST_EMPTY(&audiohook_list->whisper_list) &&
00730 AST_LIST_EMPTY(&audiohook_list->manipulate_list)) {
00731
00732 return 1;
00733 }
00734 return 0;
00735 }
00736
00737
00738
00739
00740
00741
00742
00743
00744 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)
00745 {
00746
00747 if (frame->frametype == AST_FRAME_VOICE)
00748 return audio_audiohook_write_list(chan, audiohook_list, direction, frame);
00749 else if (frame->frametype == AST_FRAME_DTMF)
00750 return dtmf_audiohook_write_list(chan, audiohook_list, direction, frame);
00751 else
00752 return frame;
00753 }
00754
00755
00756
00757
00758 void ast_audiohook_trigger_wait(struct ast_audiohook *audiohook)
00759 {
00760 struct timeval wait;
00761 struct timespec ts;
00762
00763 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(50000, 1000));
00764 ts.tv_sec = wait.tv_sec;
00765 ts.tv_nsec = wait.tv_usec * 1000;
00766
00767 ast_cond_timedwait(&audiohook->trigger, &audiohook->lock, &ts);
00768
00769 return;
00770 }
00771
00772
00773 int ast_channel_audiohook_count_by_source(struct ast_channel *chan, const char *source, enum ast_audiohook_type type)
00774 {
00775 int count = 0;
00776 struct ast_audiohook *ah = NULL;
00777
00778 if (!chan->audiohooks)
00779 return -1;
00780
00781 switch (type) {
00782 case AST_AUDIOHOOK_TYPE_SPY:
00783 AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->spy_list, ah, list) {
00784 if (!strcmp(ah->source, source)) {
00785 count++;
00786 }
00787 }
00788 AST_LIST_TRAVERSE_SAFE_END;
00789 break;
00790 case AST_AUDIOHOOK_TYPE_WHISPER:
00791 AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->whisper_list, ah, list) {
00792 if (!strcmp(ah->source, source)) {
00793 count++;
00794 }
00795 }
00796 AST_LIST_TRAVERSE_SAFE_END;
00797 break;
00798 case AST_AUDIOHOOK_TYPE_MANIPULATE:
00799 AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->manipulate_list, ah, list) {
00800 if (!strcmp(ah->source, source)) {
00801 count++;
00802 }
00803 }
00804 AST_LIST_TRAVERSE_SAFE_END;
00805 break;
00806 default:
00807 ast_log(LOG_DEBUG, "Invalid audiohook type supplied, (%d)\n", type);
00808 return -1;
00809 }
00810
00811 return count;
00812 }
00813
00814
00815 int ast_channel_audiohook_count_by_source_running(struct ast_channel *chan, const char *source, enum ast_audiohook_type type)
00816 {
00817 int count = 0;
00818 struct ast_audiohook *ah = NULL;
00819 if (!chan->audiohooks)
00820 return -1;
00821
00822 switch (type) {
00823 case AST_AUDIOHOOK_TYPE_SPY:
00824 AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->spy_list, ah, list) {
00825 if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
00826 count++;
00827 }
00828 AST_LIST_TRAVERSE_SAFE_END;
00829 break;
00830 case AST_AUDIOHOOK_TYPE_WHISPER:
00831 AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->whisper_list, ah, list) {
00832 if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
00833 count++;
00834 }
00835 AST_LIST_TRAVERSE_SAFE_END;
00836 break;
00837 case AST_AUDIOHOOK_TYPE_MANIPULATE:
00838 AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->manipulate_list, ah, list) {
00839 if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
00840 count++;
00841 }
00842 AST_LIST_TRAVERSE_SAFE_END;
00843 break;
00844 default:
00845 ast_log(LOG_DEBUG, "Invalid audiohook type supplied, (%d)\n", type);
00846 return -1;
00847 }
00848 return count;
00849 }
00850
00851
00852 struct audiohook_volume {
00853 struct ast_audiohook audiohook;
00854 int read_adjustment;
00855 int write_adjustment;
00856 };
00857
00858
00859
00860
00861
00862 static void audiohook_volume_destroy(void *data)
00863 {
00864 struct audiohook_volume *audiohook_volume = data;
00865
00866
00867 ast_audiohook_destroy(&audiohook_volume->audiohook);
00868
00869
00870 ast_free(audiohook_volume);
00871
00872 return;
00873 }
00874
00875
00876 static const struct ast_datastore_info audiohook_volume_datastore = {
00877 .type = "Volume",
00878 .destroy = audiohook_volume_destroy,
00879 };
00880
00881
00882
00883
00884
00885
00886
00887
00888 static int audiohook_volume_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
00889 {
00890 struct ast_datastore *datastore = NULL;
00891 struct audiohook_volume *audiohook_volume = NULL;
00892 int *gain = NULL;
00893
00894
00895 if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) {
00896 return 0;
00897 }
00898
00899
00900 if (!(datastore = ast_channel_datastore_find(chan, &audiohook_volume_datastore, NULL))) {
00901 return 0;
00902 }
00903
00904 audiohook_volume = datastore->data;
00905
00906
00907 if (direction == AST_AUDIOHOOK_DIRECTION_READ) {
00908 gain = &audiohook_volume->read_adjustment;
00909 } else if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) {
00910 gain = &audiohook_volume->write_adjustment;
00911 }
00912
00913
00914 if (gain && *gain) {
00915 ast_frame_adjust_volume(frame, *gain);
00916 }
00917
00918 return 0;
00919 }
00920
00921
00922
00923
00924
00925
00926 static struct audiohook_volume *audiohook_volume_get(struct ast_channel *chan, int create)
00927 {
00928 struct ast_datastore *datastore = NULL;
00929 struct audiohook_volume *audiohook_volume = NULL;
00930
00931
00932 if ((datastore = ast_channel_datastore_find(chan, &audiohook_volume_datastore, NULL))) {
00933 return datastore->data;
00934 }
00935
00936
00937 if (!create || !(datastore = ast_datastore_alloc(&audiohook_volume_datastore, NULL))) {
00938 return NULL;
00939 }
00940
00941
00942 if (!(audiohook_volume = ast_calloc(1, sizeof(*audiohook_volume)))) {
00943 ast_datastore_free(datastore);
00944 return NULL;
00945 }
00946
00947
00948 ast_audiohook_init(&audiohook_volume->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Volume");
00949 audiohook_volume->audiohook.manipulate_callback = audiohook_volume_callback;
00950
00951
00952 datastore->data = audiohook_volume;
00953 ast_channel_datastore_add(chan, datastore);
00954
00955
00956 ast_audiohook_attach(chan, &audiohook_volume->audiohook);
00957
00958 return audiohook_volume;
00959 }
00960
00961
00962
00963
00964
00965
00966
00967 int ast_audiohook_volume_set(struct ast_channel *chan, enum ast_audiohook_direction direction, int volume)
00968 {
00969 struct audiohook_volume *audiohook_volume = NULL;
00970
00971
00972 if (!(audiohook_volume = audiohook_volume_get(chan, (volume ? 1 : 0)))) {
00973 return -1;
00974 }
00975
00976
00977 if (direction == AST_AUDIOHOOK_DIRECTION_READ || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
00978 audiohook_volume->read_adjustment = volume;
00979 }
00980 if (direction == AST_AUDIOHOOK_DIRECTION_WRITE || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
00981 audiohook_volume->write_adjustment = volume;
00982 }
00983
00984 return 0;
00985 }
00986
00987
00988
00989
00990
00991
00992 int ast_audiohook_volume_get(struct ast_channel *chan, enum ast_audiohook_direction direction)
00993 {
00994 struct audiohook_volume *audiohook_volume = NULL;
00995 int adjustment = 0;
00996
00997
00998 if (!(audiohook_volume = audiohook_volume_get(chan, 0))) {
00999 return 0;
01000 }
01001
01002
01003 if (direction == AST_AUDIOHOOK_DIRECTION_READ) {
01004 adjustment = audiohook_volume->read_adjustment;
01005 } else if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) {
01006 adjustment = audiohook_volume->write_adjustment;
01007 }
01008
01009 return adjustment;
01010 }
01011
01012
01013
01014
01015
01016
01017
01018 int ast_audiohook_volume_adjust(struct ast_channel *chan, enum ast_audiohook_direction direction, int volume)
01019 {
01020 struct audiohook_volume *audiohook_volume = NULL;
01021
01022
01023 if (!(audiohook_volume = audiohook_volume_get(chan, 1))) {
01024 return -1;
01025 }
01026
01027
01028 if (direction == AST_AUDIOHOOK_DIRECTION_READ || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
01029 audiohook_volume->read_adjustment += volume;
01030 }
01031 if (direction == AST_AUDIOHOOK_DIRECTION_WRITE || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
01032 audiohook_volume->write_adjustment += volume;
01033 }
01034
01035 return 0;
01036 }