Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:01:27 2007

Asterisk developer's documentation :: Codename Pineapple


chanspy.h File Reference


Detailed Description

Asterisk PBX channel spy definitions.

Definition in file chanspy.h.

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


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

01195 {
01196    /* Link the owner channel to the spy */
01197    spy->chan = chan;
01198 
01199    if (!ast_test_flag(spy, CHANSPY_FORMAT_AUDIO)) {
01200       ast_log(LOG_WARNING, "Could not add channel spy '%s' to channel '%s', only audio format spies are supported.\n",
01201          spy->type, chan->name);
01202       return -1;
01203    }
01204 
01205    if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST) && (spy->read_queue.format != AST_FORMAT_SLINEAR)) {
01206       ast_log(LOG_WARNING, "Cannot provide volume adjustment on '%s' format spies\n",
01207          ast_getformatname(spy->read_queue.format));
01208       return -1;
01209    }
01210 
01211    if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST) && (spy->write_queue.format != AST_FORMAT_SLINEAR)) {
01212       ast_log(LOG_WARNING, "Cannot provide volume adjustment on '%s' format spies\n",
01213          ast_getformatname(spy->write_queue.format));
01214       return -1;
01215    }
01216 
01217    if (ast_test_flag(spy, CHANSPY_MIXAUDIO) &&
01218        ((spy->read_queue.format != AST_FORMAT_SLINEAR) ||
01219         (spy->write_queue.format != AST_FORMAT_SLINEAR))) {
01220       ast_log(LOG_WARNING, "Cannot provide audio mixing on '%s'-'%s' format spies\n",
01221          ast_getformatname(spy->read_queue.format), ast_getformatname(spy->write_queue.format));
01222       return -1;
01223    }
01224 
01225    if (!chan->spies) {
01226       if (!(chan->spies = ast_calloc(1, sizeof(*chan->spies)))) {
01227          return -1;
01228       }
01229 
01230       AST_LIST_HEAD_INIT_NOLOCK(&chan->spies->list);
01231       AST_LIST_INSERT_HEAD(&chan->spies->list, spy, list);
01232    } else {
01233       AST_LIST_INSERT_TAIL(&chan->spies->list, spy, list);
01234    }
01235 
01236    if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE) {
01237       ast_cond_init(&spy->trigger, NULL);
01238       ast_set_flag(spy, CHANSPY_TRIGGER_READ);
01239       ast_clear_flag(spy, CHANSPY_TRIGGER_WRITE);
01240    }
01241 
01242    if (option_debug)
01243       ast_log(LOG_DEBUG, "Spy %s added to channel %s\n",
01244          spy->type, chan->name);
01245 
01246    return 0;
01247 }

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 1329 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, ast_channel_spy::lock, ast_channel_spy::read_queue, ast_channel_spy::status, ast_channel_spy::trigger, and ast_channel_spy::write_queue.

01330 {
01331    struct ast_frame *f = NULL;
01332 
01333    if (spy->status == CHANSPY_DONE)
01334       return;
01335 
01336    /* Switch status to done in case we get called twice */
01337    spy->status = CHANSPY_DONE;
01338 
01339    /* Drop any frames in the queue */
01340    while ((f = AST_LIST_REMOVE_HEAD(&spy->write_queue.list, frame_list)))
01341       ast_frfree(f);
01342    while ((f = AST_LIST_REMOVE_HEAD(&spy->read_queue.list, frame_list)))
01343       ast_frfree(f);
01344 
01345    /* Destroy the condition if in use */
01346    if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE)
01347       ast_cond_destroy(&spy->trigger);
01348 
01349    /* Destroy our mutex since it is no longer in use */
01350    ast_mutex_destroy(&spy->lock);
01351 
01352    return;
01353 }

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 4357 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, ast_channel_spy_queue::samples, ast_channel_spy::write_queue, and ast_channel_spy::write_vol_adjustment.

04358 {
04359    struct ast_frame *result;
04360    /* buffers are allocated to hold SLINEAR, which is the largest format */
04361         short read_buf[samples];
04362         short write_buf[samples];
04363    struct ast_frame *read_frame;
04364    struct ast_frame *write_frame;
04365    int need_dup;
04366    struct ast_frame stack_read_frame = { .frametype = AST_FRAME_VOICE,
04367                      .subclass = spy->read_queue.format,
04368                      .data = read_buf,
04369                      .samples = samples,
04370                      .datalen = ast_codec_get_len(spy->read_queue.format, samples),
04371    };
04372    struct ast_frame stack_write_frame = { .frametype = AST_FRAME_VOICE,
04373                       .subclass = spy->write_queue.format,
04374                       .data = write_buf,
04375                       .samples = samples,
04376                       .datalen = ast_codec_get_len(spy->write_queue.format, samples),
04377    };
04378 
04379    /* if a flush has been requested, dump everything in whichever queue is larger */
04380    if (ast_test_flag(spy, CHANSPY_TRIGGER_FLUSH)) {
04381       if (spy->read_queue.samples > spy->write_queue.samples) {
04382          if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST)) {
04383             AST_LIST_TRAVERSE(&spy->read_queue.list, result, frame_list)
04384                ast_frame_adjust_volume(result, spy->read_vol_adjustment);
04385          }
04386          result = AST_LIST_FIRST(&spy->read_queue.list);
04387          AST_LIST_HEAD_SET_NOLOCK(&spy->read_queue.list, NULL);
04388          spy->read_queue.samples = 0;
04389       } else {
04390          if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST)) {
04391             AST_LIST_TRAVERSE(&spy->write_queue.list, result, frame_list)
04392                ast_frame_adjust_volume(result, spy->write_vol_adjustment);
04393          }
04394          result = AST_LIST_FIRST(&spy->write_queue.list);
04395          AST_LIST_HEAD_SET_NOLOCK(&spy->write_queue.list, NULL);
04396          spy->write_queue.samples = 0;
04397       }
04398       ast_clear_flag(spy, CHANSPY_TRIGGER_FLUSH);
04399       return result;
04400    }
04401 
04402    if ((spy->read_queue.samples < samples) || (spy->write_queue.samples < samples))
04403       return NULL;
04404 
04405    /* short-circuit if both head frames have exactly what we want */
04406    if ((AST_LIST_FIRST(&spy->read_queue.list)->samples == samples) &&
04407        (AST_LIST_FIRST(&spy->write_queue.list)->samples == samples)) {
04408       read_frame = AST_LIST_REMOVE_HEAD(&spy->read_queue.list, frame_list);
04409       write_frame = AST_LIST_REMOVE_HEAD(&spy->write_queue.list, frame_list);
04410 
04411       spy->read_queue.samples -= samples;
04412       spy->write_queue.samples -= samples;
04413 
04414       need_dup = 0;
04415    } else {
04416       copy_data_from_queue(&spy->read_queue, read_buf, samples);
04417       copy_data_from_queue(&spy->write_queue, write_buf, samples);
04418 
04419       read_frame = &stack_read_frame;
04420       write_frame = &stack_write_frame;
04421       need_dup = 1;
04422    }
04423    
04424    if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST))
04425       ast_frame_adjust_volume(read_frame, spy->read_vol_adjustment);
04426 
04427    if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST))
04428       ast_frame_adjust_volume(write_frame, spy->write_vol_adjustment);
04429 
04430    if (ast_test_flag(spy, CHANSPY_MIXAUDIO)) {
04431       ast_frame_slinear_sum(read_frame, write_frame);
04432 
04433       if (need_dup)
04434          result = ast_frdup(read_frame);
04435       else {
04436          result = read_frame;
04437          ast_frfree(write_frame);
04438       }
04439    } else {
04440       if (need_dup) {
04441          result = ast_frdup(read_frame);
04442          AST_LIST_NEXT(result, frame_list) = ast_frdup(write_frame);
04443       } else {
04444          result = read_frame;
04445          AST_LIST_NEXT(result, frame_list) = write_frame;
04446       }
04447    }
04448 
04449    return result;
04450 }

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

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

01320 {
01321    if (!chan->spies)
01322       return;
01323 
01324    AST_LIST_REMOVE(&chan->spies->list, spy, list);
01325    spy_detach(spy, chan);
01326    spy_cleanup(chan);
01327 }

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

01288 {
01289    struct ast_channel_spy *spy = NULL;
01290    
01291    if (!chan->spies)
01292       return;
01293 
01294    AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->spies->list, spy, list) {
01295       ast_mutex_lock(&spy->lock);
01296       if ((spy->type == type) && (spy->status == CHANSPY_RUNNING)) {
01297          ast_mutex_unlock(&spy->lock);
01298          AST_LIST_REMOVE_CURRENT(&chan->spies->list, list);
01299          spy_detach(spy, chan);
01300       } else
01301          ast_mutex_unlock(&spy->lock);
01302    }
01303    AST_LIST_TRAVERSE_SAFE_END
01304    spy_cleanup(chan);
01305 }

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

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

01308 {
01309    struct timeval tv;
01310    struct timespec ts;
01311 
01312    tv = ast_tvadd(ast_tvnow(), ast_samp2tv(50000, 1000));
01313    ts.tv_sec = tv.tv_sec;
01314    ts.tv_nsec = tv.tv_usec * 1000;
01315 
01316    ast_cond_timedwait(&spy->trigger, &spy->lock, &ts);
01317 }


Asterisk is a trademark for Digium, inc.. | Edvina.net | Asterisk.org | This documentation was generated with Doxygen