Mon Mar 20 08:25:57 2006

Asterisk developer's documentation


Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

chanspy.h File Reference

Asterisk PBX channel spy definitions. More...

#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_frameast_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.


Detailed Description

Asterisk PBX channel spy definitions.

Definition in file chanspy.h.


Enumeration Type Documentation

enum chanspy_flags
 

Enumeration values:
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
 

Enumeration values:
CHANSPY_NEW  spy not yet operating
CHANSPY_RUNNING  normal operation, spy is still operating
CHANSPY_DONE  spy is stopped and already removed from channel
CHANSPY_STOP  spy requested to stop, still attached to channel

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 };


Function Documentation

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.

Parameters:
chan The channel to add the spy to.
spy A pointer to ast_channel_spy structure describing how the spy is to be used.
Returns:
0 for success, non-zero for failure
Note: This function performs no locking; you must hold the channel's lock before calling this function.

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 }

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.

Parameters:
spy The spy to operate on
samples The number of audio samples to read
Returns:
NULL for failure, one ast_frame pointer, or a chain of ast_frame pointers
This function can return multiple frames if the spy structure needs to be 'flushed' due to mismatched queue lengths, or if the spy structure is configured to return unmixed audio (in which case each call to this function will return a frame of audio from each side of channel).

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 }

void ast_channel_spy_remove struct ast_channel chan,
struct ast_channel_spy spy
 

Remove a spy from a channel.

Parameters:
chan The channel to remove the spy from
spy The spy to be removed
Returns:
nothing
Note: This function performs no locking; you must hold the channel's lock before calling this function.

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 }

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.

Parameters:
chan The channel to operate on
type A character string identifying the type of spies to be stopped
Returns:
nothing
Note: This function performs no locking; you must hold the channel's lock before calling this function.

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 }

void ast_channel_spy_trigger_wait struct ast_channel_spy spy  ) 
 

Efficiently wait until audio is available for a spy, or an exception occurs.

Parameters:
spy The spy to wait on
Returns:
nothing
Note: The locking rules for this function are non-obvious... first, you must not hold the channel's lock when calling this function. Second, you must hold the spy's lock before making the function call; while the function runs the lock will be released, and when the trigger event occurs, the lock will be re-obtained. This means that when control returns to your code, you will again hold the spy's lock.

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 }


Generated on Mon Mar 20 08:25:57 2006 for Asterisk - the Open Source PBX by  doxygen 1.3.9.1