#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.
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. | |
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.
|
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 };
|
|
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 };
|
|
Adds a spy to a channel, to begin receiving copies of the channel's audio frames.
Definition at line 965 of file channel.c. References 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, calloc, 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, list, LOG_DEBUG, LOG_WARNING, ast_channel::name, 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(). 00966 { 00967 /* Link the owner channel to the spy */ 00968 spy->chan = chan; 00969 00970 if (!ast_test_flag(spy, CHANSPY_FORMAT_AUDIO)) { 00971 ast_log(LOG_WARNING, "Could not add channel spy '%s' to channel '%s', only audio format spies are supported.\n", 00972 spy->type, chan->name); 00973 return -1; 00974 } 00975 00976 if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST) && (spy->read_queue.format != AST_FORMAT_SLINEAR)) { 00977 ast_log(LOG_WARNING, "Cannot provide volume adjustment on '%s' format spies\n", 00978 ast_getformatname(spy->read_queue.format)); 00979 return -1; 00980 } 00981 00982 if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST) && (spy->write_queue.format != AST_FORMAT_SLINEAR)) { 00983 ast_log(LOG_WARNING, "Cannot provide volume adjustment on '%s' format spies\n", 00984 ast_getformatname(spy->write_queue.format)); 00985 return -1; 00986 } 00987 00988 if (ast_test_flag(spy, CHANSPY_MIXAUDIO) && 00989 ((spy->read_queue.format != AST_FORMAT_SLINEAR) || 00990 (spy->write_queue.format != AST_FORMAT_SLINEAR))) { 00991 ast_log(LOG_WARNING, "Cannot provide audio mixing on '%s'-'%s' format spies\n", 00992 ast_getformatname(spy->read_queue.format), ast_getformatname(spy->write_queue.format)); 00993 return -1; 00994 } 00995 00996 if (!chan->spies) { 00997 if (!(chan->spies = calloc(1, sizeof(*chan->spies)))) { 00998 ast_log(LOG_WARNING, "Memory allocation failure\n"); 00999 return -1; 01000 } 01001 01002 AST_LIST_HEAD_INIT_NOLOCK(&chan->spies->list); 01003 AST_LIST_INSERT_HEAD(&chan->spies->list, spy, list); 01004 } else { 01005 AST_LIST_INSERT_TAIL(&chan->spies->list, spy, list); 01006 } 01007 01008 if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE) { 01009 ast_cond_init(&spy->trigger, NULL); 01010 ast_set_flag(spy, CHANSPY_TRIGGER_READ); 01011 ast_clear_flag(spy, CHANSPY_TRIGGER_WRITE); 01012 } 01013 01014 ast_log(LOG_DEBUG, "Spy %s added to channel %s\n", 01015 spy->type, chan->name); 01016 01017 return 0; 01018 }
|
|
Read one (or more) frames of audio from a channel being spied upon.
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 3899 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_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_queue::head, ast_frame::next, ast_channel_spy::read_queue, ast_channel_spy::read_vol_adjustment, result, ast_frame::samples, ast_channel_spy_queue::samples, ast_channel_spy::write_queue, and ast_channel_spy::write_vol_adjustment. Referenced by mixmonitor_thread(), and spy_generate(). 03900 { 03901 struct ast_frame *result; 03902 /* buffers are allocated to hold SLINEAR, which is the largest format */ 03903 short read_buf[samples]; 03904 short write_buf[samples]; 03905 struct ast_frame *read_frame; 03906 struct ast_frame *write_frame; 03907 int need_dup; 03908 struct ast_frame stack_read_frame = { .frametype = AST_FRAME_VOICE, 03909 .subclass = spy->read_queue.format, 03910 .data = read_buf, 03911 .samples = samples, 03912 .datalen = ast_codec_get_len(spy->read_queue.format, samples), 03913 }; 03914 struct ast_frame stack_write_frame = { .frametype = AST_FRAME_VOICE, 03915 .subclass = spy->write_queue.format, 03916 .data = write_buf, 03917 .samples = samples, 03918 .datalen = ast_codec_get_len(spy->write_queue.format, samples), 03919 }; 03920 03921 /* if a flush has been requested, dump everything in whichever queue is larger */ 03922 if (ast_test_flag(spy, CHANSPY_TRIGGER_FLUSH)) { 03923 if (spy->read_queue.samples > spy->write_queue.samples) { 03924 if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST)) { 03925 for (result = spy->read_queue.head; result; result = result->next) 03926 ast_frame_adjust_volume(result, spy->read_vol_adjustment); 03927 } 03928 result = spy->read_queue.head; 03929 spy->read_queue.head = NULL; 03930 spy->read_queue.samples = 0; 03931 ast_clear_flag(spy, CHANSPY_TRIGGER_FLUSH); 03932 return result; 03933 } else { 03934 if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST)) { 03935 for (result = spy->write_queue.head; result; result = result->next) 03936 ast_frame_adjust_volume(result, spy->write_vol_adjustment); 03937 } 03938 result = spy->write_queue.head; 03939 spy->write_queue.head = NULL; 03940 spy->write_queue.samples = 0; 03941 ast_clear_flag(spy, CHANSPY_TRIGGER_FLUSH); 03942 return result; 03943 } 03944 } 03945 03946 if ((spy->read_queue.samples < samples) || (spy->write_queue.samples < samples)) 03947 return NULL; 03948 03949 /* short-circuit if both head frames have exactly what we want */ 03950 if ((spy->read_queue.head->samples == samples) && 03951 (spy->write_queue.head->samples == samples)) { 03952 read_frame = spy->read_queue.head; 03953 spy->read_queue.head = read_frame->next; 03954 read_frame->next = NULL; 03955 03956 write_frame = spy->write_queue.head; 03957 spy->write_queue.head = write_frame->next; 03958 write_frame->next = NULL; 03959 03960 spy->read_queue.samples -= samples; 03961 spy->write_queue.samples -= samples; 03962 03963 need_dup = 0; 03964 } else { 03965 copy_data_from_queue(&spy->read_queue, read_buf, samples); 03966 copy_data_from_queue(&spy->write_queue, write_buf, samples); 03967 03968 read_frame = &stack_read_frame; 03969 write_frame = &stack_write_frame; 03970 need_dup = 1; 03971 } 03972 03973 if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST)) 03974 ast_frame_adjust_volume(read_frame, spy->read_vol_adjustment); 03975 03976 if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST)) 03977 ast_frame_adjust_volume(write_frame, spy->write_vol_adjustment); 03978 03979 if (ast_test_flag(spy, CHANSPY_MIXAUDIO)) { 03980 ast_frame_slinear_sum(read_frame, write_frame); 03981 03982 if (need_dup) 03983 result = ast_frdup(read_frame); 03984 else { 03985 result = read_frame; 03986 ast_frfree(write_frame); 03987 } 03988 } else { 03989 if (need_dup) { 03990 result = ast_frdup(read_frame); 03991 result->next = ast_frdup(write_frame); 03992 } else { 03993 result = read_frame; 03994 result->next = write_frame; 03995 } 03996 } 03997 03998 return result; 03999 }
|
|
|
Find all spies of a particular type on a channel and stop them.
Definition at line 1020 of file channel.c. References ast_cond_signal(), AST_LIST_TRAVERSE, ast_mutex_lock(), ast_mutex_unlock(), ast_test_flag, CHANSPY_RUNNING, CHANSPY_STOP, CHANSPY_TRIGGER_MODE, CHANSPY_TRIGGER_NONE, list, ast_channel_spy::lock, ast_channel::spies, ast_channel_spy::status, and ast_channel_spy::type. Referenced by mixmonitor_cli(). 01021 { 01022 struct ast_channel_spy *spy; 01023 01024 if (!chan->spies) 01025 return; 01026 01027 AST_LIST_TRAVERSE(&chan->spies->list, spy, list) { 01028 ast_mutex_lock(&spy->lock); 01029 if ((spy->type == type) && (spy->status == CHANSPY_RUNNING)) { 01030 spy->status = CHANSPY_STOP; 01031 if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE) 01032 ast_cond_signal(&spy->trigger); 01033 } 01034 ast_mutex_unlock(&spy->lock); 01035 } 01036 }
|
|
Efficiently wait until audio is available for a spy, or an exception occurs.
Definition at line 1038 of file channel.c. References ast_cond_timedwait(), ast_tvadd(), ast_channel_spy::lock, and ast_channel_spy::trigger. Referenced by mixmonitor_thread(). 01039 { 01040 struct timeval tv; 01041 struct timespec ts; 01042 01043 tv = ast_tvadd(ast_tvnow(), ast_samp2tv(50000, 1000)); 01044 ts.tv_sec = tv.tv_sec; 01045 ts.tv_nsec = tv.tv_usec * 1000; 01046 01047 ast_cond_timedwait(&spy->trigger, &spy->lock, &ts); 01048 }
|