Mon Apr 30 07:40:28 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.
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 1330 of file channel.c.

References ast_calloc, 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, 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, LOG_DEBUG, LOG_WARNING, option_debug, 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().

01331 {
01332    /* Link the owner channel to the spy */
01333    spy->chan = chan;
01334 
01335    if (!ast_test_flag(spy, CHANSPY_FORMAT_AUDIO)) {
01336       ast_log(LOG_WARNING, "Could not add channel spy '%s' to channel '%s', only audio format spies are supported.\n",
01337          spy->type, chan->name);
01338       return -1;
01339    }
01340 
01341    if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST) && (spy->read_queue.format != AST_FORMAT_SLINEAR)) {
01342       ast_log(LOG_WARNING, "Cannot provide volume adjustment on '%s' format spies\n",
01343          ast_getformatname(spy->read_queue.format));
01344       return -1;
01345    }
01346 
01347    if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST) && (spy->write_queue.format != AST_FORMAT_SLINEAR)) {
01348       ast_log(LOG_WARNING, "Cannot provide volume adjustment on '%s' format spies\n",
01349          ast_getformatname(spy->write_queue.format));
01350       return -1;
01351    }
01352 
01353    if (ast_test_flag(spy, CHANSPY_MIXAUDIO) &&
01354        ((spy->read_queue.format != AST_FORMAT_SLINEAR) ||
01355         (spy->write_queue.format != AST_FORMAT_SLINEAR))) {
01356       ast_log(LOG_WARNING, "Cannot provide audio mixing on '%s'-'%s' format spies\n",
01357          ast_getformatname(spy->read_queue.format), ast_getformatname(spy->write_queue.format));
01358       return -1;
01359    }
01360 
01361    if (!chan->spies) {
01362       if (!(chan->spies = ast_calloc(1, sizeof(*chan->spies)))) {
01363          return -1;
01364       }
01365 
01366       AST_LIST_HEAD_INIT_NOLOCK(&chan->spies->list);
01367       AST_LIST_INSERT_HEAD(&chan->spies->list, spy, list);
01368    } else {
01369       AST_LIST_INSERT_TAIL(&chan->spies->list, spy, list);
01370    }
01371 
01372    if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE) {
01373       ast_cond_init(&spy->trigger, NULL);
01374       ast_set_flag(spy, CHANSPY_TRIGGER_READ);
01375       ast_clear_flag(spy, CHANSPY_TRIGGER_WRITE);
01376    }
01377 
01378    if (option_debug)
01379       ast_log(LOG_DEBUG, "Spy %s added to channel %s\n",
01380          spy->type, chan->name);
01381 
01382    return 0;
01383 }

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

References ast_cond_destroy(), ast_frfree(), AST_LIST_REMOVE_HEAD, ast_mutex_destroy(), ast_test_flag, CHANSPY_DONE, CHANSPY_TRIGGER_MODE, CHANSPY_TRIGGER_NONE, f, ast_channel_spy::lock, 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().

01466 {
01467    struct ast_frame *f = NULL;
01468 
01469    if (spy->status == CHANSPY_DONE)
01470       return;
01471 
01472    /* Switch status to done in case we get called twice */
01473    spy->status = CHANSPY_DONE;
01474 
01475    /* Drop any frames in the queue */
01476    while ((f = AST_LIST_REMOVE_HEAD(&spy->write_queue.list, frame_list)))
01477       ast_frfree(f);
01478    while ((f = AST_LIST_REMOVE_HEAD(&spy->read_queue.list, frame_list)))
01479       ast_frfree(f);
01480 
01481    /* Destroy the condition if in use */
01482    if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE)
01483       ast_cond_destroy(&spy->trigger);
01484 
01485    /* Destroy our mutex since it is no longer in use */
01486    ast_mutex_destroy(&spy->lock);
01487 
01488    return;
01489 }

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 4506 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_LIST_FIRST, AST_LIST_HEAD_SET_NOLOCK, AST_LIST_NEXT, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, 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::read_queue, ast_channel_spy::read_vol_adjustment, result, ast_channel_spy_queue::samples, ast_channel_spy::write_queue, and ast_channel_spy::write_vol_adjustment.

Referenced by mixmonitor_thread(), and spy_generate().

04507 {
04508    struct ast_frame *result;
04509    /* buffers are allocated to hold SLINEAR, which is the largest format */
04510         short read_buf[samples];
04511         short write_buf[samples];
04512    struct ast_frame *read_frame;
04513    struct ast_frame *write_frame;
04514    int need_dup;
04515    struct ast_frame stack_read_frame = { .frametype = AST_FRAME_VOICE,
04516                      .subclass = spy->read_queue.format,
04517                      .data = read_buf,
04518                      .samples = samples,
04519                      .datalen = ast_codec_get_len(spy->read_queue.format, samples),
04520    };
04521    struct ast_frame stack_write_frame = { .frametype = AST_FRAME_VOICE,
04522                       .subclass = spy->write_queue.format,
04523                       .data = write_buf,
04524                       .samples = samples,
04525                       .datalen = ast_codec_get_len(spy->write_queue.format, samples),
04526    };
04527 
04528    /* if a flush has been requested, dump everything in whichever queue is larger */
04529    if (ast_test_flag(spy, CHANSPY_TRIGGER_FLUSH)) {
04530       if (spy->read_queue.samples > spy->write_queue.samples) {
04531          if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST)) {
04532             AST_LIST_TRAVERSE(&spy->read_queue.list, result, frame_list)
04533                ast_frame_adjust_volume(result, spy->read_vol_adjustment);
04534          }
04535          result = AST_LIST_FIRST(&spy->read_queue.list);
04536          AST_LIST_HEAD_SET_NOLOCK(&spy->read_queue.list, NULL);
04537          spy->read_queue.samples = 0;
04538       } else {
04539          if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST)) {
04540             AST_LIST_TRAVERSE(&spy->write_queue.list, result, frame_list)
04541                ast_frame_adjust_volume(result, spy->write_vol_adjustment);
04542          }
04543          result = AST_LIST_FIRST(&spy->write_queue.list);
04544          AST_LIST_HEAD_SET_NOLOCK(&spy->write_queue.list, NULL);
04545          spy->write_queue.samples = 0;
04546       }
04547       ast_clear_flag(spy, CHANSPY_TRIGGER_FLUSH);
04548       return result;
04549    }
04550 
04551    if ((spy->read_queue.samples < samples) || (spy->write_queue.samples < samples))
04552       return NULL;
04553 
04554    /* short-circuit if both head frames have exactly what we want */
04555    if ((AST_LIST_FIRST(&spy->read_queue.list)->samples == samples) &&
04556        (AST_LIST_FIRST(&spy->write_queue.list)->samples == samples)) {
04557       read_frame = AST_LIST_REMOVE_HEAD(&spy->read_queue.list, frame_list);
04558       write_frame = AST_LIST_REMOVE_HEAD(&spy->write_queue.list, frame_list);
04559 
04560       spy->read_queue.samples -= samples;
04561       spy->write_queue.samples -= samples;
04562 
04563       need_dup = 0;
04564    } else {
04565       copy_data_from_queue(&spy->read_queue, read_buf, samples);
04566       copy_data_from_queue(&spy->write_queue, write_buf, samples);
04567 
04568       read_frame = &stack_read_frame;
04569       write_frame = &stack_write_frame;
04570       need_dup = 1;
04571    }
04572    
04573    if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST))
04574       ast_frame_adjust_volume(read_frame, spy->read_vol_adjustment);
04575 
04576    if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST))
04577       ast_frame_adjust_volume(write_frame, spy->write_vol_adjustment);
04578 
04579    if (ast_test_flag(spy, CHANSPY_MIXAUDIO)) {
04580       ast_frame_slinear_sum(read_frame, write_frame);
04581 
04582       if (need_dup)
04583          result = ast_frdup(read_frame);
04584       else {
04585          result = read_frame;
04586          ast_frfree(write_frame);
04587       }
04588    } else {
04589       if (need_dup) {
04590          result = ast_frdup(read_frame);
04591          AST_LIST_NEXT(result, frame_list) = ast_frdup(write_frame);
04592       } else {
04593          result = read_frame;
04594          AST_LIST_NEXT(result, frame_list) = write_frame;
04595       }
04596    }
04597 
04598    return result;
04599 }

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

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

Referenced by channel_spy().

01456 {
01457    if (!chan->spies)
01458       return;
01459 
01460    AST_LIST_REMOVE(&chan->spies->list, spy, list);
01461    spy_detach(spy, chan);
01462    spy_cleanup(chan);
01463 }

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 1423 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, ast_channel_spy::lock, ast_channel::spies, spy_cleanup(), spy_detach(), ast_channel_spy::status, and ast_channel_spy::type.

Referenced by mixmonitor_cli(), and stop_mixmonitor_exec().

01424 {
01425    struct ast_channel_spy *spy = NULL;
01426    
01427    if (!chan->spies)
01428       return;
01429 
01430    AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->spies->list, spy, list) {
01431       ast_mutex_lock(&spy->lock);
01432       if ((spy->type == type) && (spy->status == CHANSPY_RUNNING)) {
01433          ast_mutex_unlock(&spy->lock);
01434          AST_LIST_REMOVE_CURRENT(&chan->spies->list, list);
01435          spy_detach(spy, chan);
01436       } else
01437          ast_mutex_unlock(&spy->lock);
01438    }
01439    AST_LIST_TRAVERSE_SAFE_END
01440    spy_cleanup(chan);
01441 }

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

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

Referenced by mixmonitor_thread().

01444 {
01445    struct timeval tv;
01446    struct timespec ts;
01447 
01448    tv = ast_tvadd(ast_tvnow(), ast_samp2tv(50000, 1000));
01449    ts.tv_sec = tv.tv_sec;
01450    ts.tv_nsec = tv.tv_usec * 1000;
01451 
01452    ast_cond_timedwait(&spy->trigger, &spy->lock, &ts);
01453 }


Generated on Mon Apr 30 07:40:29 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1