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