Mon Sep 18 09:14:58 2006

Asterisk developer's documentation


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.
void ast_channel_spy_free (struct ast_channel_spy *spy)
 Free a spy.
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, 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 }

void ast_channel_spy_free ( struct ast_channel_spy spy  ) 

Free a spy.

Parameters:
spy The spy to free
Returns:
nothing
Note: This function MUST NOT be called with the spy locked.

Definition at line 1098 of file channel.c.

References ast_cond_destroy(), ast_frfree(), ast_mutex_destroy(), ast_test_flag, CHANSPY_DONE, CHANSPY_TRIGGER_MODE, CHANSPY_TRIGGER_NONE, ast_channel_spy_queue::head, ast_channel_spy::lock, ast_frame::next, ast_channel_spy::read_queue, ast_channel_spy::status, ast_channel_spy::trigger, and ast_channel_spy::write_queue.

Referenced by channel_spy(), and mixmonitor_thread().

01099 {
01100    struct ast_frame *f = NULL;
01101 
01102    if (spy->status == CHANSPY_DONE)
01103       return;
01104 
01105    /* Switch status to done in case we get called twice */
01106    spy->status = CHANSPY_DONE;
01107 
01108    /* Drop any frames in the queue */
01109    for (f = spy->write_queue.head; f; f = spy->write_queue.head) {
01110       spy->write_queue.head = f->next;
01111       ast_frfree(f);
01112    }
01113    for (f = spy->read_queue.head; f; f= spy->read_queue.head) {
01114       spy->read_queue.head = f->next;
01115       ast_frfree(f);
01116    }
01117 
01118    /* Destroy the condition if in use */
01119    if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE)
01120       ast_cond_destroy(&spy->trigger);
01121 
01122    /* Destroy our mutex since it is no longer in use */
01123    ast_mutex_destroy(&spy->lock);
01124 
01125    return;
01126 }

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 3975 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().

03976 {
03977    struct ast_frame *result;
03978    /* buffers are allocated to hold SLINEAR, which is the largest format */
03979         short read_buf[samples];
03980         short write_buf[samples];
03981    struct ast_frame *read_frame;
03982    struct ast_frame *write_frame;
03983    int need_dup;
03984    struct ast_frame stack_read_frame = { .frametype = AST_FRAME_VOICE,
03985                      .subclass = spy->read_queue.format,
03986                      .data = read_buf,
03987                      .samples = samples,
03988                      .datalen = ast_codec_get_len(spy->read_queue.format, samples),
03989    };
03990    struct ast_frame stack_write_frame = { .frametype = AST_FRAME_VOICE,
03991                       .subclass = spy->write_queue.format,
03992                       .data = write_buf,
03993                       .samples = samples,
03994                       .datalen = ast_codec_get_len(spy->write_queue.format, samples),
03995    };
03996 
03997    /* if a flush has been requested, dump everything in whichever queue is larger */
03998    if (ast_test_flag(spy, CHANSPY_TRIGGER_FLUSH)) {
03999       if (spy->read_queue.samples > spy->write_queue.samples) {
04000          if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST)) {
04001             for (result = spy->read_queue.head; result; result = result->next)
04002                ast_frame_adjust_volume(result, spy->read_vol_adjustment);
04003          }
04004          result = spy->read_queue.head;
04005          spy->read_queue.head = NULL;
04006          spy->read_queue.samples = 0;
04007          ast_clear_flag(spy, CHANSPY_TRIGGER_FLUSH);
04008          return result;
04009       } else {
04010          if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST)) {
04011             for (result = spy->write_queue.head; result; result = result->next)
04012                ast_frame_adjust_volume(result, spy->write_vol_adjustment);
04013          }
04014          result = spy->write_queue.head;
04015          spy->write_queue.head = NULL;
04016          spy->write_queue.samples = 0;
04017          ast_clear_flag(spy, CHANSPY_TRIGGER_FLUSH);
04018          return result;
04019       }
04020    }
04021 
04022    if ((spy->read_queue.samples < samples) || (spy->write_queue.samples < samples))
04023       return NULL;
04024 
04025    /* short-circuit if both head frames have exactly what we want */
04026    if ((spy->read_queue.head->samples == samples) &&
04027        (spy->write_queue.head->samples == samples)) {
04028       read_frame = spy->read_queue.head;
04029       spy->read_queue.head = read_frame->next;
04030       read_frame->next = NULL;
04031 
04032       write_frame = spy->write_queue.head;
04033       spy->write_queue.head = write_frame->next;
04034       write_frame->next = NULL;
04035 
04036       spy->read_queue.samples -= samples;
04037       spy->write_queue.samples -= samples;
04038 
04039       need_dup = 0;
04040    } else {
04041       copy_data_from_queue(&spy->read_queue, read_buf, samples);
04042       copy_data_from_queue(&spy->write_queue, write_buf, samples);
04043 
04044       read_frame = &stack_read_frame;
04045       write_frame = &stack_write_frame;
04046       need_dup = 1;
04047    }
04048    
04049    if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST))
04050       ast_frame_adjust_volume(read_frame, spy->read_vol_adjustment);
04051 
04052    if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST))
04053       ast_frame_adjust_volume(write_frame, spy->write_vol_adjustment);
04054 
04055    if (ast_test_flag(spy, CHANSPY_MIXAUDIO)) {
04056       ast_frame_slinear_sum(read_frame, write_frame);
04057 
04058       if (need_dup)
04059          result = ast_frdup(read_frame);
04060       else {
04061          result = read_frame;
04062          ast_frfree(write_frame);
04063       }
04064    } else {
04065       if (need_dup) {
04066          result = ast_frdup(read_frame);
04067          result->next = ast_frdup(write_frame);
04068       } else {
04069          result = read_frame;
04070          result->next = write_frame;
04071       }
04072    }
04073 
04074    return result;
04075 }

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 1087 of file channel.c.

References AST_LIST_REMOVE, list, ast_channel::spies, spy_cleanup(), and spy_detach().

Referenced by channel_spy().

01088 {
01089    if (!chan->spies)
01090       return;
01091 
01092    AST_LIST_REMOVE(&chan->spies->list, spy, list);
01093 
01094    spy_detach(spy, chan);
01095    spy_cleanup(chan);
01096 }

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 1055 of file channel.c.

References AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_mutex_lock(), ast_mutex_unlock(), ast_channel_spy::chan, CHANSPY_RUNNING, list, ast_channel_spy::lock, ast_channel::spies, spy_cleanup(), spy_detach(), ast_channel_spy::status, and ast_channel_spy::type.

Referenced by mixmonitor_cli().

01056 {
01057    struct ast_channel_spy *spy = NULL;
01058    
01059    if (!chan->spies)
01060       return;
01061 
01062    AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->spies->list, spy, list) {
01063       ast_mutex_lock(&spy->lock);
01064       if ((spy->type == type) && (spy->status == CHANSPY_RUNNING)) {
01065          ast_mutex_unlock(&spy->lock);
01066          AST_LIST_REMOVE_CURRENT(&chan->spies->list, list);
01067          spy_detach(spy, chan);
01068       } else
01069          ast_mutex_unlock(&spy->lock);
01070    }
01071    AST_LIST_TRAVERSE_SAFE_END
01072    spy_cleanup(chan);
01073 }

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 1075 of file channel.c.

References ast_cond_timedwait(), ast_tvadd(), ast_channel_spy::lock, and ast_channel_spy::trigger.

Referenced by mixmonitor_thread().

01076 {
01077    struct timeval tv;
01078    struct timespec ts;
01079 
01080    tv = ast_tvadd(ast_tvnow(), ast_samp2tv(50000, 1000));
01081    ts.tv_sec = tv.tv_sec;
01082    ts.tv_nsec = tv.tv_usec * 1000;
01083 
01084    ast_cond_timedwait(&spy->trigger, &spy->lock, &ts);
01085 }


Generated on Mon Sep 18 09:14:58 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.7