#include "asterisk/linkedlists.h"
Include dependency graph for chanspy.h:
This graph shows which files directly or indirectly include this file:
Go to the source code of this file.
Data Structures | |
struct | ast_channel_spy |
struct | ast_channel_spy_queue |
Enumerations | |
enum | chanspy_flags { CHANSPY_MIXAUDIO = (1 << 0), CHANSPY_READ_VOLADJUST = (1 << 1), CHANSPY_WRITE_VOLADJUST = (1 << 2), CHANSPY_FORMAT_AUDIO = (1 << 3), CHANSPY_TRIGGER_MODE = (3 << 4), CHANSPY_TRIGGER_READ = (1 << 4), CHANSPY_TRIGGER_WRITE = (2 << 4), CHANSPY_TRIGGER_NONE = (3 << 4), CHANSPY_TRIGGER_FLUSH = (1 << 6) } |
enum | chanspy_states { CHANSPY_NEW = 0, CHANSPY_RUNNING = 1, CHANSPY_DONE = 2, CHANSPY_STOP = 3 } |
Functions | |
int | ast_channel_spy_add (struct ast_channel *chan, struct ast_channel_spy *spy) |
Adds a spy to a channel, to begin receiving copies of the channel's audio frames. | |
void | ast_channel_spy_free (struct ast_channel_spy *spy) |
Free a spy. | |
ast_frame * | ast_channel_spy_read_frame (struct ast_channel_spy *spy, unsigned int samples) |
Read one (or more) frames of audio from a channel being spied upon. | |
void | ast_channel_spy_remove (struct ast_channel *chan, struct ast_channel_spy *spy) |
Remove a spy from a channel. | |
void | ast_channel_spy_stop_by_type (struct ast_channel *chan, const char *type) |
Find all spies of a particular type on a channel and stop them. | |
void | ast_channel_spy_trigger_wait (struct ast_channel_spy *spy) |
Efficiently wait until audio is available for a spy, or an exception occurs. |
Definition in file chanspy.h.
enum chanspy_flags |
CHANSPY_MIXAUDIO | |
CHANSPY_READ_VOLADJUST | |
CHANSPY_WRITE_VOLADJUST | |
CHANSPY_FORMAT_AUDIO | |
CHANSPY_TRIGGER_MODE | |
CHANSPY_TRIGGER_READ | |
CHANSPY_TRIGGER_WRITE | |
CHANSPY_TRIGGER_NONE | |
CHANSPY_TRIGGER_FLUSH |
Definition at line 39 of file chanspy.h.
00039 { 00040 CHANSPY_MIXAUDIO = (1 << 0), 00041 CHANSPY_READ_VOLADJUST = (1 << 1), 00042 CHANSPY_WRITE_VOLADJUST = (1 << 2), 00043 CHANSPY_FORMAT_AUDIO = (1 << 3), 00044 CHANSPY_TRIGGER_MODE = (3 << 4), 00045 CHANSPY_TRIGGER_READ = (1 << 4), 00046 CHANSPY_TRIGGER_WRITE = (2 << 4), 00047 CHANSPY_TRIGGER_NONE = (3 << 4), 00048 CHANSPY_TRIGGER_FLUSH = (1 << 6), 00049 };
enum chanspy_states |
Definition at line 32 of file chanspy.h.
00032 { 00033 CHANSPY_NEW = 0, /*!< spy not yet operating */ 00034 CHANSPY_RUNNING = 1, /*!< normal operation, spy is still operating */ 00035 CHANSPY_DONE = 2, /*!< spy is stopped and already removed from channel */ 00036 CHANSPY_STOP = 3, /*!< spy requested to stop, still attached to channel */ 00037 };
int ast_channel_spy_add | ( | struct ast_channel * | chan, | |
struct ast_channel_spy * | spy | |||
) |
Adds a spy to a channel, to begin receiving copies of the channel's audio frames.
chan | The channel to add the spy to. | |
spy | A pointer to ast_channel_spy structure describing how the spy is to be used. |
Definition at line 1369 of file channel.c.
References ast_calloc, ast_clear_flag, ast_cond_init(), AST_FORMAT_SLINEAR, ast_getformatname(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_HEAD, AST_LIST_INSERT_TAIL, ast_log(), ast_set_flag, ast_test_flag, ast_channel_spy::chan, CHANSPY_FORMAT_AUDIO, CHANSPY_MIXAUDIO, CHANSPY_READ_VOLADJUST, CHANSPY_TRIGGER_MODE, CHANSPY_TRIGGER_NONE, CHANSPY_TRIGGER_READ, CHANSPY_TRIGGER_WRITE, CHANSPY_WRITE_VOLADJUST, ast_channel_spy_queue::format, LOG_DEBUG, LOG_WARNING, option_debug, ast_channel_spy::read_queue, ast_channel::spies, ast_channel_spy::trigger, ast_channel_spy::type, and ast_channel_spy::write_queue.
Referenced by start_spying(), and startmon().
01370 { 01371 /* Link the owner channel to the spy */ 01372 spy->chan = chan; 01373 01374 if (!ast_test_flag(spy, CHANSPY_FORMAT_AUDIO)) { 01375 ast_log(LOG_WARNING, "Could not add channel spy '%s' to channel '%s', only audio format spies are supported.\n", 01376 spy->type, chan->name); 01377 return -1; 01378 } 01379 01380 if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST) && (spy->read_queue.format != AST_FORMAT_SLINEAR)) { 01381 ast_log(LOG_WARNING, "Cannot provide volume adjustment on '%s' format spies\n", 01382 ast_getformatname(spy->read_queue.format)); 01383 return -1; 01384 } 01385 01386 if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST) && (spy->write_queue.format != AST_FORMAT_SLINEAR)) { 01387 ast_log(LOG_WARNING, "Cannot provide volume adjustment on '%s' format spies\n", 01388 ast_getformatname(spy->write_queue.format)); 01389 return -1; 01390 } 01391 01392 if (ast_test_flag(spy, CHANSPY_MIXAUDIO) && 01393 ((spy->read_queue.format != AST_FORMAT_SLINEAR) || 01394 (spy->write_queue.format != AST_FORMAT_SLINEAR))) { 01395 ast_log(LOG_WARNING, "Cannot provide audio mixing on '%s'-'%s' format spies\n", 01396 ast_getformatname(spy->read_queue.format), ast_getformatname(spy->write_queue.format)); 01397 return -1; 01398 } 01399 01400 if (!chan->spies) { 01401 if (!(chan->spies = ast_calloc(1, sizeof(*chan->spies)))) { 01402 return -1; 01403 } 01404 01405 AST_LIST_HEAD_INIT_NOLOCK(&chan->spies->list); 01406 AST_LIST_INSERT_HEAD(&chan->spies->list, spy, list); 01407 } else { 01408 AST_LIST_INSERT_TAIL(&chan->spies->list, spy, list); 01409 } 01410 01411 if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE) { 01412 ast_cond_init(&spy->trigger, NULL); 01413 ast_set_flag(spy, CHANSPY_TRIGGER_READ); 01414 ast_clear_flag(spy, CHANSPY_TRIGGER_WRITE); 01415 } 01416 01417 if (option_debug) 01418 ast_log(LOG_DEBUG, "Spy %s added to channel %s\n", 01419 spy->type, chan->name); 01420 01421 return 0; 01422 }
void ast_channel_spy_free | ( | struct ast_channel_spy * | spy | ) |
Free a spy.
spy | The spy to free |
Definition at line 1499 of file channel.c.
References ast_cond_destroy(), ast_frfree(), AST_LIST_REMOVE_HEAD, ast_mutex_destroy(), ast_test_flag, CHANSPY_DONE, CHANSPY_TRIGGER_MODE, CHANSPY_TRIGGER_NONE, f, ast_channel_spy::lock, ast_channel_spy::read_queue, ast_channel_spy::status, ast_channel_spy::trigger, and ast_channel_spy::write_queue.
Referenced by channel_spy(), and mixmonitor_thread().
01500 { 01501 struct ast_frame *f = NULL; 01502 01503 if (spy->status == CHANSPY_DONE) 01504 return; 01505 01506 /* Switch status to done in case we get called twice */ 01507 spy->status = CHANSPY_DONE; 01508 01509 /* Drop any frames in the queue */ 01510 while ((f = AST_LIST_REMOVE_HEAD(&spy->write_queue.list, frame_list))) 01511 ast_frfree(f); 01512 while ((f = AST_LIST_REMOVE_HEAD(&spy->read_queue.list, frame_list))) 01513 ast_frfree(f); 01514 01515 /* Destroy the condition if in use */ 01516 if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE) 01517 ast_cond_destroy(&spy->trigger); 01518 01519 /* Destroy our mutex since it is no longer in use */ 01520 ast_mutex_destroy(&spy->lock); 01521 01522 return; 01523 }
struct ast_frame* ast_channel_spy_read_frame | ( | struct ast_channel_spy * | spy, | |
unsigned int | samples | |||
) |
Read one (or more) frames of audio from a channel being spied upon.
spy | The spy to operate on | |
samples | The number of audio samples to read |
Note: This function performs no locking; you must hold the spy's lock before calling this function. You must not hold the channel's lock at the same time.
Definition at line 4659 of file channel.c.
References ast_clear_flag, ast_codec_get_len(), ast_frame_adjust_volume(), ast_frame_slinear_sum(), AST_FRAME_VOICE, ast_frdup(), ast_frfree(), AST_LIST_FIRST, AST_LIST_HEAD_SET_NOLOCK, AST_LIST_NEXT, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, ast_test_flag, CHANSPY_MIXAUDIO, CHANSPY_READ_VOLADJUST, CHANSPY_TRIGGER_FLUSH, CHANSPY_WRITE_VOLADJUST, copy_data_from_queue(), ast_channel_spy_queue::format, ast_frame::frametype, ast_channel_spy::read_queue, ast_channel_spy::read_vol_adjustment, result, ast_channel_spy_queue::samples, ast_channel_spy::write_queue, and ast_channel_spy::write_vol_adjustment.
Referenced by mixmonitor_thread(), and spy_generate().
04660 { 04661 struct ast_frame *result; 04662 /* buffers are allocated to hold SLINEAR, which is the largest format */ 04663 short read_buf[samples]; 04664 short write_buf[samples]; 04665 struct ast_frame *read_frame; 04666 struct ast_frame *write_frame; 04667 int need_dup; 04668 struct ast_frame stack_read_frame = { .frametype = AST_FRAME_VOICE, 04669 .subclass = spy->read_queue.format, 04670 .data = read_buf, 04671 .samples = samples, 04672 .datalen = ast_codec_get_len(spy->read_queue.format, samples), 04673 }; 04674 struct ast_frame stack_write_frame = { .frametype = AST_FRAME_VOICE, 04675 .subclass = spy->write_queue.format, 04676 .data = write_buf, 04677 .samples = samples, 04678 .datalen = ast_codec_get_len(spy->write_queue.format, samples), 04679 }; 04680 04681 /* if a flush has been requested, dump everything in whichever queue is larger */ 04682 if (ast_test_flag(spy, CHANSPY_TRIGGER_FLUSH)) { 04683 if (spy->read_queue.samples > spy->write_queue.samples) { 04684 if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST)) { 04685 AST_LIST_TRAVERSE(&spy->read_queue.list, result, frame_list) 04686 ast_frame_adjust_volume(result, spy->read_vol_adjustment); 04687 } 04688 result = AST_LIST_FIRST(&spy->read_queue.list); 04689 AST_LIST_HEAD_SET_NOLOCK(&spy->read_queue.list, NULL); 04690 spy->read_queue.samples = 0; 04691 } else { 04692 if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST)) { 04693 AST_LIST_TRAVERSE(&spy->write_queue.list, result, frame_list) 04694 ast_frame_adjust_volume(result, spy->write_vol_adjustment); 04695 } 04696 result = AST_LIST_FIRST(&spy->write_queue.list); 04697 AST_LIST_HEAD_SET_NOLOCK(&spy->write_queue.list, NULL); 04698 spy->write_queue.samples = 0; 04699 } 04700 ast_clear_flag(spy, CHANSPY_TRIGGER_FLUSH); 04701 return result; 04702 } 04703 04704 if ((spy->read_queue.samples < samples) || (spy->write_queue.samples < samples)) 04705 return NULL; 04706 04707 /* short-circuit if both head frames have exactly what we want */ 04708 if ((AST_LIST_FIRST(&spy->read_queue.list)->samples == samples) && 04709 (AST_LIST_FIRST(&spy->write_queue.list)->samples == samples)) { 04710 read_frame = AST_LIST_REMOVE_HEAD(&spy->read_queue.list, frame_list); 04711 write_frame = AST_LIST_REMOVE_HEAD(&spy->write_queue.list, frame_list); 04712 04713 spy->read_queue.samples -= samples; 04714 spy->write_queue.samples -= samples; 04715 04716 need_dup = 0; 04717 } else { 04718 copy_data_from_queue(&spy->read_queue, read_buf, samples); 04719 copy_data_from_queue(&spy->write_queue, write_buf, samples); 04720 04721 read_frame = &stack_read_frame; 04722 write_frame = &stack_write_frame; 04723 need_dup = 1; 04724 } 04725 04726 if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST)) 04727 ast_frame_adjust_volume(read_frame, spy->read_vol_adjustment); 04728 04729 if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST)) 04730 ast_frame_adjust_volume(write_frame, spy->write_vol_adjustment); 04731 04732 if (ast_test_flag(spy, CHANSPY_MIXAUDIO)) { 04733 ast_frame_slinear_sum(read_frame, write_frame); 04734 04735 if (need_dup) 04736 result = ast_frdup(read_frame); 04737 else { 04738 result = read_frame; 04739 ast_frfree(write_frame); 04740 } 04741 } else { 04742 if (need_dup) { 04743 result = ast_frdup(read_frame); 04744 AST_LIST_NEXT(result, frame_list) = ast_frdup(write_frame); 04745 } else { 04746 result = read_frame; 04747 AST_LIST_NEXT(result, frame_list) = write_frame; 04748 } 04749 } 04750 04751 return result; 04752 }
void ast_channel_spy_remove | ( | struct ast_channel * | chan, | |
struct ast_channel_spy * | spy | |||
) |
Remove a spy from a channel.
chan | The channel to remove the spy from | |
spy | The spy to be removed |
Definition at line 1489 of file channel.c.
References AST_LIST_REMOVE, ast_channel::spies, spy_cleanup(), and spy_detach().
Referenced by channel_spy().
01490 { 01491 if (!chan->spies) 01492 return; 01493 01494 AST_LIST_REMOVE(&chan->spies->list, spy, list); 01495 spy_detach(spy, chan); 01496 spy_cleanup(chan); 01497 }
void ast_channel_spy_stop_by_type | ( | struct ast_channel * | chan, | |
const char * | type | |||
) |
Find all spies of a particular type on a channel and stop them.
chan | The channel to operate on | |
type | A character string identifying the type of spies to be stopped |
Definition at line 1460 of file channel.c.
References AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_channel_spy::chan, CHANSPY_RUNNING, ast_channel::spies, spy_cleanup(), spy_detach(), ast_channel_spy::status, and ast_channel_spy::type.
Referenced by mixmonitor_cli(), and stop_mixmonitor_exec().
01461 { 01462 struct ast_channel_spy *spy = NULL; 01463 01464 if (!chan->spies) 01465 return; 01466 01467 AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->spies->list, spy, list) { 01468 if ((spy->type == type) && (spy->status == CHANSPY_RUNNING)) { 01469 AST_LIST_REMOVE_CURRENT(&chan->spies->list, list); 01470 spy_detach(spy, chan); 01471 } 01472 } 01473 AST_LIST_TRAVERSE_SAFE_END 01474 spy_cleanup(chan); 01475 }
void ast_channel_spy_trigger_wait | ( | struct ast_channel_spy * | spy | ) |
Efficiently wait until audio is available for a spy, or an exception occurs.
spy | The spy to wait on |
Definition at line 1477 of file channel.c.
References ast_cond_timedwait(), ast_tvadd(), ast_channel_spy::lock, and ast_channel_spy::trigger.
Referenced by mixmonitor_thread().
01478 { 01479 struct timeval tv; 01480 struct timespec ts; 01481 01482 tv = ast_tvadd(ast_tvnow(), ast_samp2tv(50000, 1000)); 01483 ts.tv_sec = tv.tv_sec; 01484 ts.tv_nsec = tv.tv_usec * 1000; 01485 01486 ast_cond_timedwait(&spy->trigger, &spy->lock, &ts); 01487 }