Wed Aug 18 22:34:05 2010

Asterisk developer's documentation


audiohook.c File Reference

Audiohooks Architecture. More...

#include "asterisk.h"
#include <signal.h>
#include "asterisk/channel.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"
#include "asterisk/linkedlists.h"
#include "asterisk/audiohook.h"
#include "asterisk/slinfactory.h"
#include "asterisk/frame.h"
#include "asterisk/translate.h"

Go to the source code of this file.

Data Structures

struct  ast_audiohook_list
struct  ast_audiohook_translate
struct  audiohook_volume
 Audiohook volume adjustment structure. More...

Functions

int ast_audiohook_attach (struct ast_channel *chan, struct ast_audiohook *audiohook)
 Attach audiohook to channel.
int ast_audiohook_destroy (struct ast_audiohook *audiohook)
 Destroys an audiohook structure.
int ast_audiohook_detach (struct ast_audiohook *audiohook)
 Detach audiohook from channel.
int ast_audiohook_detach_list (struct ast_audiohook_list *audiohook_list)
 Detach audiohooks from list and destroy said list.
int ast_audiohook_detach_source (struct ast_channel *chan, const char *source)
 Detach specified source audiohook from channel.
int ast_audiohook_init (struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source)
 Initialize an audiohook structure.
void ast_audiohook_move_by_source (struct ast_channel *old_chan, struct ast_channel *new_chan, const char *source)
 Move an audiohook from one channel to a new one.
ast_frameast_audiohook_read_frame (struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, int format)
 Reads a frame in from the audiohook structure.
int ast_audiohook_remove (struct ast_channel *chan, struct ast_audiohook *audiohook)
 Remove an audiohook from a specified channel.
void ast_audiohook_trigger_wait (struct ast_audiohook *audiohook)
 Wait for audiohook trigger to be triggered.
void ast_audiohook_update_status (struct ast_audiohook *audiohook, enum ast_audiohook_status status)
 Update audiohook's status.
int ast_audiohook_volume_adjust (struct ast_channel *chan, enum ast_audiohook_direction direction, int volume)
 Adjust the volume on frames read from or written to a channel.
int ast_audiohook_volume_get (struct ast_channel *chan, enum ast_audiohook_direction direction)
 Retrieve the volume adjustment value on frames read from or written to a channel.
int ast_audiohook_volume_set (struct ast_channel *chan, enum ast_audiohook_direction direction, int volume)
 Adjust the volume on frames read from or written to a channel.
int ast_audiohook_write_frame (struct ast_audiohook *audiohook, enum ast_audiohook_direction direction, struct ast_frame *frame)
 Writes a frame into the audiohook structure.
ast_frameast_audiohook_write_list (struct ast_channel *chan, struct ast_audiohook_list *audiohook_list, enum ast_audiohook_direction direction, struct ast_frame *frame)
 Pass a frame off to be handled by the audiohook core.
int ast_channel_audiohook_count_by_source (struct ast_channel *chan, const char *source, enum ast_audiohook_type type)
 Find out how many audiohooks from a certain source exist on a given channel, regardless of status.
int ast_channel_audiohook_count_by_source_running (struct ast_channel *chan, const char *source, enum ast_audiohook_type type)
 Find out how many spies of a certain type exist on a given channel, and are in state running.
static struct ast_frameaudio_audiohook_write_list (struct ast_channel *chan, struct ast_audiohook_list *audiohook_list, enum ast_audiohook_direction direction, struct ast_frame *frame)
 Pass an AUDIO frame off to be handled by the audiohook core.
static struct ast_frameaudiohook_read_frame_both (struct ast_audiohook *audiohook, size_t samples)
static struct ast_frameaudiohook_read_frame_single (struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction)
static int audiohook_volume_callback (struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
 Helper function which actually gets called by audiohooks to perform the adjustment.
static void audiohook_volume_destroy (void *data)
 Callback used to destroy the audiohook volume datastore.
static struct audiohook_volumeaudiohook_volume_get (struct ast_channel *chan, int create)
 Helper function which finds and optionally creates an audiohook_volume_datastore datastore on a channel.
static struct ast_framedtmf_audiohook_write_list (struct ast_channel *chan, struct ast_audiohook_list *audiohook_list, enum ast_audiohook_direction direction, struct ast_frame *frame)
 Pass a DTMF frame off to be handled by the audiohook core.
static struct ast_audiohookfind_audiohook_by_source (struct ast_audiohook_list *audiohook_list, const char *source)
 find an audiohook based on its source

Variables

static struct ast_datastore_info audiohook_volume_datastore
 Datastore used to store audiohook volume information.


Detailed Description

Audiohooks Architecture.

Author:
Joshua 'file' Colp <jcolp@digium.com>

Definition in file audiohook.c.


Function Documentation

int ast_audiohook_attach ( struct ast_channel chan,
struct ast_audiohook audiohook 
)

Attach audiohook to channel.

Parameters:
chan Channel
audiohook Audiohook structure
Returns:
Returns 0 on success, -1 on failure

Definition at line 330 of file audiohook.c.

References AST_AUDIOHOOK_STATUS_RUNNING, AST_AUDIOHOOK_TYPE_MANIPULATE, AST_AUDIOHOOK_TYPE_SPY, AST_AUDIOHOOK_TYPE_WHISPER, ast_audiohook_update_status(), ast_calloc, ast_channel_lock, ast_channel_unlock, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, ast_channel::audiohooks, chan, ast_audiohook_list::manipulate_list, ast_audiohook_list::spy_list, ast_audiohook::type, and ast_audiohook_list::whisper_list.

Referenced by ast_audiohook_move_by_source(), audiohook_volume_get(), enable_jack_hook(), speex_write(), start_spying(), startmon(), and volume_write().

00331 {
00332    ast_channel_lock(chan);
00333 
00334    if (!chan->audiohooks) {
00335       /* Whoops... allocate a new structure */
00336       if (!(chan->audiohooks = ast_calloc(1, sizeof(*chan->audiohooks)))) {
00337          ast_channel_unlock(chan);
00338          return -1;
00339       }
00340       AST_LIST_HEAD_INIT_NOLOCK(&chan->audiohooks->spy_list);
00341       AST_LIST_HEAD_INIT_NOLOCK(&chan->audiohooks->whisper_list);
00342       AST_LIST_HEAD_INIT_NOLOCK(&chan->audiohooks->manipulate_list);
00343    }
00344 
00345    /* Drop into respective list */
00346    if (audiohook->type == AST_AUDIOHOOK_TYPE_SPY)
00347       AST_LIST_INSERT_TAIL(&chan->audiohooks->spy_list, audiohook, list);
00348    else if (audiohook->type == AST_AUDIOHOOK_TYPE_WHISPER)
00349       AST_LIST_INSERT_TAIL(&chan->audiohooks->whisper_list, audiohook, list);
00350    else if (audiohook->type == AST_AUDIOHOOK_TYPE_MANIPULATE)
00351       AST_LIST_INSERT_TAIL(&chan->audiohooks->manipulate_list, audiohook, list);
00352 
00353    /* Change status over to running since it is now attached */
00354    ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_RUNNING);
00355 
00356    ast_channel_unlock(chan);
00357 
00358    return 0;
00359 }

int ast_audiohook_destroy ( struct ast_audiohook audiohook  ) 

Destroys an audiohook structure.

Parameters:
audiohook Audiohook structure
Returns:
Returns 0 on success, -1 on failure

Definition at line 91 of file audiohook.c.

References AST_AUDIOHOOK_TYPE_SPY, AST_AUDIOHOOK_TYPE_WHISPER, ast_cond_destroy(), ast_mutex_destroy(), ast_slinfactory_destroy(), ast_translator_free_path(), ast_audiohook::lock, ast_audiohook::read_factory, ast_audiohook::trans_pvt, ast_audiohook::trigger, ast_audiohook::type, and ast_audiohook::write_factory.

Referenced by audiohook_volume_destroy(), channel_spy(), destroy_callback(), destroy_jack_data(), destroy_monitor_audiohook(), and launch_monitor_thread().

00092 {
00093    /* Drop the factories used by this audiohook type */
00094    switch (audiohook->type) {
00095    case AST_AUDIOHOOK_TYPE_SPY:
00096       ast_slinfactory_destroy(&audiohook->read_factory);
00097    case AST_AUDIOHOOK_TYPE_WHISPER:
00098       ast_slinfactory_destroy(&audiohook->write_factory);
00099       break;
00100    default:
00101       break;
00102    }
00103 
00104    /* Destroy translation path if present */
00105    if (audiohook->trans_pvt)
00106       ast_translator_free_path(audiohook->trans_pvt);
00107 
00108    /* Lock and trigger be gone! */
00109    ast_cond_destroy(&audiohook->trigger);
00110    ast_mutex_destroy(&audiohook->lock);
00111 
00112    return 0;
00113 }

int ast_audiohook_detach ( struct ast_audiohook audiohook  ) 

Detach audiohook from channel.

Parameters:
audiohook Audiohook structure
Returns:
Returns 0 on success, -1 on failure

Definition at line 383 of file audiohook.c.

References AST_AUDIOHOOK_STATUS_DONE, AST_AUDIOHOOK_STATUS_NEW, AST_AUDIOHOOK_STATUS_SHUTDOWN, ast_audiohook_trigger_wait(), ast_audiohook_update_status(), and ast_audiohook::status.

Referenced by channel_spy(), destroy_monitor_audiohook(), disable_jack_hook(), and speex_write().

00384 {
00385    if (audiohook->status == AST_AUDIOHOOK_STATUS_NEW || audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
00386       return 0;
00387 
00388    ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_SHUTDOWN);
00389 
00390    while (audiohook->status != AST_AUDIOHOOK_STATUS_DONE)
00391       ast_audiohook_trigger_wait(audiohook);
00392 
00393    return 0;
00394 }

int ast_audiohook_detach_list ( struct ast_audiohook_list audiohook_list  ) 

Detach audiohooks from list and destroy said list.

Parameters:
audiohook_list List of audiohooks
Returns:
Returns 0 on success, -1 on failure

Definition at line 400 of file audiohook.c.

References AST_AUDIOHOOK_STATUS_DONE, ast_audiohook_update_status(), ast_free, AST_LIST_REMOVE_HEAD, ast_translator_free_path(), ast_audiohook_list::in_translate, ast_audiohook::list, ast_audiohook_list::manipulate_list, ast_audiohook_list::out_translate, ast_audiohook_list::spy_list, ast_audiohook_translate::trans_pvt, and ast_audiohook_list::whisper_list.

Referenced by ast_hangup().

00401 {
00402    int i = 0;
00403    struct ast_audiohook *audiohook = NULL;
00404 
00405    /* Drop any spies */
00406    while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->spy_list, list))) {
00407       ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00408    }
00409 
00410    /* Drop any whispering sources */
00411    while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->whisper_list, list))) {
00412       ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00413    }
00414 
00415    /* Drop any manipulaters */
00416    while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->manipulate_list, list))) {
00417       ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00418       audiohook->manipulate_callback(audiohook, NULL, NULL, 0);
00419    }
00420 
00421    /* Drop translation paths if present */
00422    for (i = 0; i < 2; i++) {
00423       if (audiohook_list->in_translate[i].trans_pvt)
00424          ast_translator_free_path(audiohook_list->in_translate[i].trans_pvt);
00425       if (audiohook_list->out_translate[i].trans_pvt)
00426          ast_translator_free_path(audiohook_list->out_translate[i].trans_pvt);
00427    }
00428    
00429    /* Free ourselves */
00430    ast_free(audiohook_list);
00431 
00432    return 0;
00433 }

int ast_audiohook_detach_source ( struct ast_channel chan,
const char *  source 
)

Detach specified source audiohook from channel.

Parameters:
chan Channel to detach from
source Name of source to detach
Returns:
Returns 0 on success, -1 on failure

Definition at line 491 of file audiohook.c.

References AST_AUDIOHOOK_STATUS_DONE, AST_AUDIOHOOK_STATUS_SHUTDOWN, ast_audiohook_update_status(), ast_channel_lock, ast_channel_unlock, ast_channel::audiohooks, chan, find_audiohook_by_source(), and ast_audiohook::status.

Referenced by handle_cli_mixmonitor(), and stop_mixmonitor_exec().

00492 {
00493    struct ast_audiohook *audiohook = NULL;
00494 
00495    ast_channel_lock(chan);
00496 
00497    /* Ensure the channel has audiohooks on it */
00498    if (!chan->audiohooks) {
00499       ast_channel_unlock(chan);
00500       return -1;
00501    }
00502 
00503    audiohook = find_audiohook_by_source(chan->audiohooks, source);
00504 
00505    ast_channel_unlock(chan);
00506 
00507    if (audiohook && audiohook->status != AST_AUDIOHOOK_STATUS_DONE)
00508       ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_SHUTDOWN);
00509 
00510    return (audiohook ? 0 : -1);
00511 }

int ast_audiohook_init ( struct ast_audiohook audiohook,
enum ast_audiohook_type  type,
const char *  source 
)

Initialize an audiohook structure.

Parameters:
audiohook Audiohook structure
type 
source 
Returns:
Returns 0 on success, -1 on failure

Definition at line 60 of file audiohook.c.

References AST_AUDIOHOOK_STATUS_NEW, AST_AUDIOHOOK_TYPE_SPY, AST_AUDIOHOOK_TYPE_WHISPER, ast_audiohook_update_status(), ast_cond_init(), ast_mutex_init(), and ast_slinfactory_init().

Referenced by audiohook_volume_get(), channel_spy(), enable_jack_hook(), launch_monitor_thread(), speex_write(), and volume_write().

00061 {
00062    /* Need to keep the type and source */
00063    audiohook->type = type;
00064    audiohook->source = source;
00065 
00066    /* Initialize lock that protects our audiohook */
00067    ast_mutex_init(&audiohook->lock);
00068    ast_cond_init(&audiohook->trigger, NULL);
00069 
00070    /* Setup the factories that are needed for this audiohook type */
00071    switch (type) {
00072    case AST_AUDIOHOOK_TYPE_SPY:
00073       ast_slinfactory_init(&audiohook->read_factory);
00074    case AST_AUDIOHOOK_TYPE_WHISPER:
00075       ast_slinfactory_init(&audiohook->write_factory);
00076       break;
00077    default:
00078       break;
00079    }
00080 
00081    /* Since we are just starting out... this audiohook is new */
00082    ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_NEW);
00083 
00084    return 0;
00085 }

void ast_audiohook_move_by_source ( struct ast_channel old_chan,
struct ast_channel new_chan,
const char *  source 
)

Move an audiohook from one channel to a new one.

Todo:
Currently only the first audiohook of a specific source found will be moved. We should add the capability to move multiple audiohooks from a single source as well.
Note:
It is required that both old_chan and new_chan are locked prior to calling this function. Besides needing to protect the data within the channels, not locking these channels can lead to a potential deadlock
Parameters:
old_chan The source of the audiohook to move
new_chan The destination to which we want the audiohook to move
source The source of the audiohook we want to move

Definition at line 462 of file audiohook.c.

References ast_audiohook_attach(), ast_audiohook_lock, ast_audiohook_remove(), ast_audiohook_unlock, ast_channel::audiohooks, find_audiohook_by_source(), and ast_audiohook::status.

Referenced by audiohook_inheritance_fixup().

00463 {
00464    struct ast_audiohook *audiohook;
00465    enum ast_audiohook_status oldstatus;
00466 
00467    if (!old_chan->audiohooks || !(audiohook = find_audiohook_by_source(old_chan->audiohooks, source))) {
00468       return;
00469    }
00470 
00471    /* By locking both channels and the audiohook, we can assure that
00472     * another thread will not have a chance to read the audiohook's status
00473     * as done, even though ast_audiohook_remove signals the trigger
00474     * condition.
00475     */
00476    ast_audiohook_lock(audiohook);
00477    oldstatus = audiohook->status;
00478 
00479    ast_audiohook_remove(old_chan, audiohook);
00480    ast_audiohook_attach(new_chan, audiohook);
00481 
00482    audiohook->status = oldstatus;
00483    ast_audiohook_unlock(audiohook);
00484 }

struct ast_frame* ast_audiohook_read_frame ( struct ast_audiohook audiohook,
size_t  samples,
enum ast_audiohook_direction  direction,
int  format 
)

Reads a frame in from the audiohook structure.

Parameters:
audiohook Audiohook structure
samples Number of samples wanted
direction Direction the audio frame came from
format Format of frame remote side wants back
Returns:
Returns frame on success, NULL on failure

Definition at line 295 of file audiohook.c.

References AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR, ast_frfree, ast_translate(), ast_translator_build_path(), ast_translator_free_path(), audiohook_read_frame_both(), audiohook_read_frame_single(), and read_frame().

Referenced by mixmonitor_thread(), and spy_generate().

00296 {
00297    struct ast_frame *read_frame = NULL, *final_frame = NULL;
00298 
00299    if (!(read_frame = (direction == AST_AUDIOHOOK_DIRECTION_BOTH ? audiohook_read_frame_both(audiohook, samples) : audiohook_read_frame_single(audiohook, samples, direction))))
00300       return NULL;
00301 
00302    /* If they don't want signed linear back out, we'll have to send it through the translation path */
00303    if (format != AST_FORMAT_SLINEAR) {
00304       /* Rebuild translation path if different format then previously */
00305       if (audiohook->format != format) {
00306          if (audiohook->trans_pvt) {
00307             ast_translator_free_path(audiohook->trans_pvt);
00308             audiohook->trans_pvt = NULL;
00309          }
00310          /* Setup new translation path for this format... if we fail we can't very well return signed linear so free the frame and return nothing */
00311          if (!(audiohook->trans_pvt = ast_translator_build_path(format, AST_FORMAT_SLINEAR))) {
00312             ast_frfree(read_frame);
00313             return NULL;
00314          }
00315       }
00316       /* Convert to requested format, and allow the read in frame to be freed */
00317       final_frame = ast_translate(audiohook->trans_pvt, read_frame, 1);
00318    } else {
00319       final_frame = read_frame;
00320    }
00321 
00322    return final_frame;
00323 }

int ast_audiohook_remove ( struct ast_channel chan,
struct ast_audiohook audiohook 
)

Remove an audiohook from a specified channel.

Parameters:
chan Channel to remove from
audiohook Audiohook to remove
Returns:
Returns 0 on success, -1 on failure
Note:
The channel does not need to be locked before calling this function

Definition at line 523 of file audiohook.c.

References AST_AUDIOHOOK_STATUS_DONE, AST_AUDIOHOOK_TYPE_MANIPULATE, AST_AUDIOHOOK_TYPE_SPY, AST_AUDIOHOOK_TYPE_WHISPER, ast_audiohook_update_status(), ast_channel_lock, ast_channel_unlock, AST_LIST_REMOVE, ast_channel::audiohooks, chan, ast_audiohook::list, ast_audiohook_list::manipulate_list, ast_audiohook_list::spy_list, ast_audiohook::type, and ast_audiohook_list::whisper_list.

Referenced by ast_audiohook_move_by_source(), and speex_write().

00524 {
00525    ast_channel_lock(chan);
00526 
00527    if (!chan->audiohooks) {
00528       ast_channel_unlock(chan);
00529       return -1;
00530    }
00531 
00532    if (audiohook->type == AST_AUDIOHOOK_TYPE_SPY)
00533       AST_LIST_REMOVE(&chan->audiohooks->spy_list, audiohook, list);
00534    else if (audiohook->type == AST_AUDIOHOOK_TYPE_WHISPER)
00535       AST_LIST_REMOVE(&chan->audiohooks->whisper_list, audiohook, list);
00536    else if (audiohook->type == AST_AUDIOHOOK_TYPE_MANIPULATE)
00537       AST_LIST_REMOVE(&chan->audiohooks->manipulate_list, audiohook, list);
00538 
00539    ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00540 
00541    ast_channel_unlock(chan);
00542 
00543    return 0;
00544 }

void ast_audiohook_trigger_wait ( struct ast_audiohook audiohook  ) 

Wait for audiohook trigger to be triggered.

Parameters:
audiohook Audiohook to wait on

Definition at line 748 of file audiohook.c.

References ast_cond_timedwait(), ast_samp2tv(), ast_tvadd(), ast_tvnow(), ast_audiohook::lock, and ast_audiohook::trigger.

Referenced by ast_audiohook_detach(), and mixmonitor_thread().

00749 {
00750    struct timeval wait;
00751    struct timespec ts;
00752 
00753    wait = ast_tvadd(ast_tvnow(), ast_samp2tv(50000, 1000));
00754    ts.tv_sec = wait.tv_sec;
00755    ts.tv_nsec = wait.tv_usec * 1000;
00756    
00757    ast_cond_timedwait(&audiohook->trigger, &audiohook->lock, &ts);
00758    
00759    return;
00760 }

void ast_audiohook_update_status ( struct ast_audiohook audiohook,
enum ast_audiohook_status  status 
)

Update audiohook's status.

Parameters:
audiohook status enum
audiohook Audiohook structure
Note:
once status is updated to DONE, this function can not be used to set the status back to any other setting. Setting DONE effectively locks the status as such.

Definition at line 369 of file audiohook.c.

References ast_audiohook_lock, AST_AUDIOHOOK_STATUS_DONE, ast_audiohook_unlock, ast_cond_signal(), ast_audiohook::status, and ast_audiohook::trigger.

Referenced by ast_audiohook_attach(), ast_audiohook_detach(), ast_audiohook_detach_list(), ast_audiohook_detach_source(), ast_audiohook_init(), ast_audiohook_remove(), audio_audiohook_write_list(), and dtmf_audiohook_write_list().

00370 {
00371    ast_audiohook_lock(audiohook);
00372    if (audiohook->status != AST_AUDIOHOOK_STATUS_DONE) {
00373       audiohook->status = status;
00374       ast_cond_signal(&audiohook->trigger);
00375    }
00376    ast_audiohook_unlock(audiohook);
00377 }

int ast_audiohook_volume_adjust ( struct ast_channel chan,
enum ast_audiohook_direction  direction,
int  volume 
)

Adjust the volume on frames read from or written to a channel.

Parameters:
chan Channel to muck with
direction Direction to increase
volume Value to adjust the adjustment by
Returns:
Returns 0 on success, -1 on failure

Definition at line 1008 of file audiohook.c.

References AST_AUDIOHOOK_DIRECTION_BOTH, AST_AUDIOHOOK_DIRECTION_READ, AST_AUDIOHOOK_DIRECTION_WRITE, audiohook_volume_get(), chan, audiohook_volume::read_adjustment, and audiohook_volume::write_adjustment.

01009 {
01010    struct audiohook_volume *audiohook_volume = NULL;
01011 
01012    /* Attempt to find the audiohook volume information, and create an audiohook if none exists */
01013    if (!(audiohook_volume = audiohook_volume_get(chan, 1))) {
01014       return -1;
01015    }
01016 
01017    /* Based on the direction change the specific adjustment value */
01018    if (direction == AST_AUDIOHOOK_DIRECTION_READ || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
01019       audiohook_volume->read_adjustment += volume;
01020    }
01021    if (direction == AST_AUDIOHOOK_DIRECTION_WRITE || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
01022       audiohook_volume->write_adjustment += volume;
01023    }
01024 
01025    return 0;
01026 }

int ast_audiohook_volume_get ( struct ast_channel chan,
enum ast_audiohook_direction  direction 
)

Retrieve the volume adjustment value on frames read from or written to a channel.

Parameters:
chan Channel to retrieve volume adjustment from
direction Direction to retrieve
Returns:
Returns adjustment value

Definition at line 982 of file audiohook.c.

References AST_AUDIOHOOK_DIRECTION_READ, AST_AUDIOHOOK_DIRECTION_WRITE, audiohook_volume_get(), chan, audiohook_volume::read_adjustment, and audiohook_volume::write_adjustment.

00983 {
00984    struct audiohook_volume *audiohook_volume = NULL;
00985    int adjustment = 0;
00986 
00987    /* Attempt to find the audiohook volume information, but do not create it as we only want to look at the values */
00988    if (!(audiohook_volume = audiohook_volume_get(chan, 0))) {
00989       return 0;
00990    }
00991 
00992    /* Grab the adjustment value based on direction given */
00993    if (direction == AST_AUDIOHOOK_DIRECTION_READ) {
00994       adjustment = audiohook_volume->read_adjustment;
00995    } else if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) {
00996       adjustment = audiohook_volume->write_adjustment;
00997    }
00998 
00999    return adjustment;
01000 }

int ast_audiohook_volume_set ( struct ast_channel chan,
enum ast_audiohook_direction  direction,
int  volume 
)

Adjust the volume on frames read from or written to a channel.

Parameters:
chan Channel to muck with
direction Direction to set on
volume Value to adjust the volume by
Returns:
Returns 0 on success, -1 on failure

Definition at line 957 of file audiohook.c.

References AST_AUDIOHOOK_DIRECTION_BOTH, AST_AUDIOHOOK_DIRECTION_READ, AST_AUDIOHOOK_DIRECTION_WRITE, audiohook_volume_get(), chan, audiohook_volume::read_adjustment, and audiohook_volume::write_adjustment.

00958 {
00959    struct audiohook_volume *audiohook_volume = NULL;
00960 
00961    /* Attempt to find the audiohook volume information, but only create it if we are not setting the adjustment value to zero */
00962    if (!(audiohook_volume = audiohook_volume_get(chan, (volume ? 1 : 0)))) {
00963       return -1;
00964    }
00965 
00966    /* Now based on the direction set the proper value */
00967    if (direction == AST_AUDIOHOOK_DIRECTION_READ || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
00968       audiohook_volume->read_adjustment = volume;
00969    }
00970    if (direction == AST_AUDIOHOOK_DIRECTION_WRITE || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
00971       audiohook_volume->write_adjustment = volume;
00972    }
00973 
00974    return 0;
00975 }

int ast_audiohook_write_frame ( struct ast_audiohook audiohook,
enum ast_audiohook_direction  direction,
struct ast_frame frame 
)

Writes a frame into the audiohook structure.

Parameters:
audiohook Audiohook structure
direction Direction the audio frame came from
frame Frame to write in
Returns:
Returns 0 on success, -1 on failure

Definition at line 121 of file audiohook.c.

References AST_AUDIOHOOK_DIRECTION_READ, AST_AUDIOHOOK_DIRECTION_WRITE, AST_AUDIOHOOK_SMALL_QUEUE, AST_AUDIOHOOK_SYNC_TOLERANCE, AST_AUDIOHOOK_TRIGGER_MODE, AST_AUDIOHOOK_TRIGGER_READ, AST_AUDIOHOOK_TRIGGER_SYNC, AST_AUDIOHOOK_TRIGGER_WRITE, ast_cond_signal(), ast_log(), ast_slinfactory_available(), ast_slinfactory_feed(), ast_slinfactory_flush(), ast_test_flag, ast_tvdiff_ms(), ast_tvnow(), LOG_DEBUG, option_debug, ast_audiohook::read_factory, ast_audiohook::read_time, ast_audiohook::trigger, ast_audiohook::write_factory, and ast_audiohook::write_time.

Referenced by audio_audiohook_write_list(), and channel_spy().

00122 {
00123    struct ast_slinfactory *factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_factory : &audiohook->write_factory);
00124    struct ast_slinfactory *other_factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->write_factory : &audiohook->read_factory);
00125    struct timeval *rwtime = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_time : &audiohook->write_time), previous_time = *rwtime;
00126    int our_factory_samples;
00127    int our_factory_ms;
00128    int other_factory_samples;
00129    int other_factory_ms;
00130 
00131    /* Update last feeding time to be current */
00132    *rwtime = ast_tvnow();
00133 
00134    our_factory_samples = ast_slinfactory_available(factory);
00135    our_factory_ms = ast_tvdiff_ms(*rwtime, previous_time) + (our_factory_samples / 8);
00136    other_factory_samples = ast_slinfactory_available(other_factory);
00137    other_factory_ms = other_factory_samples / 8;
00138 
00139    if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC) && other_factory_samples && (our_factory_ms - other_factory_ms > AST_AUDIOHOOK_SYNC_TOLERANCE)) {
00140       if (option_debug)
00141          ast_log(LOG_DEBUG, "Flushing audiohook %p so it remains in sync\n", audiohook);
00142       ast_slinfactory_flush(factory);
00143       ast_slinfactory_flush(other_factory);
00144    }
00145 
00146    if (ast_test_flag(audiohook, AST_AUDIOHOOK_SMALL_QUEUE) && (our_factory_samples > 640 || other_factory_samples > 640)) {
00147       if (option_debug) {
00148          ast_log(LOG_DEBUG, "Audiohook %p has stale audio in its factories. Flushing them both\n", audiohook);
00149       }
00150       ast_slinfactory_flush(factory);
00151       ast_slinfactory_flush(other_factory);
00152    }
00153 
00154    /* Write frame out to respective factory */
00155    ast_slinfactory_feed(factory, frame);
00156 
00157    /* If we need to notify the respective handler of this audiohook, do so */
00158    if ((ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_MODE) == AST_AUDIOHOOK_TRIGGER_READ) && (direction == AST_AUDIOHOOK_DIRECTION_READ)) {
00159       ast_cond_signal(&audiohook->trigger);
00160    } else if ((ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_MODE) == AST_AUDIOHOOK_TRIGGER_WRITE) && (direction == AST_AUDIOHOOK_DIRECTION_WRITE)) {
00161       ast_cond_signal(&audiohook->trigger);
00162    } else if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC)) {
00163       ast_cond_signal(&audiohook->trigger);
00164    }
00165 
00166    return 0;
00167 }

struct ast_frame* ast_audiohook_write_list ( struct ast_channel chan,
struct ast_audiohook_list audiohook_list,
enum ast_audiohook_direction  direction,
struct ast_frame frame 
)

Pass a frame off to be handled by the audiohook core.

Parameters:
chan Channel that the list is coming off of
audiohook_list List of audiohooks
direction Direction frame is coming in from
frame The frame itself
Returns:
Return frame on success, NULL on failure

Definition at line 733 of file audiohook.c.

References AST_FRAME_DTMF, AST_FRAME_VOICE, audio_audiohook_write_list(), chan, dtmf_audiohook_write_list(), and ast_frame::frametype.

Referenced by __ast_read(), and ast_write().

00734 {
00735    /* Pass off frame to it's respective list write function */
00736    if (frame->frametype == AST_FRAME_VOICE)
00737       return audio_audiohook_write_list(chan, audiohook_list, direction, frame);
00738    else if (frame->frametype == AST_FRAME_DTMF)
00739       return dtmf_audiohook_write_list(chan, audiohook_list, direction, frame);
00740    else
00741       return frame;
00742 }

int ast_channel_audiohook_count_by_source ( struct ast_channel chan,
const char *  source,
enum ast_audiohook_type  type 
)

Find out how many audiohooks from a certain source exist on a given channel, regardless of status.

Parameters:
chan The channel on which to find the spies
source The audiohook's source
type The type of audiohook
Returns:
Return the number of audiohooks which are from the source specified
Note: Function performs nlocking.

Definition at line 763 of file audiohook.c.

References AST_AUDIOHOOK_TYPE_MANIPULATE, AST_AUDIOHOOK_TYPE_SPY, AST_AUDIOHOOK_TYPE_WHISPER, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_channel::audiohooks, chan, ast_audiohook::list, ast_audiohook_list::manipulate_list, ast_audiohook::source, ast_audiohook_list::spy_list, and ast_audiohook_list::whisper_list.

Referenced by builtin_automixmonitor().

00764 {
00765    int count = 0;
00766    struct ast_audiohook *ah = NULL;
00767 
00768    if (!chan->audiohooks)
00769       return -1;
00770 
00771    switch (type) {
00772       case AST_AUDIOHOOK_TYPE_SPY:
00773          AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->spy_list, ah, list) {
00774             if (!strcmp(ah->source, source)) {
00775                count++;
00776             }
00777          }
00778          AST_LIST_TRAVERSE_SAFE_END;
00779          break;
00780       case AST_AUDIOHOOK_TYPE_WHISPER:
00781          AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->whisper_list, ah, list) {
00782             if (!strcmp(ah->source, source)) {
00783                count++;
00784             }
00785          }
00786          AST_LIST_TRAVERSE_SAFE_END;
00787          break;
00788       case AST_AUDIOHOOK_TYPE_MANIPULATE:
00789          AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->manipulate_list, ah, list) {
00790             if (!strcmp(ah->source, source)) {
00791                count++;
00792             }
00793          }
00794          AST_LIST_TRAVERSE_SAFE_END;
00795          break;
00796       default:
00797          ast_log(LOG_DEBUG, "Invalid audiohook type supplied, (%d)\n", type);
00798          return -1;
00799    }
00800 
00801    return count;
00802 }

int ast_channel_audiohook_count_by_source_running ( struct ast_channel chan,
const char *  source,
enum ast_audiohook_type  type 
)

Find out how many spies of a certain type exist on a given channel, and are in state running.

Parameters:
chan The channel on which to find the spies
source The source of the audiohook
type The type of spy to look for
Returns:
Return the number of running audiohooks which are from the source specified
Note: Function performs no locking.

Definition at line 805 of file audiohook.c.

References AST_AUDIOHOOK_STATUS_RUNNING, AST_AUDIOHOOK_TYPE_MANIPULATE, AST_AUDIOHOOK_TYPE_SPY, AST_AUDIOHOOK_TYPE_WHISPER, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_channel::audiohooks, chan, ast_audiohook::list, ast_audiohook_list::manipulate_list, ast_audiohook::source, ast_audiohook_list::spy_list, ast_audiohook::status, and ast_audiohook_list::whisper_list.

Referenced by builtin_automixmonitor().

00806 {
00807    int count = 0;
00808    struct ast_audiohook *ah = NULL;
00809    if (!chan->audiohooks)
00810       return -1;
00811 
00812    switch (type) {
00813       case AST_AUDIOHOOK_TYPE_SPY:
00814          AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->spy_list, ah, list) {
00815             if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
00816                count++;
00817          }
00818          AST_LIST_TRAVERSE_SAFE_END;
00819          break;
00820       case AST_AUDIOHOOK_TYPE_WHISPER:
00821          AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->whisper_list, ah, list) {
00822             if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
00823                count++;
00824          }
00825          AST_LIST_TRAVERSE_SAFE_END;
00826          break;
00827       case AST_AUDIOHOOK_TYPE_MANIPULATE:
00828          AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->manipulate_list, ah, list) {
00829             if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
00830                count++;
00831          }
00832          AST_LIST_TRAVERSE_SAFE_END;
00833          break;
00834       default:
00835          ast_log(LOG_DEBUG, "Invalid audiohook type supplied, (%d)\n", type);
00836          return -1;
00837    }
00838    return count;
00839 }

static struct ast_frame* audio_audiohook_write_list ( struct ast_channel chan,
struct ast_audiohook_list audiohook_list,
enum ast_audiohook_direction  direction,
struct ast_frame frame 
) [static]

Pass an AUDIO frame off to be handled by the audiohook core.

This function has 3 ast_frames and 3 parts to handle each. At the beginning of this function all 3 frames, start_frame, middle_frame, and end_frame point to the initial input frame.

Part_1: Translate the start_frame into SLINEAR audio if it is not already in that format. The result of this part is middle_frame is guaranteed to be in SLINEAR format for Part_2. Part_2: Send middle_frame off to spies and manipulators. At this point middle_frame is either a new frame as result of the translation, or points directly to the start_frame because no translation to SLINEAR audio was required. The result of this part is end_frame will be updated to point to middle_frame if any audiohook manipulation took place. Part_3: Translate end_frame's audio back into the format of start frame if necessary. At this point if middle_frame != end_frame, we are guaranteed that no manipulation took place and middle_frame can be freed as it was translated... If middle_frame was not translated and still pointed to start_frame, it would be equal to end_frame as well regardless if manipulation took place which would not result in this free. The result of this part is end_frame is guaranteed to be the format of start_frame for the return.

Parameters:
chan Channel that the list is coming off of
audiohook_list List of audiohooks
direction Direction frame is coming in from
frame The frame itself
Returns:
Return frame on success, NULL on failure

Definition at line 604 of file audiohook.c.

References AST_AUDIOHOOK_DIRECTION_READ, AST_AUDIOHOOK_DIRECTION_WRITE, ast_audiohook_lock, AST_AUDIOHOOK_STATUS_DONE, AST_AUDIOHOOK_STATUS_RUNNING, ast_audiohook_unlock, ast_audiohook_update_status(), ast_audiohook_write_frame(), AST_FORMAT_SLINEAR, ast_frfree, AST_LIST_EMPTY, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_slinear_saturated_add(), ast_slinfactory_available(), ast_slinfactory_read(), ast_translate(), ast_translator_build_path(), ast_translator_free_path(), chan, ast_audiohook_translate::format, ast_audiohook_list::in_translate, ast_audiohook::list, ast_audiohook::manipulate_callback, ast_audiohook_list::manipulate_list, ast_audiohook_list::out_translate, ast_frame::samples, ast_audiohook_list::spy_list, ast_audiohook::status, ast_frame::subclass, ast_audiohook_translate::trans_pvt, ast_audiohook_list::whisper_list, and ast_audiohook::write_factory.

Referenced by ast_audiohook_write_list().

00605 {
00606    struct ast_audiohook_translate *in_translate = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook_list->in_translate[0] : &audiohook_list->in_translate[1]);
00607    struct ast_audiohook_translate *out_translate = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook_list->out_translate[0] : &audiohook_list->out_translate[1]);
00608    struct ast_frame *start_frame = frame, *middle_frame = frame, *end_frame = frame;
00609    struct ast_audiohook *audiohook = NULL;
00610    int samples = frame->samples;
00611 
00612    /* ---Part_1. translate start_frame to SLINEAR if necessary. */
00613    /* If the frame coming in is not signed linear we have to send it through the in_translate path */
00614    if (frame->subclass != AST_FORMAT_SLINEAR) {
00615       if (in_translate->format != frame->subclass) {
00616          if (in_translate->trans_pvt)
00617             ast_translator_free_path(in_translate->trans_pvt);
00618          if (!(in_translate->trans_pvt = ast_translator_build_path(AST_FORMAT_SLINEAR, frame->subclass)))
00619             return frame;
00620          in_translate->format = frame->subclass;
00621       }
00622       if (!(middle_frame = ast_translate(in_translate->trans_pvt, frame, 0)))
00623          return frame;
00624       samples = middle_frame->samples;
00625    }
00626 
00627    /* ---Part_2: Send middle_frame to spy and manipulator lists.  middle_frame is guaranteed to be SLINEAR here.*/
00628    /* Queue up signed linear frame to each spy */
00629    AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->spy_list, audiohook, list) {
00630       ast_audiohook_lock(audiohook);
00631       if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
00632          AST_LIST_REMOVE_CURRENT(list);
00633          ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00634          ast_audiohook_unlock(audiohook);
00635          continue;
00636       }
00637       ast_audiohook_write_frame(audiohook, direction, middle_frame);
00638       ast_audiohook_unlock(audiohook);
00639    }
00640    AST_LIST_TRAVERSE_SAFE_END;
00641 
00642    /* If this frame is being written out to the channel then we need to use whisper sources */
00643    if (direction == AST_AUDIOHOOK_DIRECTION_WRITE && !AST_LIST_EMPTY(&audiohook_list->whisper_list)) {
00644       int i = 0;
00645       short read_buf[samples], combine_buf[samples], *data1 = NULL, *data2 = NULL;
00646       memset(&combine_buf, 0, sizeof(combine_buf));
00647       AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->whisper_list, audiohook, list) {
00648          ast_audiohook_lock(audiohook);
00649          if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
00650             AST_LIST_REMOVE_CURRENT(list);
00651             ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00652             ast_audiohook_unlock(audiohook);
00653             continue;
00654          }
00655          if (ast_slinfactory_available(&audiohook->write_factory) >= samples && ast_slinfactory_read(&audiohook->write_factory, read_buf, samples)) {
00656             /* Take audio from this whisper source and combine it into our main buffer */
00657             for (i = 0, data1 = combine_buf, data2 = read_buf; i < samples; i++, data1++, data2++)
00658                ast_slinear_saturated_add(data1, data2);
00659          }
00660          ast_audiohook_unlock(audiohook);
00661       }
00662       AST_LIST_TRAVERSE_SAFE_END;
00663       /* We take all of the combined whisper sources and combine them into the audio being written out */
00664       for (i = 0, data1 = middle_frame->data.ptr, data2 = combine_buf; i < samples; i++, data1++, data2++)
00665          ast_slinear_saturated_add(data1, data2);
00666       end_frame = middle_frame;
00667    }
00668 
00669    /* Pass off frame to manipulate audiohooks */
00670    if (!AST_LIST_EMPTY(&audiohook_list->manipulate_list)) {
00671       AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->manipulate_list, audiohook, list) {
00672          ast_audiohook_lock(audiohook);
00673          if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
00674             AST_LIST_REMOVE_CURRENT(list);
00675             ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00676             ast_audiohook_unlock(audiohook);
00677             /* We basically drop all of our links to the manipulate audiohook and prod it to do it's own destructive things */
00678             audiohook->manipulate_callback(audiohook, chan, NULL, direction);
00679             continue;
00680          }
00681          /* Feed in frame to manipulation. */
00682          if (audiohook->manipulate_callback(audiohook, chan, middle_frame, direction)) {
00683             /* XXX IGNORE FAILURE */
00684 
00685             /* If the manipulation fails then the frame will be returned in its original state.
00686              * Since there are potentially more manipulator callbacks in the list, no action should
00687              * be taken here to exit early. */
00688          }
00689          ast_audiohook_unlock(audiohook);
00690       }
00691       AST_LIST_TRAVERSE_SAFE_END;
00692       end_frame = middle_frame;
00693    }
00694 
00695    /* ---Part_3: Decide what to do with the end_frame (whether to transcode or not) */
00696    if (middle_frame == end_frame) {
00697       /* Middle frame was modified and became the end frame... let's see if we need to transcode */
00698       if (end_frame->subclass != start_frame->subclass) {
00699          if (out_translate->format != start_frame->subclass) {
00700             if (out_translate->trans_pvt)
00701                ast_translator_free_path(out_translate->trans_pvt);
00702             if (!(out_translate->trans_pvt = ast_translator_build_path(start_frame->subclass, AST_FORMAT_SLINEAR))) {
00703                /* We can't transcode this... drop our middle frame and return the original */
00704                ast_frfree(middle_frame);
00705                return start_frame;
00706             }
00707             out_translate->format = start_frame->subclass;
00708          }
00709          /* Transcode from our middle (signed linear) frame to new format of the frame that came in */
00710          if (!(end_frame = ast_translate(out_translate->trans_pvt, middle_frame, 0))) {
00711             /* Failed to transcode the frame... drop it and return the original */
00712             ast_frfree(middle_frame);
00713             return start_frame;
00714          }
00715          /* Here's the scoop... middle frame is no longer of use to us */
00716          ast_frfree(middle_frame);
00717       }
00718    } else {
00719       /* No frame was modified, we can just drop our middle frame and pass the frame we got in out */
00720       ast_frfree(middle_frame);
00721    }
00722 
00723    return end_frame;
00724 }

static struct ast_frame* audiohook_read_frame_both ( struct ast_audiohook audiohook,
size_t  samples 
) [static]

Definition at line 197 of file audiohook.c.

References ast_debug, AST_FORMAT_SLINEAR, AST_FRAME_VOICE, ast_log(), ast_slinear_saturated_divide(), ast_slinear_saturated_multiply(), ast_slinfactory_available(), ast_slinfactory_read(), ast_tvdiff_ms(), ast_tvnow(), ast_frame::frametype, LOG_DEBUG, option_debug, ast_audiohook::options, ast_audiohook::read_factory, ast_audiohook::read_time, ast_audiohook_options::read_volume, ast_audiohook::write_factory, ast_audiohook::write_time, and ast_audiohook_options::write_volume.

Referenced by ast_audiohook_read_frame().

00198 {
00199    int i = 0, usable_read, usable_write;
00200    short buf1[samples], buf2[samples], *read_buf = NULL, *write_buf = NULL, *final_buf = NULL, *data1 = NULL, *data2 = NULL;
00201    struct ast_frame frame = {
00202       .frametype = AST_FRAME_VOICE,
00203       .subclass = AST_FORMAT_SLINEAR,
00204       .data.ptr = NULL,
00205       .datalen = sizeof(buf1),
00206       .samples = samples,
00207    };
00208 
00209    /* Make sure both factories have the required samples */
00210    usable_read = (ast_slinfactory_available(&audiohook->read_factory) >= samples ? 1 : 0);
00211    usable_write = (ast_slinfactory_available(&audiohook->write_factory) >= samples ? 1 : 0);
00212 
00213    if (!usable_read && !usable_write) {
00214       /* If both factories are unusable bail out */
00215       ast_debug(1, "Read factory %p and write factory %p both fail to provide %zd samples\n", &audiohook->read_factory, &audiohook->write_factory, samples);
00216       return NULL;
00217    }
00218 
00219    /* If we want to provide only a read factory make sure we aren't waiting for other audio */
00220    if (usable_read && !usable_write && (ast_tvdiff_ms(ast_tvnow(), audiohook->write_time) < (samples/8)*2)) {
00221       ast_debug(3, "Write factory %p was pretty quick last time, waiting for them.\n", &audiohook->write_factory);
00222       return NULL;
00223    }
00224 
00225    /* If we want to provide only a write factory make sure we aren't waiting for other audio */
00226    if (usable_write && !usable_read && (ast_tvdiff_ms(ast_tvnow(), audiohook->read_time) < (samples/8)*2)) {
00227       ast_debug(3, "Read factory %p was pretty quick last time, waiting for them.\n", &audiohook->read_factory);
00228       return NULL;
00229    }
00230 
00231    /* Start with the read factory... if there are enough samples, read them in */
00232    if (usable_read) {
00233       if (ast_slinfactory_read(&audiohook->read_factory, buf1, samples)) {
00234          read_buf = buf1;
00235          /* Adjust read volume if need be */
00236          if (audiohook->options.read_volume) {
00237             int count = 0;
00238             short adjust_value = abs(audiohook->options.read_volume);
00239             for (count = 0; count < samples; count++) {
00240                if (audiohook->options.read_volume > 0)
00241                   ast_slinear_saturated_multiply(&buf1[count], &adjust_value);
00242                else if (audiohook->options.read_volume < 0)
00243                   ast_slinear_saturated_divide(&buf1[count], &adjust_value);
00244             }
00245          }
00246       }
00247    } else if (option_debug)
00248       ast_log(LOG_DEBUG, "Failed to get %d samples from read factory %p\n", (int)samples, &audiohook->read_factory);
00249 
00250    /* Move on to the write factory... if there are enough samples, read them in */
00251    if (usable_write) {
00252       if (ast_slinfactory_read(&audiohook->write_factory, buf2, samples)) {
00253          write_buf = buf2;
00254          /* Adjust write volume if need be */
00255          if (audiohook->options.write_volume) {
00256             int count = 0;
00257             short adjust_value = abs(audiohook->options.write_volume);
00258             for (count = 0; count < samples; count++) {
00259                if (audiohook->options.write_volume > 0)
00260                   ast_slinear_saturated_multiply(&buf2[count], &adjust_value);
00261                else if (audiohook->options.write_volume < 0)
00262                   ast_slinear_saturated_divide(&buf2[count], &adjust_value);
00263             }
00264          }
00265       }
00266    } else if (option_debug)
00267       ast_log(LOG_DEBUG, "Failed to get %d samples from write factory %p\n", (int)samples, &audiohook->write_factory);
00268 
00269    /* Basically we figure out which buffer to use... and if mixing can be done here */
00270    if (!read_buf && !write_buf)
00271       return NULL;
00272    else if (read_buf && write_buf) {
00273       for (i = 0, data1 = read_buf, data2 = write_buf; i < samples; i++, data1++, data2++)
00274          ast_slinear_saturated_add(data1, data2);
00275       final_buf = buf1;
00276    } else if (read_buf)
00277       final_buf = buf1;
00278    else if (write_buf)
00279       final_buf = buf2;
00280 
00281    /* Make the final buffer part of the frame, so it gets duplicated fine */
00282    frame.data.ptr = final_buf;
00283 
00284    /* Yahoo, a combined copy of the audio! */
00285    return ast_frdup(&frame);
00286 }

static struct ast_frame* audiohook_read_frame_single ( struct ast_audiohook audiohook,
size_t  samples,
enum ast_audiohook_direction  direction 
) [static]

Definition at line 169 of file audiohook.c.

References AST_AUDIOHOOK_DIRECTION_READ, AST_FORMAT_SLINEAR, ast_frame_adjust_volume(), AST_FRAME_VOICE, ast_frdup(), ast_slinfactory_available(), ast_slinfactory_read(), buf, ast_frame::frametype, ast_audiohook::options, ast_audiohook::read_factory, ast_audiohook_options::read_volume, ast_audiohook::write_factory, and ast_audiohook_options::write_volume.

Referenced by ast_audiohook_read_frame().

00170 {
00171    struct ast_slinfactory *factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_factory : &audiohook->write_factory);
00172    int vol = (direction == AST_AUDIOHOOK_DIRECTION_READ ? audiohook->options.read_volume : audiohook->options.write_volume);
00173    short buf[samples];
00174    struct ast_frame frame = {
00175       .frametype = AST_FRAME_VOICE,
00176       .subclass = AST_FORMAT_SLINEAR,
00177       .data.ptr = buf,
00178       .datalen = sizeof(buf),
00179       .samples = samples,
00180    };
00181 
00182    /* Ensure the factory is able to give us the samples we want */
00183    if (samples > ast_slinfactory_available(factory))
00184       return NULL;
00185    
00186    /* Read data in from factory */
00187    if (!ast_slinfactory_read(factory, buf, samples))
00188       return NULL;
00189 
00190    /* If a volume adjustment needs to be applied apply it */
00191    if (vol)
00192       ast_frame_adjust_volume(&frame, vol);
00193 
00194    return ast_frdup(&frame);
00195 }

static int audiohook_volume_callback ( struct ast_audiohook audiohook,
struct ast_channel chan,
struct ast_frame frame,
enum ast_audiohook_direction  direction 
) [static]

Helper function which actually gets called by audiohooks to perform the adjustment.

Parameters:
audiohook Audiohook attached to the channel
chan Channel we are attached to
frame Frame of audio we want to manipulate
direction Direction the audio came in from
Returns:
Returns 0 on success, -1 on failure

Definition at line 878 of file audiohook.c.

References AST_AUDIOHOOK_DIRECTION_READ, AST_AUDIOHOOK_DIRECTION_WRITE, AST_AUDIOHOOK_STATUS_DONE, ast_channel_datastore_find(), ast_frame_adjust_volume(), audiohook_volume::audiohook, audiohook_volume_datastore, chan, ast_datastore::data, audiohook_volume::read_adjustment, ast_audiohook::status, and audiohook_volume::write_adjustment.

Referenced by audiohook_volume_get().

00879 {
00880    struct ast_datastore *datastore = NULL;
00881    struct audiohook_volume *audiohook_volume = NULL;
00882    int *gain = NULL;
00883 
00884    /* If the audiohook is shutting down don't even bother */
00885    if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) {
00886       return 0;
00887    }
00888 
00889    /* Try to find the datastore containg adjustment information, if we can't just bail out */
00890    if (!(datastore = ast_channel_datastore_find(chan, &audiohook_volume_datastore, NULL))) {
00891       return 0;
00892    }
00893 
00894    audiohook_volume = datastore->data;
00895 
00896    /* Based on direction grab the appropriate adjustment value */
00897    if (direction == AST_AUDIOHOOK_DIRECTION_READ) {
00898       gain = &audiohook_volume->read_adjustment;
00899    } else if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) {
00900       gain = &audiohook_volume->write_adjustment;
00901    }
00902 
00903    /* If an adjustment value is present modify the frame */
00904    if (gain && *gain) {
00905       ast_frame_adjust_volume(frame, *gain);
00906    }
00907 
00908    return 0;
00909 }

static void audiohook_volume_destroy ( void *  data  )  [static]

Callback used to destroy the audiohook volume datastore.

Parameters:
data Volume information structure
Returns:
Returns nothing

Definition at line 852 of file audiohook.c.

References ast_audiohook_destroy(), ast_free, and audiohook_volume::audiohook.

00853 {
00854    struct audiohook_volume *audiohook_volume = data;
00855 
00856    /* Destroy the audiohook as it is no longer in use */
00857    ast_audiohook_destroy(&audiohook_volume->audiohook);
00858 
00859    /* Finally free ourselves, we are of no more use */
00860    ast_free(audiohook_volume);
00861 
00862    return;
00863 }

static struct audiohook_volume* audiohook_volume_get ( struct ast_channel chan,
int  create 
) [static]

Helper function which finds and optionally creates an audiohook_volume_datastore datastore on a channel.

Parameters:
chan Channel to look on
create Whether to create the datastore if not found
Returns:
Returns audiohook_volume structure on success, NULL on failure

Definition at line 916 of file audiohook.c.

References ast_audiohook_attach(), ast_audiohook_init(), AST_AUDIOHOOK_TYPE_MANIPULATE, ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_datastore_alloc, ast_datastore_free(), audiohook_volume_callback(), audiohook_volume_datastore, chan, and ast_datastore::data.

Referenced by ast_audiohook_volume_adjust(), ast_audiohook_volume_get(), and ast_audiohook_volume_set().

00917 {
00918    struct ast_datastore *datastore = NULL;
00919    struct audiohook_volume *audiohook_volume = NULL;
00920 
00921    /* If we are able to find the datastore return the contents (which is actually an audiohook_volume structure) */
00922    if ((datastore = ast_channel_datastore_find(chan, &audiohook_volume_datastore, NULL))) {
00923       return datastore->data;
00924    }
00925 
00926    /* If we are not allowed to create a datastore or if we fail to create a datastore, bail out now as we have nothing for them */
00927    if (!create || !(datastore = ast_datastore_alloc(&audiohook_volume_datastore, NULL))) {
00928       return NULL;
00929    }
00930 
00931    /* Create a new audiohook_volume structure to contain our adjustments and audiohook */
00932    if (!(audiohook_volume = ast_calloc(1, sizeof(*audiohook_volume)))) {
00933       ast_datastore_free(datastore);
00934       return NULL;
00935    }
00936 
00937    /* Setup our audiohook structure so we can manipulate the audio */
00938    ast_audiohook_init(&audiohook_volume->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Volume");
00939    audiohook_volume->audiohook.manipulate_callback = audiohook_volume_callback;
00940 
00941    /* Attach the audiohook_volume blob to the datastore and attach to the channel */
00942    datastore->data = audiohook_volume;
00943    ast_channel_datastore_add(chan, datastore);
00944 
00945    /* All is well... put the audiohook into motion */
00946    ast_audiohook_attach(chan, &audiohook_volume->audiohook);
00947 
00948    return audiohook_volume;
00949 }

static struct ast_frame* dtmf_audiohook_write_list ( struct ast_channel chan,
struct ast_audiohook_list audiohook_list,
enum ast_audiohook_direction  direction,
struct ast_frame frame 
) [static]

Pass a DTMF frame off to be handled by the audiohook core.

Parameters:
chan Channel that the list is coming off of
audiohook_list List of audiohooks
direction Direction frame is coming in from
frame The frame itself
Returns:
Return frame on success, NULL on failure

Definition at line 553 of file audiohook.c.

References ast_audiohook_lock, AST_AUDIOHOOK_STATUS_DONE, AST_AUDIOHOOK_STATUS_RUNNING, ast_audiohook_unlock, ast_audiohook_update_status(), AST_AUDIOHOOK_WANTS_DTMF, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_test_flag, chan, ast_audiohook::list, ast_audiohook::manipulate_callback, ast_audiohook_list::manipulate_list, and ast_audiohook::status.

Referenced by ast_audiohook_write_list().

00554 {
00555    struct ast_audiohook *audiohook = NULL;
00556 
00557    AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->manipulate_list, audiohook, list) {
00558       ast_audiohook_lock(audiohook);
00559       if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
00560          AST_LIST_REMOVE_CURRENT(list);
00561          ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
00562          ast_audiohook_unlock(audiohook);
00563          audiohook->manipulate_callback(audiohook, NULL, NULL, 0);
00564          continue;
00565       }
00566       if (ast_test_flag(audiohook, AST_AUDIOHOOK_WANTS_DTMF))
00567          audiohook->manipulate_callback(audiohook, chan, frame, direction);
00568       ast_audiohook_unlock(audiohook);
00569    }
00570    AST_LIST_TRAVERSE_SAFE_END;
00571 
00572    return frame;
00573 }

static struct ast_audiohook* find_audiohook_by_source ( struct ast_audiohook_list audiohook_list,
const char *  source 
) [static]

find an audiohook based on its source

Parameters:
audiohook_list The list of audiohooks to search in
source The source of the audiohook we wish to find
Returns:
Return the corresponding audiohook or NULL if it cannot be found.

Definition at line 440 of file audiohook.c.

References AST_LIST_TRAVERSE, ast_audiohook::list, ast_audiohook_list::manipulate_list, ast_audiohook::source, ast_audiohook_list::spy_list, and ast_audiohook_list::whisper_list.

Referenced by ast_audiohook_detach_source(), and ast_audiohook_move_by_source().

00441 {
00442    struct ast_audiohook *audiohook = NULL;
00443 
00444    AST_LIST_TRAVERSE(&audiohook_list->spy_list, audiohook, list) {
00445       if (!strcasecmp(audiohook->source, source))
00446          return audiohook;
00447    }
00448 
00449    AST_LIST_TRAVERSE(&audiohook_list->whisper_list, audiohook, list) {
00450       if (!strcasecmp(audiohook->source, source))
00451          return audiohook;
00452    }
00453 
00454    AST_LIST_TRAVERSE(&audiohook_list->manipulate_list, audiohook, list) {
00455       if (!strcasecmp(audiohook->source, source))
00456          return audiohook;
00457    }
00458 
00459    return NULL;
00460 }


Variable Documentation

struct ast_datastore_info audiohook_volume_datastore [static]

Initial value:

 {
   .type = "Volume",
   .destroy = audiohook_volume_destroy,
}
Datastore used to store audiohook volume information.

Definition at line 866 of file audiohook.c.

Referenced by audiohook_volume_callback(), and audiohook_volume_get().


Generated on Wed Aug 18 22:34:05 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7