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