Thu Apr 28 2011 16:56:55

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"
Include dependency graph for audiohook.c:

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.
struct 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.
struct 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_audiohook_write_list_empty (struct ast_audiohook_list *audiohook_list)
 determines if a audiohook_list is empty or not.
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:
chanChannel
audiohookAudiohook 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, 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().

{
   ast_channel_lock(chan);

   if (!chan->audiohooks) {
      /* Whoops... allocate a new structure */
      if (!(chan->audiohooks = ast_calloc(1, sizeof(*chan->audiohooks)))) {
         ast_channel_unlock(chan);
         return -1;
      }
      AST_LIST_HEAD_INIT_NOLOCK(&chan->audiohooks->spy_list);
      AST_LIST_HEAD_INIT_NOLOCK(&chan->audiohooks->whisper_list);
      AST_LIST_HEAD_INIT_NOLOCK(&chan->audiohooks->manipulate_list);
   }

   /* Drop into respective list */
   if (audiohook->type == AST_AUDIOHOOK_TYPE_SPY)
      AST_LIST_INSERT_TAIL(&chan->audiohooks->spy_list, audiohook, list);
   else if (audiohook->type == AST_AUDIOHOOK_TYPE_WHISPER)
      AST_LIST_INSERT_TAIL(&chan->audiohooks->whisper_list, audiohook, list);
   else if (audiohook->type == AST_AUDIOHOOK_TYPE_MANIPULATE)
      AST_LIST_INSERT_TAIL(&chan->audiohooks->manipulate_list, audiohook, list);

   /* Change status over to running since it is now attached */
   ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_RUNNING);

   ast_channel_unlock(chan);

   return 0;
}
int ast_audiohook_destroy ( struct ast_audiohook audiohook)

Destroys an audiohook structure.

Parameters:
audiohookAudiohook 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().

{
   /* Drop the factories used by this audiohook type */
   switch (audiohook->type) {
   case AST_AUDIOHOOK_TYPE_SPY:
      ast_slinfactory_destroy(&audiohook->read_factory);
   case AST_AUDIOHOOK_TYPE_WHISPER:
      ast_slinfactory_destroy(&audiohook->write_factory);
      break;
   default:
      break;
   }

   /* Destroy translation path if present */
   if (audiohook->trans_pvt)
      ast_translator_free_path(audiohook->trans_pvt);

   /* Lock and trigger be gone! */
   ast_cond_destroy(&audiohook->trigger);
   ast_mutex_destroy(&audiohook->lock);

   return 0;
}
int ast_audiohook_detach ( struct ast_audiohook audiohook)

Detach audiohook from channel.

Parameters:
audiohookAudiohook 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().

{
   if (audiohook->status == AST_AUDIOHOOK_STATUS_NEW || audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
      return 0;

   ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_SHUTDOWN);

   while (audiohook->status != AST_AUDIOHOOK_STATUS_DONE)
      ast_audiohook_trigger_wait(audiohook);

   return 0;
}
int ast_audiohook_detach_list ( struct ast_audiohook_list audiohook_list)

Detach audiohooks from list and destroy said list.

Parameters:
audiohook_listList 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::manipulate_callback, 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_read(), ast_hangup(), and ast_write().

{
   int i = 0;
   struct ast_audiohook *audiohook = NULL;

   /* Drop any spies */
   while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->spy_list, list))) {
      ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
   }

   /* Drop any whispering sources */
   while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->whisper_list, list))) {
      ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
   }

   /* Drop any manipulaters */
   while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->manipulate_list, list))) {
      ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
      audiohook->manipulate_callback(audiohook, NULL, NULL, 0);
   }

   /* Drop translation paths if present */
   for (i = 0; i < 2; i++) {
      if (audiohook_list->in_translate[i].trans_pvt)
         ast_translator_free_path(audiohook_list->in_translate[i].trans_pvt);
      if (audiohook_list->out_translate[i].trans_pvt)
         ast_translator_free_path(audiohook_list->out_translate[i].trans_pvt);
   }
   
   /* Free ourselves */
   ast_free(audiohook_list);

   return 0;
}
int ast_audiohook_detach_source ( struct ast_channel chan,
const char *  source 
)

Detach specified source audiohook from channel.

Parameters:
chanChannel to detach from
sourceName 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, find_audiohook_by_source(), and ast_audiohook::status.

Referenced by handle_cli_mixmonitor(), and stop_mixmonitor_exec().

{
   struct ast_audiohook *audiohook = NULL;

   ast_channel_lock(chan);

   /* Ensure the channel has audiohooks on it */
   if (!chan->audiohooks) {
      ast_channel_unlock(chan);
      return -1;
   }

   audiohook = find_audiohook_by_source(chan->audiohooks, source);

   ast_channel_unlock(chan);

   if (audiohook && audiohook->status != AST_AUDIOHOOK_STATUS_DONE)
      ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_SHUTDOWN);

   return (audiohook ? 0 : -1);
}
int ast_audiohook_init ( struct ast_audiohook audiohook,
enum ast_audiohook_type  type,
const char *  source 
)

Initialize an audiohook structure.

Parameters:
audiohookAudiohook 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(), ast_slinfactory_init(), and type.

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

{
   /* Need to keep the type and source */
   audiohook->type = type;
   audiohook->source = source;

   /* Initialize lock that protects our audiohook */
   ast_mutex_init(&audiohook->lock);
   ast_cond_init(&audiohook->trigger, NULL);

   /* Setup the factories that are needed for this audiohook type */
   switch (type) {
   case AST_AUDIOHOOK_TYPE_SPY:
      ast_slinfactory_init(&audiohook->read_factory);
   case AST_AUDIOHOOK_TYPE_WHISPER:
      ast_slinfactory_init(&audiohook->write_factory);
      break;
   default:
      break;
   }

   /* Since we are just starting out... this audiohook is new */
   ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_NEW);

   return 0;
}
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_chanThe source of the audiohook to move
new_chanThe destination to which we want the audiohook to move
sourceThe 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().

{
   struct ast_audiohook *audiohook;
   enum ast_audiohook_status oldstatus;

   if (!old_chan->audiohooks || !(audiohook = find_audiohook_by_source(old_chan->audiohooks, source))) {
      return;
   }

   /* By locking both channels and the audiohook, we can assure that
    * another thread will not have a chance to read the audiohook's status
    * as done, even though ast_audiohook_remove signals the trigger
    * condition.
    */
   ast_audiohook_lock(audiohook);
   oldstatus = audiohook->status;

   ast_audiohook_remove(old_chan, audiohook);
   ast_audiohook_attach(new_chan, audiohook);

   audiohook->status = oldstatus;
   ast_audiohook_unlock(audiohook);
}
struct ast_frame* ast_audiohook_read_frame ( struct ast_audiohook audiohook,
size_t  samples,
enum ast_audiohook_direction  direction,
int  format 
) [read]

Reads a frame in from the audiohook structure.

Parameters:
audiohookAudiohook structure
samplesNumber of samples wanted
directionDirection the audio frame came from
formatFormat 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(), ast_audiohook::format, read_frame(), and ast_audiohook::trans_pvt.

Referenced by mixmonitor_thread(), and spy_generate().

{
   struct ast_frame *read_frame = NULL, *final_frame = NULL;

   if (!(read_frame = (direction == AST_AUDIOHOOK_DIRECTION_BOTH ? audiohook_read_frame_both(audiohook, samples) : audiohook_read_frame_single(audiohook, samples, direction))))
      return NULL;

   /* If they don't want signed linear back out, we'll have to send it through the translation path */
   if (format != AST_FORMAT_SLINEAR) {
      /* Rebuild translation path if different format then previously */
      if (audiohook->format != format) {
         if (audiohook->trans_pvt) {
            ast_translator_free_path(audiohook->trans_pvt);
            audiohook->trans_pvt = NULL;
         }
         /* 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 */
         if (!(audiohook->trans_pvt = ast_translator_build_path(format, AST_FORMAT_SLINEAR))) {
            ast_frfree(read_frame);
            return NULL;
         }
      }
      /* Convert to requested format, and allow the read in frame to be freed */
      final_frame = ast_translate(audiohook->trans_pvt, read_frame, 1);
   } else {
      final_frame = read_frame;
   }

   return final_frame;
}
int ast_audiohook_remove ( struct ast_channel chan,
struct ast_audiohook audiohook 
)

Remove an audiohook from a specified channel.

Parameters:
chanChannel to remove from
audiohookAudiohook 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, 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().

{
   ast_channel_lock(chan);

   if (!chan->audiohooks) {
      ast_channel_unlock(chan);
      return -1;
   }

   if (audiohook->type == AST_AUDIOHOOK_TYPE_SPY)
      AST_LIST_REMOVE(&chan->audiohooks->spy_list, audiohook, list);
   else if (audiohook->type == AST_AUDIOHOOK_TYPE_WHISPER)
      AST_LIST_REMOVE(&chan->audiohooks->whisper_list, audiohook, list);
   else if (audiohook->type == AST_AUDIOHOOK_TYPE_MANIPULATE)
      AST_LIST_REMOVE(&chan->audiohooks->manipulate_list, audiohook, list);

   ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);

   ast_channel_unlock(chan);

   return 0;
}
void ast_audiohook_trigger_wait ( struct ast_audiohook audiohook)

Wait for audiohook trigger to be triggered.

Parameters:
audiohookAudiohook to wait on

Definition at line 758 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().

{
   struct timeval wait;
   struct timespec ts;

   wait = ast_tvadd(ast_tvnow(), ast_samp2tv(50000, 1000));
   ts.tv_sec = wait.tv_sec;
   ts.tv_nsec = wait.tv_usec * 1000;
   
   ast_cond_timedwait(&audiohook->trigger, &audiohook->lock, &ts);
   
   return;
}
void ast_audiohook_update_status ( struct ast_audiohook audiohook,
enum ast_audiohook_status  status 
)

Update audiohook's status.

Parameters:
audiohookstatus enum
audiohookAudiohook 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(), status, 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().

{
   ast_audiohook_lock(audiohook);
   if (audiohook->status != AST_AUDIOHOOK_STATUS_DONE) {
      audiohook->status = status;
      ast_cond_signal(&audiohook->trigger);
   }
   ast_audiohook_unlock(audiohook);
}
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:
chanChannel to muck with
directionDirection to increase
volumeValue to adjust the adjustment by
Returns:
Returns 0 on success, -1 on failure

Definition at line 1018 of file audiohook.c.

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

Referenced by menu_callback().

{
   struct audiohook_volume *audiohook_volume = NULL;

   /* Attempt to find the audiohook volume information, and create an audiohook if none exists */
   if (!(audiohook_volume = audiohook_volume_get(chan, 1))) {
      return -1;
   }

   /* Based on the direction change the specific adjustment value */
   if (direction == AST_AUDIOHOOK_DIRECTION_READ || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
      audiohook_volume->read_adjustment += volume;
   }
   if (direction == AST_AUDIOHOOK_DIRECTION_WRITE || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
      audiohook_volume->write_adjustment += volume;
   }

   return 0;
}
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:
chanChannel to retrieve volume adjustment from
directionDirection to retrieve
Returns:
Returns adjustment value

Definition at line 992 of file audiohook.c.

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

Referenced by confbridge_exec().

{
   struct audiohook_volume *audiohook_volume = NULL;
   int adjustment = 0;

   /* Attempt to find the audiohook volume information, but do not create it as we only want to look at the values */
   if (!(audiohook_volume = audiohook_volume_get(chan, 0))) {
      return 0;
   }

   /* Grab the adjustment value based on direction given */
   if (direction == AST_AUDIOHOOK_DIRECTION_READ) {
      adjustment = audiohook_volume->read_adjustment;
   } else if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) {
      adjustment = audiohook_volume->write_adjustment;
   }

   return adjustment;
}
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:
chanChannel to muck with
directionDirection to set on
volumeValue to adjust the volume by
Returns:
Returns 0 on success, -1 on failure

Definition at line 967 of file audiohook.c.

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

Referenced by confbridge_exec().

{
   struct audiohook_volume *audiohook_volume = NULL;

   /* Attempt to find the audiohook volume information, but only create it if we are not setting the adjustment value to zero */
   if (!(audiohook_volume = audiohook_volume_get(chan, (volume ? 1 : 0)))) {
      return -1;
   }

   /* Now based on the direction set the proper value */
   if (direction == AST_AUDIOHOOK_DIRECTION_READ || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
      audiohook_volume->read_adjustment = volume;
   }
   if (direction == AST_AUDIOHOOK_DIRECTION_WRITE || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
      audiohook_volume->write_adjustment = volume;
   }

   return 0;
}
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:
audiohookAudiohook structure
directionDirection the audio frame came from
frameFrame 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().

{
   struct ast_slinfactory *factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_factory : &audiohook->write_factory);
   struct ast_slinfactory *other_factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->write_factory : &audiohook->read_factory);
   struct timeval *rwtime = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_time : &audiohook->write_time), previous_time = *rwtime;
   int our_factory_samples;
   int our_factory_ms;
   int other_factory_samples;
   int other_factory_ms;

   /* Update last feeding time to be current */
   *rwtime = ast_tvnow();

   our_factory_samples = ast_slinfactory_available(factory);
   our_factory_ms = ast_tvdiff_ms(*rwtime, previous_time) + (our_factory_samples / 8);
   other_factory_samples = ast_slinfactory_available(other_factory);
   other_factory_ms = other_factory_samples / 8;

   if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC) && other_factory_samples && (our_factory_ms - other_factory_ms > AST_AUDIOHOOK_SYNC_TOLERANCE)) {
      if (option_debug)
         ast_log(LOG_DEBUG, "Flushing audiohook %p so it remains in sync\n", audiohook);
      ast_slinfactory_flush(factory);
      ast_slinfactory_flush(other_factory);
   }

   if (ast_test_flag(audiohook, AST_AUDIOHOOK_SMALL_QUEUE) && (our_factory_samples > 640 || other_factory_samples > 640)) {
      if (option_debug) {
         ast_log(LOG_DEBUG, "Audiohook %p has stale audio in its factories. Flushing them both\n", audiohook);
      }
      ast_slinfactory_flush(factory);
      ast_slinfactory_flush(other_factory);
   }

   /* Write frame out to respective factory */
   ast_slinfactory_feed(factory, frame);

   /* If we need to notify the respective handler of this audiohook, do so */
   if ((ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_MODE) == AST_AUDIOHOOK_TRIGGER_READ) && (direction == AST_AUDIOHOOK_DIRECTION_READ)) {
      ast_cond_signal(&audiohook->trigger);
   } else if ((ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_MODE) == AST_AUDIOHOOK_TRIGGER_WRITE) && (direction == AST_AUDIOHOOK_DIRECTION_WRITE)) {
      ast_cond_signal(&audiohook->trigger);
   } else if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC)) {
      ast_cond_signal(&audiohook->trigger);
   }

   return 0;
}
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 
) [read]

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

Parameters:
chanChannel that the list is coming off of
audiohook_listList of audiohooks
directionDirection frame is coming in from
frameThe frame itself
Returns:
Return frame on success, NULL on failure

Definition at line 744 of file audiohook.c.

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

Referenced by __ast_read(), and ast_write().

{
   /* Pass off frame to it's respective list write function */
   if (frame->frametype == AST_FRAME_VOICE)
      return audio_audiohook_write_list(chan, audiohook_list, direction, frame);
   else if (frame->frametype == AST_FRAME_DTMF)
      return dtmf_audiohook_write_list(chan, audiohook_list, direction, frame);
   else
      return frame;
}
int ast_audiohook_write_list_empty ( struct ast_audiohook_list audiohook_list)

determines if a audiohook_list is empty or not.

retval 0 false, 1 true

Definition at line 726 of file audiohook.c.

References AST_LIST_EMPTY, ast_audiohook_list::manipulate_list, ast_audiohook_list::spy_list, and ast_audiohook_list::whisper_list.

Referenced by __ast_read(), and ast_write().

{
   if (AST_LIST_EMPTY(&audiohook_list->spy_list) &&
      AST_LIST_EMPTY(&audiohook_list->whisper_list) &&
      AST_LIST_EMPTY(&audiohook_list->manipulate_list)) {

      return 1;
   }
   return 0;
}
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:
chanThe channel on which to find the spies
sourceThe audiohook's source
typeThe type of audiohook
Returns:
Return the number of audiohooks which are from the source specified

Note: Function performs nlocking.

Definition at line 773 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, ast_audiohook::list, LOG_DEBUG, ast_audiohook_list::manipulate_list, ast_audiohook::source, ast_audiohook_list::spy_list, and ast_audiohook_list::whisper_list.

Referenced by builtin_automixmonitor().

{
   int count = 0;
   struct ast_audiohook *ah = NULL;

   if (!chan->audiohooks)
      return -1;

   switch (type) {
      case AST_AUDIOHOOK_TYPE_SPY:
         AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->spy_list, ah, list) {
            if (!strcmp(ah->source, source)) {
               count++;
            }
         }
         AST_LIST_TRAVERSE_SAFE_END;
         break;
      case AST_AUDIOHOOK_TYPE_WHISPER:
         AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->whisper_list, ah, list) {
            if (!strcmp(ah->source, source)) {
               count++;
            }
         }
         AST_LIST_TRAVERSE_SAFE_END;
         break;
      case AST_AUDIOHOOK_TYPE_MANIPULATE:
         AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->manipulate_list, ah, list) {
            if (!strcmp(ah->source, source)) {
               count++;
            }
         }
         AST_LIST_TRAVERSE_SAFE_END;
         break;
      default:
         ast_log(LOG_DEBUG, "Invalid audiohook type supplied, (%d)\n", type);
         return -1;
   }

   return count;
}
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:
chanThe channel on which to find the spies
sourceThe source of the audiohook
typeThe 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 815 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, ast_audiohook::list, LOG_DEBUG, 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().

{
   int count = 0;
   struct ast_audiohook *ah = NULL;
   if (!chan->audiohooks)
      return -1;

   switch (type) {
      case AST_AUDIOHOOK_TYPE_SPY:
         AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->spy_list, ah, list) {
            if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
               count++;
         }
         AST_LIST_TRAVERSE_SAFE_END;
         break;
      case AST_AUDIOHOOK_TYPE_WHISPER:
         AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->whisper_list, ah, list) {
            if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
               count++;
         }
         AST_LIST_TRAVERSE_SAFE_END;
         break;
      case AST_AUDIOHOOK_TYPE_MANIPULATE:
         AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->manipulate_list, ah, list) {
            if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
               count++;
         }
         AST_LIST_TRAVERSE_SAFE_END;
         break;
      default:
         ast_log(LOG_DEBUG, "Invalid audiohook type supplied, (%d)\n", type);
         return -1;
   }
   return count;
}
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, read]

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:
chanChannel that the list is coming off of
audiohook_listList of audiohooks
directionDirection frame is coming in from
frameThe 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(), 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().

{
   struct ast_audiohook_translate *in_translate = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook_list->in_translate[0] : &audiohook_list->in_translate[1]);
   struct ast_audiohook_translate *out_translate = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook_list->out_translate[0] : &audiohook_list->out_translate[1]);
   struct ast_frame *start_frame = frame, *middle_frame = frame, *end_frame = frame;
   struct ast_audiohook *audiohook = NULL;
   int samples = frame->samples;

   /* ---Part_1. translate start_frame to SLINEAR if necessary. */
   /* If the frame coming in is not signed linear we have to send it through the in_translate path */
   if (frame->subclass != AST_FORMAT_SLINEAR) {
      if (in_translate->format != frame->subclass) {
         if (in_translate->trans_pvt)
            ast_translator_free_path(in_translate->trans_pvt);
         if (!(in_translate->trans_pvt = ast_translator_build_path(AST_FORMAT_SLINEAR, frame->subclass)))
            return frame;
         in_translate->format = frame->subclass;
      }
      if (!(middle_frame = ast_translate(in_translate->trans_pvt, frame, 0)))
         return frame;
      samples = middle_frame->samples;
   }

   /* ---Part_2: Send middle_frame to spy and manipulator lists.  middle_frame is guaranteed to be SLINEAR here.*/
   /* Queue up signed linear frame to each spy */
   AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->spy_list, audiohook, list) {
      ast_audiohook_lock(audiohook);
      if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
         AST_LIST_REMOVE_CURRENT(list);
         ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
         ast_audiohook_unlock(audiohook);
         continue;
      }
      ast_audiohook_write_frame(audiohook, direction, middle_frame);
      ast_audiohook_unlock(audiohook);
   }
   AST_LIST_TRAVERSE_SAFE_END;

   /* If this frame is being written out to the channel then we need to use whisper sources */
   if (direction == AST_AUDIOHOOK_DIRECTION_WRITE && !AST_LIST_EMPTY(&audiohook_list->whisper_list)) {
      int i = 0;
      short read_buf[samples], combine_buf[samples], *data1 = NULL, *data2 = NULL;
      memset(&combine_buf, 0, sizeof(combine_buf));
      AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->whisper_list, audiohook, list) {
         ast_audiohook_lock(audiohook);
         if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
            AST_LIST_REMOVE_CURRENT(list);
            ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
            ast_audiohook_unlock(audiohook);
            continue;
         }
         if (ast_slinfactory_available(&audiohook->write_factory) >= samples && ast_slinfactory_read(&audiohook->write_factory, read_buf, samples)) {
            /* Take audio from this whisper source and combine it into our main buffer */
            for (i = 0, data1 = combine_buf, data2 = read_buf; i < samples; i++, data1++, data2++)
               ast_slinear_saturated_add(data1, data2);
         }
         ast_audiohook_unlock(audiohook);
      }
      AST_LIST_TRAVERSE_SAFE_END;
      /* We take all of the combined whisper sources and combine them into the audio being written out */
      for (i = 0, data1 = middle_frame->data.ptr, data2 = combine_buf; i < samples; i++, data1++, data2++)
         ast_slinear_saturated_add(data1, data2);
      end_frame = middle_frame;
   }

   /* Pass off frame to manipulate audiohooks */
   if (!AST_LIST_EMPTY(&audiohook_list->manipulate_list)) {
      AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->manipulate_list, audiohook, list) {
         ast_audiohook_lock(audiohook);
         if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
            AST_LIST_REMOVE_CURRENT(list);
            ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
            ast_audiohook_unlock(audiohook);
            /* We basically drop all of our links to the manipulate audiohook and prod it to do it's own destructive things */
            audiohook->manipulate_callback(audiohook, chan, NULL, direction);
            continue;
         }
         /* Feed in frame to manipulation. */
         if (audiohook->manipulate_callback(audiohook, chan, middle_frame, direction)) {
            /* XXX IGNORE FAILURE */

            /* If the manipulation fails then the frame will be returned in its original state.
             * Since there are potentially more manipulator callbacks in the list, no action should
             * be taken here to exit early. */
         }
         ast_audiohook_unlock(audiohook);
      }
      AST_LIST_TRAVERSE_SAFE_END;
      end_frame = middle_frame;
   }

   /* ---Part_3: Decide what to do with the end_frame (whether to transcode or not) */
   if (middle_frame == end_frame) {
      /* Middle frame was modified and became the end frame... let's see if we need to transcode */
      if (end_frame->subclass != start_frame->subclass) {
         if (out_translate->format != start_frame->subclass) {
            if (out_translate->trans_pvt)
               ast_translator_free_path(out_translate->trans_pvt);
            if (!(out_translate->trans_pvt = ast_translator_build_path(start_frame->subclass, AST_FORMAT_SLINEAR))) {
               /* We can't transcode this... drop our middle frame and return the original */
               ast_frfree(middle_frame);
               return start_frame;
            }
            out_translate->format = start_frame->subclass;
         }
         /* Transcode from our middle (signed linear) frame to new format of the frame that came in */
         if (!(end_frame = ast_translate(out_translate->trans_pvt, middle_frame, 0))) {
            /* Failed to transcode the frame... drop it and return the original */
            ast_frfree(middle_frame);
            return start_frame;
         }
         /* Here's the scoop... middle frame is no longer of use to us */
         ast_frfree(middle_frame);
      }
   } else {
      /* No frame was modified, we can just drop our middle frame and pass the frame we got in out */
      ast_frfree(middle_frame);
   }

   return end_frame;
}
static struct ast_frame* audiohook_read_frame_both ( struct ast_audiohook audiohook,
size_t  samples 
) [static, read]

Definition at line 197 of file audiohook.c.

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

Referenced by ast_audiohook_read_frame().

{
   int i = 0, usable_read, usable_write;
   short buf1[samples], buf2[samples], *read_buf = NULL, *write_buf = NULL, *final_buf = NULL, *data1 = NULL, *data2 = NULL;
   struct ast_frame frame = {
      .frametype = AST_FRAME_VOICE,
      .subclass = AST_FORMAT_SLINEAR,
      .data.ptr = NULL,
      .datalen = sizeof(buf1),
      .samples = samples,
   };

   /* Make sure both factories have the required samples */
   usable_read = (ast_slinfactory_available(&audiohook->read_factory) >= samples ? 1 : 0);
   usable_write = (ast_slinfactory_available(&audiohook->write_factory) >= samples ? 1 : 0);

   if (!usable_read && !usable_write) {
      /* If both factories are unusable bail out */
      ast_debug(1, "Read factory %p and write factory %p both fail to provide %zd samples\n", &audiohook->read_factory, &audiohook->write_factory, samples);
      return NULL;
   }

   /* If we want to provide only a read factory make sure we aren't waiting for other audio */
   if (usable_read && !usable_write && (ast_tvdiff_ms(ast_tvnow(), audiohook->write_time) < (samples/8)*2)) {
      ast_debug(3, "Write factory %p was pretty quick last time, waiting for them.\n", &audiohook->write_factory);
      return NULL;
   }

   /* If we want to provide only a write factory make sure we aren't waiting for other audio */
   if (usable_write && !usable_read && (ast_tvdiff_ms(ast_tvnow(), audiohook->read_time) < (samples/8)*2)) {
      ast_debug(3, "Read factory %p was pretty quick last time, waiting for them.\n", &audiohook->read_factory);
      return NULL;
   }

   /* Start with the read factory... if there are enough samples, read them in */
   if (usable_read) {
      if (ast_slinfactory_read(&audiohook->read_factory, buf1, samples)) {
         read_buf = buf1;
         /* Adjust read volume if need be */
         if (audiohook->options.read_volume) {
            int count = 0;
            short adjust_value = abs(audiohook->options.read_volume);
            for (count = 0; count < samples; count++) {
               if (audiohook->options.read_volume > 0)
                  ast_slinear_saturated_multiply(&buf1[count], &adjust_value);
               else if (audiohook->options.read_volume < 0)
                  ast_slinear_saturated_divide(&buf1[count], &adjust_value);
            }
         }
      }
   } else if (option_debug)
      ast_log(LOG_DEBUG, "Failed to get %d samples from read factory %p\n", (int)samples, &audiohook->read_factory);

   /* Move on to the write factory... if there are enough samples, read them in */
   if (usable_write) {
      if (ast_slinfactory_read(&audiohook->write_factory, buf2, samples)) {
         write_buf = buf2;
         /* Adjust write volume if need be */
         if (audiohook->options.write_volume) {
            int count = 0;
            short adjust_value = abs(audiohook->options.write_volume);
            for (count = 0; count < samples; count++) {
               if (audiohook->options.write_volume > 0)
                  ast_slinear_saturated_multiply(&buf2[count], &adjust_value);
               else if (audiohook->options.write_volume < 0)
                  ast_slinear_saturated_divide(&buf2[count], &adjust_value);
            }
         }
      }
   } else if (option_debug)
      ast_log(LOG_DEBUG, "Failed to get %d samples from write factory %p\n", (int)samples, &audiohook->write_factory);

   /* Basically we figure out which buffer to use... and if mixing can be done here */
   if (!read_buf && !write_buf)
      return NULL;
   else if (read_buf && write_buf) {
      for (i = 0, data1 = read_buf, data2 = write_buf; i < samples; i++, data1++, data2++)
         ast_slinear_saturated_add(data1, data2);
      final_buf = buf1;
   } else if (read_buf)
      final_buf = buf1;
   else if (write_buf)
      final_buf = buf2;

   /* Make the final buffer part of the frame, so it gets duplicated fine */
   frame.data.ptr = final_buf;

   /* Yahoo, a combined copy of the audio! */
   return ast_frdup(&frame);
}
static struct ast_frame* audiohook_read_frame_single ( struct ast_audiohook audiohook,
size_t  samples,
enum ast_audiohook_direction  direction 
) [static, read]

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

{
   struct ast_slinfactory *factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_factory : &audiohook->write_factory);
   int vol = (direction == AST_AUDIOHOOK_DIRECTION_READ ? audiohook->options.read_volume : audiohook->options.write_volume);
   short buf[samples];
   struct ast_frame frame = {
      .frametype = AST_FRAME_VOICE,
      .subclass = AST_FORMAT_SLINEAR,
      .data.ptr = buf,
      .datalen = sizeof(buf),
      .samples = samples,
   };

   /* Ensure the factory is able to give us the samples we want */
   if (samples > ast_slinfactory_available(factory))
      return NULL;
   
   /* Read data in from factory */
   if (!ast_slinfactory_read(factory, buf, samples))
      return NULL;

   /* If a volume adjustment needs to be applied apply it */
   if (vol)
      ast_frame_adjust_volume(&frame, vol);

   return ast_frdup(&frame);
}
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:
audiohookAudiohook attached to the channel
chanChannel we are attached to
frameFrame of audio we want to manipulate
directionDirection the audio came in from
Returns:
Returns 0 on success, -1 on failure

Definition at line 888 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(), ast_datastore::data, audiohook_volume::read_adjustment, ast_audiohook::status, and audiohook_volume::write_adjustment.

Referenced by audiohook_volume_get().

{
   struct ast_datastore *datastore = NULL;
   struct audiohook_volume *audiohook_volume = NULL;
   int *gain = NULL;

   /* If the audiohook is shutting down don't even bother */
   if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) {
      return 0;
   }

   /* Try to find the datastore containg adjustment information, if we can't just bail out */
   if (!(datastore = ast_channel_datastore_find(chan, &audiohook_volume_datastore, NULL))) {
      return 0;
   }

   audiohook_volume = datastore->data;

   /* Based on direction grab the appropriate adjustment value */
   if (direction == AST_AUDIOHOOK_DIRECTION_READ) {
      gain = &audiohook_volume->read_adjustment;
   } else if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) {
      gain = &audiohook_volume->write_adjustment;
   }

   /* If an adjustment value is present modify the frame */
   if (gain && *gain) {
      ast_frame_adjust_volume(frame, *gain);
   }

   return 0;
}
static void audiohook_volume_destroy ( void *  data) [static]

Callback used to destroy the audiohook volume datastore.

Parameters:
dataVolume information structure
Returns:
Returns nothing

Definition at line 862 of file audiohook.c.

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

{
   struct audiohook_volume *audiohook_volume = data;

   /* Destroy the audiohook as it is no longer in use */
   ast_audiohook_destroy(&audiohook_volume->audiohook);

   /* Finally free ourselves, we are of no more use */
   ast_free(audiohook_volume);

   return;
}
static struct audiohook_volume* audiohook_volume_get ( struct ast_channel chan,
int  create 
) [static, read]

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

Parameters:
chanChannel to look on
createWhether to create the datastore if not found
Returns:
Returns audiohook_volume structure on success, NULL on failure

Definition at line 926 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::audiohook, audiohook_volume_callback(), ast_datastore::data, and ast_audiohook::manipulate_callback.

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

{
   struct ast_datastore *datastore = NULL;
   struct audiohook_volume *audiohook_volume = NULL;

   /* If we are able to find the datastore return the contents (which is actually an audiohook_volume structure) */
   if ((datastore = ast_channel_datastore_find(chan, &audiohook_volume_datastore, NULL))) {
      return datastore->data;
   }

   /* 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 */
   if (!create || !(datastore = ast_datastore_alloc(&audiohook_volume_datastore, NULL))) {
      return NULL;
   }

   /* Create a new audiohook_volume structure to contain our adjustments and audiohook */
   if (!(audiohook_volume = ast_calloc(1, sizeof(*audiohook_volume)))) {
      ast_datastore_free(datastore);
      return NULL;
   }

   /* Setup our audiohook structure so we can manipulate the audio */
   ast_audiohook_init(&audiohook_volume->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Volume");
   audiohook_volume->audiohook.manipulate_callback = audiohook_volume_callback;

   /* Attach the audiohook_volume blob to the datastore and attach to the channel */
   datastore->data = audiohook_volume;
   ast_channel_datastore_add(chan, datastore);

   /* All is well... put the audiohook into motion */
   ast_audiohook_attach(chan, &audiohook_volume->audiohook);

   return audiohook_volume;
}
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, read]

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

Parameters:
chanChannel that the list is coming off of
audiohook_listList of audiohooks
directionDirection frame is coming in from
frameThe 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, ast_audiohook::list, ast_audiohook::manipulate_callback, ast_audiohook_list::manipulate_list, and ast_audiohook::status.

Referenced by ast_audiohook_write_list().

{
   struct ast_audiohook *audiohook = NULL;

   AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->manipulate_list, audiohook, list) {
      ast_audiohook_lock(audiohook);
      if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
         AST_LIST_REMOVE_CURRENT(list);
         ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
         ast_audiohook_unlock(audiohook);
         audiohook->manipulate_callback(audiohook, NULL, NULL, 0);
         continue;
      }
      if (ast_test_flag(audiohook, AST_AUDIOHOOK_WANTS_DTMF))
         audiohook->manipulate_callback(audiohook, chan, frame, direction);
      ast_audiohook_unlock(audiohook);
   }
   AST_LIST_TRAVERSE_SAFE_END;

   return frame;
}
static struct ast_audiohook* find_audiohook_by_source ( struct ast_audiohook_list audiohook_list,
const char *  source 
) [static, read]

find an audiohook based on its source

Parameters:
audiohook_listThe list of audiohooks to search in
sourceThe 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().

{
   struct ast_audiohook *audiohook = NULL;

   AST_LIST_TRAVERSE(&audiohook_list->spy_list, audiohook, list) {
      if (!strcasecmp(audiohook->source, source))
         return audiohook;
   }

   AST_LIST_TRAVERSE(&audiohook_list->whisper_list, audiohook, list) {
      if (!strcasecmp(audiohook->source, source))
         return audiohook;
   }

   AST_LIST_TRAVERSE(&audiohook_list->manipulate_list, audiohook, list) {
      if (!strcasecmp(audiohook->source, source))
         return audiohook;
   }

   return NULL;
}

Variable Documentation

Initial value:
 {
   .type = "Volume",
   .destroy = audiohook_volume_destroy,
}

Datastore used to store audiohook volume information.

Definition at line 876 of file audiohook.c.