#include "asterisk/linkedlists.h"
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. | |
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_getformatname(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_HEAD, AST_LIST_INSERT_TAIL, ast_log(), ast_set_flag, ast_test_flag, calloc, CHANSPY_FORMAT_AUDIO, CHANSPY_MIXAUDIO, CHANSPY_READ_VOLADJUST, CHANSPY_TRIGGER_MODE, CHANSPY_TRIGGER_READ, CHANSPY_TRIGGER_WRITE, CHANSPY_WRITE_VOLADJUST, ast_channel_spy_queue::format, 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 if (!ast_test_flag(spy, CHANSPY_FORMAT_AUDIO)) { 00968 ast_log(LOG_WARNING, "Could not add channel spy '%s' to channel '%s', only audio format spies are supported.\n", 00969 spy->type, chan->name); 00970 return -1; 00971 } 00972 00973 if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST) && (spy->read_queue.format != AST_FORMAT_SLINEAR)) { 00974 ast_log(LOG_WARNING, "Cannot provide volume adjustment on '%s' format spies\n", 00975 ast_getformatname(spy->read_queue.format)); 00976 return -1; 00977 } 00978 00979 if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST) && (spy->write_queue.format != AST_FORMAT_SLINEAR)) { 00980 ast_log(LOG_WARNING, "Cannot provide volume adjustment on '%s' format spies\n", 00981 ast_getformatname(spy->write_queue.format)); 00982 return -1; 00983 } 00984 00985 if (ast_test_flag(spy, CHANSPY_MIXAUDIO) && 00986 ((spy->read_queue.format != AST_FORMAT_SLINEAR) || 00987 (spy->write_queue.format != AST_FORMAT_SLINEAR))) { 00988 ast_log(LOG_WARNING, "Cannot provide audio mixing on '%s'-'%s' format spies\n", 00989 ast_getformatname(spy->read_queue.format), ast_getformatname(spy->write_queue.format)); 00990 return -1; 00991 } 00992 00993 if (!chan->spies) { 00994 if (!(chan->spies = calloc(1, sizeof(*chan->spies)))) { 00995 ast_log(LOG_WARNING, "Memory allocation failure\n"); 00996 return -1; 00997 } 00998 00999 AST_LIST_HEAD_INIT_NOLOCK(&chan->spies->list); 01000 AST_LIST_INSERT_HEAD(&chan->spies->list, spy, list); 01001 } else { 01002 AST_LIST_INSERT_TAIL(&chan->spies->list, spy, list); 01003 } 01004 01005 if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE) { 01006 ast_cond_init(&spy->trigger, NULL); 01007 ast_set_flag(spy, CHANSPY_TRIGGER_READ); 01008 ast_clear_flag(spy, CHANSPY_TRIGGER_WRITE); 01009 } 01010 01011 ast_log(LOG_DEBUG, "Spy %s added to channel %s\n", 01012 spy->type, chan->name); 01013 01014 return 0; 01015 }
|
|
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 3862 of file channel.c. References ast_clear_flag, ast_codec_get_len(), ast_frame_adjust_volume(), ast_frame_slinear_sum(), 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_frame::subclass, ast_channel_spy::write_queue, and ast_channel_spy::write_vol_adjustment. Referenced by mixmonitor_thread(), and spy_generate(). 03863 { 03864 struct ast_frame *result; 03865 /* buffers are allocated to hold SLINEAR, which is the largest format */ 03866 short read_buf[samples]; 03867 short write_buf[samples]; 03868 struct ast_frame *read_frame; 03869 struct ast_frame *write_frame; 03870 int need_dup; 03871 struct ast_frame stack_read_frame = { .frametype = AST_FRAME_VOICE, 03872 .subclass = spy->read_queue.format, 03873 .data = read_buf, 03874 .samples = samples, 03875 .datalen = ast_codec_get_len(spy->read_queue.format, samples), 03876 }; 03877 struct ast_frame stack_write_frame = { .frametype = AST_FRAME_VOICE, 03878 .subclass = spy->write_queue.format, 03879 .data = write_buf, 03880 .samples = samples, 03881 .datalen = ast_codec_get_len(spy->write_queue.format, samples), 03882 }; 03883 03884 /* if a flush has been requested, dump everything in whichever queue is larger */ 03885 if (ast_test_flag(spy, CHANSPY_TRIGGER_FLUSH)) { 03886 if (spy->read_queue.samples > spy->write_queue.samples) { 03887 if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST)) { 03888 for (result = spy->read_queue.head; result; result = result->next) 03889 ast_frame_adjust_volume(result, spy->read_vol_adjustment); 03890 } 03891 result = spy->read_queue.head; 03892 spy->read_queue.head = NULL; 03893 spy->read_queue.samples = 0; 03894 ast_clear_flag(spy, CHANSPY_TRIGGER_FLUSH); 03895 return result; 03896 } else { 03897 if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST)) { 03898 for (result = spy->write_queue.head; result; result = result->next) 03899 ast_frame_adjust_volume(result, spy->write_vol_adjustment); 03900 } 03901 result = spy->write_queue.head; 03902 spy->write_queue.head = NULL; 03903 spy->write_queue.samples = 0; 03904 ast_clear_flag(spy, CHANSPY_TRIGGER_FLUSH); 03905 return result; 03906 } 03907 } 03908 03909 if ((spy->read_queue.samples < samples) || (spy->write_queue.samples < samples)) 03910 return NULL; 03911 03912 /* short-circuit if both head frames have exactly what we want */ 03913 if ((spy->read_queue.head->samples == samples) && 03914 (spy->write_queue.head->samples == samples)) { 03915 read_frame = spy->read_queue.head; 03916 spy->read_queue.head = read_frame->next; 03917 read_frame->next = NULL; 03918 03919 write_frame = spy->write_queue.head; 03920 spy->write_queue.head = write_frame->next; 03921 write_frame->next = NULL; 03922 03923 spy->read_queue.samples -= samples; 03924 spy->write_queue.samples -= samples; 03925 03926 need_dup = 0; 03927 } else { 03928 copy_data_from_queue(&spy->read_queue, read_buf, samples); 03929 copy_data_from_queue(&spy->write_queue, write_buf, samples); 03930 03931 read_frame = &stack_read_frame; 03932 write_frame = &stack_write_frame; 03933 need_dup = 1; 03934 } 03935 03936 if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST)) 03937 ast_frame_adjust_volume(read_frame, spy->read_vol_adjustment); 03938 03939 if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST)) 03940 ast_frame_adjust_volume(write_frame, spy->write_vol_adjustment); 03941 03942 if (ast_test_flag(spy, CHANSPY_MIXAUDIO)) { 03943 ast_frame_slinear_sum(read_frame, write_frame); 03944 03945 if (need_dup) 03946 result = ast_frdup(read_frame); 03947 else { 03948 result = read_frame; 03949 ast_frfree(write_frame); 03950 } 03951 } else { 03952 if (need_dup) { 03953 result = ast_frdup(read_frame); 03954 result->next = ast_frdup(write_frame); 03955 } else { 03956 result = read_frame; 03957 result->next = write_frame; 03958 } 03959 } 03960 03961 return result; 03962 }
|
|
Remove a spy from a channel.
Definition at line 1040 of file channel.c. References ast_cond_destroy(), ast_frfree(), AST_LIST_EMPTY, AST_LIST_REMOVE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_test_flag, ast_translator_free_path(), CHANSPY_TRIGGER_MODE, free, ast_channel_spy_queue::head, ast_channel_spy::lock, LOG_DEBUG, ast_channel::name, ast_frame::next, channel_spy_trans::path, ast_channel_spy::read_queue, ast_channel_spy_list::read_translator, ast_channel::spies, ast_channel_spy::trigger, ast_channel_spy::type, ast_channel_spy::write_queue, and ast_channel_spy_list::write_translator. Referenced by detach_spies(), stop_spying(), and stopmon(). 01041 { 01042 struct ast_frame *f; 01043 01044 if (!chan->spies) 01045 return; 01046 01047 AST_LIST_REMOVE(&chan->spies->list, spy, list); 01048 01049 ast_mutex_lock(&spy->lock); 01050 01051 for (f = spy->read_queue.head; f; f = spy->read_queue.head) { 01052 spy->read_queue.head = f->next; 01053 ast_frfree(f); 01054 } 01055 for (f = spy->write_queue.head; f; f = spy->write_queue.head) { 01056 spy->write_queue.head = f->next; 01057 ast_frfree(f); 01058 } 01059 01060 if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE) 01061 ast_cond_destroy(&spy->trigger); 01062 01063 ast_mutex_unlock(&spy->lock); 01064 01065 ast_log(LOG_DEBUG, "Spy %s removed from channel %s\n", 01066 spy->type, chan->name); 01067 01068 if (AST_LIST_EMPTY(&chan->spies->list)) { 01069 if (chan->spies->read_translator.path) 01070 ast_translator_free_path(chan->spies->read_translator.path); 01071 if (chan->spies->write_translator.path) 01072 ast_translator_free_path(chan->spies->write_translator.path); 01073 free(chan->spies); 01074 chan->spies = NULL; 01075 } 01076 }
|
|
Find all spies of a particular type on a channel and stop them.
Definition at line 1017 of file channel.c. References ast_cond_signal(), AST_LIST_TRAVERSE, ast_mutex_lock(), ast_mutex_unlock(), ast_test_flag, CHANSPY_TRIGGER_MODE, ast_channel_spy::lock, ast_channel::spies, ast_channel_spy::trigger, and ast_channel_spy::type. Referenced by mixmonitor_cli(). 01018 { 01019 struct ast_channel_spy *spy; 01020 01021 if (!chan->spies) 01022 return; 01023 01024 AST_LIST_TRAVERSE(&chan->spies->list, spy, list) { 01025 ast_mutex_lock(&spy->lock); 01026 if ((spy->type == type) && (spy->status == CHANSPY_RUNNING)) { 01027 spy->status = CHANSPY_STOP; 01028 if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE) 01029 ast_cond_signal(&spy->trigger); 01030 } 01031 ast_mutex_unlock(&spy->lock); 01032 } 01033 }
|
|
Efficiently wait until audio is available for a spy, or an exception occurs.
Definition at line 1035 of file channel.c. References ast_cond_wait(), ast_channel_spy::lock, and ast_channel_spy::trigger. Referenced by mixmonitor_thread(). 01036 { 01037 ast_cond_wait(&spy->trigger, &spy->lock); 01038 }
|