Sun Aug 6 15:07:23 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"

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

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

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 1050 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(), ast_channel_spy::chan, CHANSPY_TRIGGER_MODE, CHANSPY_TRIGGER_NONE, free, ast_channel_spy_queue::head, list, 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().

01051 {
01052    struct ast_frame *f;
01053 
01054    if (!chan->spies)
01055       return;
01056 
01057    AST_LIST_REMOVE(&chan->spies->list, spy, list);
01058 
01059    ast_mutex_lock(&spy->lock);
01060 
01061    spy->chan = NULL;
01062 
01063    for (f = spy->read_queue.head; f; f = spy->read_queue.head) {
01064       spy->read_queue.head = f->next;
01065       ast_frfree(f);
01066    }
01067    for (f = spy->write_queue.head; f; f = spy->write_queue.head) {
01068       spy->write_queue.head = f->next;
01069       ast_frfree(f);
01070    }
01071 
01072    if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE)
01073       ast_cond_destroy(&spy->trigger);
01074 
01075    ast_mutex_unlock(&spy->lock);
01076 
01077    ast_log(LOG_DEBUG, "Spy %s removed from channel %s\n",
01078       spy->type, chan->name);
01079 
01080    if (AST_LIST_EMPTY(&chan->spies->list)) {
01081       if (chan->spies->read_translator.path)
01082          ast_translator_free_path(chan->spies->read_translator.path);
01083       if (chan->spies->write_translator.path)
01084          ast_translator_free_path(chan->spies->write_translator.path);
01085       free(chan->spies);
01086       chan->spies = NULL;
01087    }
01088 }

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

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


Generated on Sun Aug 6 15:07:24 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.2