Sat Mar 24 23:27:38 2007

Asterisk developer's documentation


chanspy.h File Reference

Asterisk PBX channel spy definitions. More...

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

Enumerator:
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
 

Enumerator:
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_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, 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_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 3855 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().

03856 {
03857    struct ast_frame *result;
03858    /* buffers are allocated to hold SLINEAR, which is the largest format */
03859         short read_buf[samples];
03860         short write_buf[samples];
03861    struct ast_frame *read_frame;
03862    struct ast_frame *write_frame;
03863    int need_dup;
03864    struct ast_frame stack_read_frame = { .frametype = AST_FRAME_VOICE,
03865                      .subclass = spy->read_queue.format,
03866                      .data = read_buf,
03867                      .samples = samples,
03868                      .datalen = ast_codec_get_len(spy->read_queue.format, samples),
03869    };
03870    struct ast_frame stack_write_frame = { .frametype = AST_FRAME_VOICE,
03871                       .subclass = spy->write_queue.format,
03872                       .data = write_buf,
03873                       .samples = samples,
03874                       .datalen = ast_codec_get_len(spy->write_queue.format, samples),
03875    };
03876 
03877    /* if a flush has been requested, dump everything in whichever queue is larger */
03878    if (ast_test_flag(spy, CHANSPY_TRIGGER_FLUSH)) {
03879       if (spy->read_queue.samples > spy->write_queue.samples) {
03880          if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST)) {
03881             for (result = spy->read_queue.head; result; result = result->next)
03882                ast_frame_adjust_volume(result, spy->read_vol_adjustment);
03883          }
03884          result = spy->read_queue.head;
03885          spy->read_queue.head = NULL;
03886          spy->read_queue.samples = 0;
03887          ast_clear_flag(spy, CHANSPY_TRIGGER_FLUSH);
03888          return result;
03889       } else {
03890          if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST)) {
03891             for (result = spy->write_queue.head; result; result = result->next)
03892                ast_frame_adjust_volume(result, spy->write_vol_adjustment);
03893          }
03894          result = spy->write_queue.head;
03895          spy->write_queue.head = NULL;
03896          spy->write_queue.samples = 0;
03897          ast_clear_flag(spy, CHANSPY_TRIGGER_FLUSH);
03898          return result;
03899       }
03900    }
03901 
03902    if ((spy->read_queue.samples < samples) || (spy->write_queue.samples < samples))
03903       return NULL;
03904 
03905    /* short-circuit if both head frames have exactly what we want */
03906    if ((spy->read_queue.head->samples == samples) &&
03907        (spy->write_queue.head->samples == samples)) {
03908       read_frame = spy->read_queue.head;
03909       spy->read_queue.head = read_frame->next;
03910       read_frame->next = NULL;
03911 
03912       write_frame = spy->write_queue.head;
03913       spy->write_queue.head = write_frame->next;
03914       write_frame->next = NULL;
03915 
03916       spy->read_queue.samples -= samples;
03917       spy->write_queue.samples -= samples;
03918 
03919       need_dup = 0;
03920    } else {
03921       copy_data_from_queue(&spy->read_queue, read_buf, samples);
03922       copy_data_from_queue(&spy->write_queue, write_buf, samples);
03923 
03924       read_frame = &stack_read_frame;
03925       write_frame = &stack_write_frame;
03926       need_dup = 1;
03927    }
03928    
03929    if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST))
03930       ast_frame_adjust_volume(read_frame, spy->read_vol_adjustment);
03931 
03932    if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST))
03933       ast_frame_adjust_volume(write_frame, spy->write_vol_adjustment);
03934 
03935    if (ast_test_flag(spy, CHANSPY_MIXAUDIO)) {
03936       ast_frame_slinear_sum(read_frame, write_frame);
03937 
03938       if (need_dup)
03939          result = ast_frdup(read_frame);
03940       else {
03941          result = read_frame;
03942          ast_frfree(write_frame);
03943       }
03944    } else {
03945       if (need_dup) {
03946          result = ast_frdup(read_frame);
03947          result->next = ast_frdup(write_frame);
03948       } else {
03949          result = read_frame;
03950          result->next = write_frame;
03951       }
03952    }
03953 
03954    return result;
03955 }

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, CHANSPY_TRIGGER_NONE, free, ast_channel_spy_queue::head, list, ast_channel_spy::lock, 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_RUNNING, CHANSPY_STOP, CHANSPY_TRIGGER_MODE, CHANSPY_TRIGGER_NONE, list, ast_channel_spy::lock, ast_channel::spies, ast_channel_spy::status, 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 Sat Mar 24 23:27:38 2007 for Asterisk - the Open Source PBX by  doxygen 1.4.6