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: 260052 $")
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
00727
00728
00729
00730
00731
00732
00733 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)
00734 {
00735
00736 if (frame->frametype == AST_FRAME_VOICE)
00737 return audio_audiohook_write_list(chan, audiohook_list, direction, frame);
00738 else if (frame->frametype == AST_FRAME_DTMF)
00739 return dtmf_audiohook_write_list(chan, audiohook_list, direction, frame);
00740 else
00741 return frame;
00742 }
00743
00744
00745
00746
00747
00748 void ast_audiohook_trigger_wait(struct ast_audiohook *audiohook)
00749 {
00750 struct timeval wait;
00751 struct timespec ts;
00752
00753 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(50000, 1000));
00754 ts.tv_sec = wait.tv_sec;
00755 ts.tv_nsec = wait.tv_usec * 1000;
00756
00757 ast_cond_timedwait(&audiohook->trigger, &audiohook->lock, &ts);
00758
00759 return;
00760 }
00761
00762
00763 int ast_channel_audiohook_count_by_source(struct ast_channel *chan, const char *source, enum ast_audiohook_type type)
00764 {
00765 int count = 0;
00766 struct ast_audiohook *ah = NULL;
00767
00768 if (!chan->audiohooks)
00769 return -1;
00770
00771 switch (type) {
00772 case AST_AUDIOHOOK_TYPE_SPY:
00773 AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->spy_list, ah, list) {
00774 if (!strcmp(ah->source, source)) {
00775 count++;
00776 }
00777 }
00778 AST_LIST_TRAVERSE_SAFE_END;
00779 break;
00780 case AST_AUDIOHOOK_TYPE_WHISPER:
00781 AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->whisper_list, ah, list) {
00782 if (!strcmp(ah->source, source)) {
00783 count++;
00784 }
00785 }
00786 AST_LIST_TRAVERSE_SAFE_END;
00787 break;
00788 case AST_AUDIOHOOK_TYPE_MANIPULATE:
00789 AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->manipulate_list, ah, list) {
00790 if (!strcmp(ah->source, source)) {
00791 count++;
00792 }
00793 }
00794 AST_LIST_TRAVERSE_SAFE_END;
00795 break;
00796 default:
00797 ast_log(LOG_DEBUG, "Invalid audiohook type supplied, (%d)\n", type);
00798 return -1;
00799 }
00800
00801 return count;
00802 }
00803
00804
00805 int ast_channel_audiohook_count_by_source_running(struct ast_channel *chan, const char *source, enum ast_audiohook_type type)
00806 {
00807 int count = 0;
00808 struct ast_audiohook *ah = NULL;
00809 if (!chan->audiohooks)
00810 return -1;
00811
00812 switch (type) {
00813 case AST_AUDIOHOOK_TYPE_SPY:
00814 AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->spy_list, ah, list) {
00815 if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
00816 count++;
00817 }
00818 AST_LIST_TRAVERSE_SAFE_END;
00819 break;
00820 case AST_AUDIOHOOK_TYPE_WHISPER:
00821 AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->whisper_list, ah, list) {
00822 if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
00823 count++;
00824 }
00825 AST_LIST_TRAVERSE_SAFE_END;
00826 break;
00827 case AST_AUDIOHOOK_TYPE_MANIPULATE:
00828 AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->manipulate_list, ah, list) {
00829 if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
00830 count++;
00831 }
00832 AST_LIST_TRAVERSE_SAFE_END;
00833 break;
00834 default:
00835 ast_log(LOG_DEBUG, "Invalid audiohook type supplied, (%d)\n", type);
00836 return -1;
00837 }
00838 return count;
00839 }
00840
00841
00842 struct audiohook_volume {
00843 struct ast_audiohook audiohook;
00844 int read_adjustment;
00845 int write_adjustment;
00846 };
00847
00848
00849
00850
00851
00852 static void audiohook_volume_destroy(void *data)
00853 {
00854 struct audiohook_volume *audiohook_volume = data;
00855
00856
00857 ast_audiohook_destroy(&audiohook_volume->audiohook);
00858
00859
00860 ast_free(audiohook_volume);
00861
00862 return;
00863 }
00864
00865
00866 static const struct ast_datastore_info audiohook_volume_datastore = {
00867 .type = "Volume",
00868 .destroy = audiohook_volume_destroy,
00869 };
00870
00871
00872
00873
00874
00875
00876
00877
00878 static int audiohook_volume_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
00879 {
00880 struct ast_datastore *datastore = NULL;
00881 struct audiohook_volume *audiohook_volume = NULL;
00882 int *gain = NULL;
00883
00884
00885 if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) {
00886 return 0;
00887 }
00888
00889
00890 if (!(datastore = ast_channel_datastore_find(chan, &audiohook_volume_datastore, NULL))) {
00891 return 0;
00892 }
00893
00894 audiohook_volume = datastore->data;
00895
00896
00897 if (direction == AST_AUDIOHOOK_DIRECTION_READ) {
00898 gain = &audiohook_volume->read_adjustment;
00899 } else if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) {
00900 gain = &audiohook_volume->write_adjustment;
00901 }
00902
00903
00904 if (gain && *gain) {
00905 ast_frame_adjust_volume(frame, *gain);
00906 }
00907
00908 return 0;
00909 }
00910
00911
00912
00913
00914
00915
00916 static struct audiohook_volume *audiohook_volume_get(struct ast_channel *chan, int create)
00917 {
00918 struct ast_datastore *datastore = NULL;
00919 struct audiohook_volume *audiohook_volume = NULL;
00920
00921
00922 if ((datastore = ast_channel_datastore_find(chan, &audiohook_volume_datastore, NULL))) {
00923 return datastore->data;
00924 }
00925
00926
00927 if (!create || !(datastore = ast_datastore_alloc(&audiohook_volume_datastore, NULL))) {
00928 return NULL;
00929 }
00930
00931
00932 if (!(audiohook_volume = ast_calloc(1, sizeof(*audiohook_volume)))) {
00933 ast_datastore_free(datastore);
00934 return NULL;
00935 }
00936
00937
00938 ast_audiohook_init(&audiohook_volume->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Volume");
00939 audiohook_volume->audiohook.manipulate_callback = audiohook_volume_callback;
00940
00941
00942 datastore->data = audiohook_volume;
00943 ast_channel_datastore_add(chan, datastore);
00944
00945
00946 ast_audiohook_attach(chan, &audiohook_volume->audiohook);
00947
00948 return audiohook_volume;
00949 }
00950
00951
00952
00953
00954
00955
00956
00957 int ast_audiohook_volume_set(struct ast_channel *chan, enum ast_audiohook_direction direction, int volume)
00958 {
00959 struct audiohook_volume *audiohook_volume = NULL;
00960
00961
00962 if (!(audiohook_volume = audiohook_volume_get(chan, (volume ? 1 : 0)))) {
00963 return -1;
00964 }
00965
00966
00967 if (direction == AST_AUDIOHOOK_DIRECTION_READ || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
00968 audiohook_volume->read_adjustment = volume;
00969 }
00970 if (direction == AST_AUDIOHOOK_DIRECTION_WRITE || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
00971 audiohook_volume->write_adjustment = volume;
00972 }
00973
00974 return 0;
00975 }
00976
00977
00978
00979
00980
00981
00982 int ast_audiohook_volume_get(struct ast_channel *chan, enum ast_audiohook_direction direction)
00983 {
00984 struct audiohook_volume *audiohook_volume = NULL;
00985 int adjustment = 0;
00986
00987
00988 if (!(audiohook_volume = audiohook_volume_get(chan, 0))) {
00989 return 0;
00990 }
00991
00992
00993 if (direction == AST_AUDIOHOOK_DIRECTION_READ) {
00994 adjustment = audiohook_volume->read_adjustment;
00995 } else if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) {
00996 adjustment = audiohook_volume->write_adjustment;
00997 }
00998
00999 return adjustment;
01000 }
01001
01002
01003
01004
01005
01006
01007
01008 int ast_audiohook_volume_adjust(struct ast_channel *chan, enum ast_audiohook_direction direction, int volume)
01009 {
01010 struct audiohook_volume *audiohook_volume = NULL;
01011
01012
01013 if (!(audiohook_volume = audiohook_volume_get(chan, 1))) {
01014 return -1;
01015 }
01016
01017
01018 if (direction == AST_AUDIOHOOK_DIRECTION_READ || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
01019 audiohook_volume->read_adjustment += volume;
01020 }
01021 if (direction == AST_AUDIOHOOK_DIRECTION_WRITE || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
01022 audiohook_volume->write_adjustment += volume;
01023 }
01024
01025 return 0;
01026 }