#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 }
|
1.3.9.1