Asterisk - The Open Source Telephony Project GIT-master-70eff7f
Loading...
Searching...
No Matches
Data Structures | Macros | Functions | Variables
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/audiohook.h"
#include "asterisk/slinfactory.h"
#include "asterisk/frame.h"
#include "asterisk/translate.h"
#include "asterisk/format_cache.h"
#include "asterisk/framehook.h"
#include "asterisk/timing.h"
#include "asterisk/test.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...
 
struct  whisper_framehook_data
 

Macros

#define AST_AUDIOHOOK_LONG_QUEUE_TOLERANCE   500
 
#define AST_AUDIOHOOK_SMALL_QUEUE_TOLERANCE   100
 
#define AST_AUDIOHOOK_SYNC_TOLERANCE   100
 
#define AST_WHISPER_TIMER_CLAMP(interval)
 
#define AST_WHISPER_TIMER_INTERVAL   20
 
#define AST_WHISPER_TIMER_INTERVAL_MAX   60
 
#define AST_WHISPER_TIMER_INTERVAL_MIN   10
 
#define AST_WHISPER_TIMER_SRC   "audiohook whisper timer"
 
#define DEFAULT_INTERNAL_SAMPLE_RATE   8000
 
#define SHOULD_MUTE(hook, dir)
 

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.
 
void 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, enum ast_audiohook_init_flags init_flags)
 Initialize an audiohook structure.
 
void ast_audiohook_move_all (struct ast_channel *old_chan, struct ast_channel *new_chan)
 Move all audiohooks from one channel to another.
 
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, struct ast_format *format)
 Reads a frame in from the audiohook structure.
 
struct ast_frameast_audiohook_read_frame_all (struct ast_audiohook *audiohook, size_t samples, struct ast_format *format, struct ast_frame **read_frame, struct ast_frame **write_frame)
 Reads a frame in from the audiohook structure in mixed audio mode and copies read and write frame data to provided arguments.
 
int ast_audiohook_remove (struct ast_channel *chan, struct ast_audiohook *audiohook)
 Remove an audiohook from a specified channel.
 
int ast_audiohook_set_frame_feed_direction (struct ast_audiohook *audiohook, enum ast_audiohook_direction direction)
 Sets direction on audiohook.
 
int ast_audiohook_set_mute (struct ast_channel *chan, const char *source, enum ast_audiohook_flags flag, int clear)
 Mute frames read from or written to a channel.
 
int ast_audiohook_set_mute_all (struct ast_channel *chan, const char *source, enum ast_audiohook_flags flag, int clearmute)
 Mute frames read from or written for all audiohooks on a 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_adjust_float (struct ast_channel *chan, enum ast_audiohook_direction direction, float 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.
 
float ast_audiohook_volume_get_float (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_volume_set_float (struct ast_channel *chan, enum ast_audiohook_direction direction, float 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)
 Determine 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 void audiohook_list_set_hook_rate (struct ast_audiohook_list *audiohook_list, struct ast_audiohook *audiohook, int *rate)
 Set the audiohook's internal sample rate to the audiohook_list's rate, but only when native slin compatibility is turned on.
 
static void audiohook_list_set_samplerate_compatibility (struct ast_audiohook_list *audiohook_list)
 
static struct ast_frameaudiohook_list_translate_to_native (struct ast_audiohook_list *audiohook_list, enum ast_audiohook_direction direction, struct ast_frame *slin_frame, struct ast_format *outformat)
 
static struct ast_frameaudiohook_list_translate_to_slin (struct ast_audiohook_list *audiohook_list, enum ast_audiohook_direction direction, struct ast_frame *frame)
 
static void audiohook_move (struct ast_channel *old_chan, struct ast_channel *new_chan, struct ast_audiohook *audiohook)
 
static struct ast_frameaudiohook_read_frame_both (struct ast_audiohook *audiohook, size_t samples, struct ast_frame **read_reference, struct ast_frame **write_reference)
 
static struct ast_frameaudiohook_read_frame_helper (struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format, struct ast_frame **read_reference, struct ast_frame **write_reference)
 
static struct ast_frameaudiohook_read_frame_single (struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction)
 
static int audiohook_set_internal_rate (struct ast_audiohook *audiohook, int rate, int reset)
 
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
 
static int whisper_framehook_attach (struct ast_channel *chan, struct ast_audiohook_list *audiohook_list)
 
static void whisper_framehook_destroy_cb (void *data)
 
static void whisper_framehook_detach (struct ast_channel *chan, struct ast_audiohook_list *audiohook_list)
 
static struct ast_framewhisper_framehook_event_cb (struct ast_channel *chan, struct ast_frame *frame, enum ast_framehook_event event, void *data)
 
static void whisper_framehook_timer_update (struct ast_audiohook_list *audiohook_list, struct ast_frame *start_frame, int internal_sample_rate, int samples)
 

Variables

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

Detailed Description

Audiohooks Architecture.

Author
Joshua Colp jcolp.nosp@m.@dig.nosp@m.ium.c.nosp@m.om

Definition in file audiohook.c.

Macro Definition Documentation

◆ AST_AUDIOHOOK_LONG_QUEUE_TOLERANCE

#define AST_AUDIOHOOK_LONG_QUEUE_TOLERANCE   500

Otheriwise we still don't want the queue to grow indefinitely

Definition at line 48 of file audiohook.c.

◆ AST_AUDIOHOOK_SMALL_QUEUE_TOLERANCE

#define AST_AUDIOHOOK_SMALL_QUEUE_TOLERANCE   100

When small queue is enabled, this is the maximum amount of audio that can remain queued at a time.

Definition at line 47 of file audiohook.c.

◆ AST_AUDIOHOOK_SYNC_TOLERANCE

#define AST_AUDIOHOOK_SYNC_TOLERANCE   100

Tolerance in milliseconds for audiohooks synchronization

Definition at line 46 of file audiohook.c.

◆ AST_WHISPER_TIMER_CLAMP

#define AST_WHISPER_TIMER_CLAMP (   interval)
Value:
#define AST_WHISPER_TIMER_INTERVAL_MIN
Definition audiohook.c:50
#define AST_WHISPER_TIMER_INTERVAL_MAX
Definition audiohook.c:51

Definition at line 52 of file audiohook.c.

53 : \

◆ AST_WHISPER_TIMER_INTERVAL

#define AST_WHISPER_TIMER_INTERVAL   20

Definition at line 49 of file audiohook.c.

◆ AST_WHISPER_TIMER_INTERVAL_MAX

#define AST_WHISPER_TIMER_INTERVAL_MAX   60

Definition at line 51 of file audiohook.c.

◆ AST_WHISPER_TIMER_INTERVAL_MIN

#define AST_WHISPER_TIMER_INTERVAL_MIN   10

Definition at line 50 of file audiohook.c.

◆ AST_WHISPER_TIMER_SRC

#define AST_WHISPER_TIMER_SRC   "audiohook whisper timer"

Definition at line 55 of file audiohook.c.

◆ DEFAULT_INTERNAL_SAMPLE_RATE

#define DEFAULT_INTERNAL_SAMPLE_RATE   8000

Definition at line 57 of file audiohook.c.

◆ SHOULD_MUTE

#define SHOULD_MUTE (   hook,
  dir 
)
Value:
@ AST_AUDIOHOOK_DIRECTION_READ
Definition audiohook.h:49
@ AST_AUDIOHOOK_DIRECTION_WRITE
Definition audiohook.h:50
@ AST_AUDIOHOOK_MUTE_READ
Definition audiohook.h:64
@ AST_AUDIOHOOK_MUTE_WRITE
Definition audiohook.h:65
#define ast_test_flag(p, flag)
Definition utils.h:64

Definition at line 386 of file audiohook.c.

Function Documentation

◆ ast_audiohook_attach()

int ast_audiohook_attach ( struct ast_channel chan,
struct ast_audiohook audiohook 
)

Attach audiohook to channel.

Parameters
chan
audiohook
Returns
0 on success
Return values
-1on failure

Definition at line 745 of file audiohook.c.

746{
747 ast_channel_lock(chan);
748
749 /* Don't allow an audiohook to be attached to a channel that is already hung up.
750 * The hang up process is what actually notifies the audiohook that it should
751 * stop.
752 */
754 ast_channel_unlock(chan);
755 return -1;
756 }
757
758 if (!ast_channel_audiohooks(chan)) {
759 struct ast_audiohook_list *ahlist;
760 /* Whoops... allocate a new structure */
761 if (!(ahlist = ast_calloc(1, sizeof(*ahlist)))) {
762 ast_channel_unlock(chan);
763 return -1;
764 }
765 ast_channel_audiohooks_set(chan, ahlist);
769 /* This sample rate will adjust as necessary when writing to the list. */
772 }
773
774 /* Drop into respective list */
775 if (audiohook->type == AST_AUDIOHOOK_TYPE_SPY) {
776 AST_LIST_INSERT_TAIL(&ast_channel_audiohooks(chan)->spy_list, audiohook, list);
777 } else if (audiohook->type == AST_AUDIOHOOK_TYPE_WHISPER) {
778 int was_empty = AST_LIST_EMPTY(&ast_channel_audiohooks(chan)->whisper_list);
780 /* Only attach the framehook on the first whisper audiohook */
781 if (was_empty) {
783 AST_LIST_REMOVE(&ast_channel_audiohooks(chan)->whisper_list, audiohook, list);
784 ast_channel_unlock(chan);
785 return -1;
786 }
787 }
788 } else if (audiohook->type == AST_AUDIOHOOK_TYPE_MANIPULATE) {
790 }
791
792 /*
793 * Initialize the audiohook's rate to the default. If it needs to be,
794 * it will get updated later.
795 */
798
799 /* Change status over to running since it is now attached */
801
802 if (ast_channel_is_bridged(chan)) {
804 }
805
806 ast_channel_unlock(chan);
807
808 return 0;
809}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
static void audiohook_list_set_samplerate_compatibility(struct ast_audiohook_list *audiohook_list)
Definition audiohook.c:717
void ast_audiohook_update_status(struct ast_audiohook *audiohook, enum ast_audiohook_status status)
Update audiohook's status.
Definition audiohook.c:811
static int whisper_framehook_attach(struct ast_channel *chan, struct ast_audiohook_list *audiohook_list)
Definition audiohook.c:248
static int audiohook_set_internal_rate(struct ast_audiohook *audiohook, int rate, int reset)
Definition audiohook.c:294
#define DEFAULT_INTERNAL_SAMPLE_RATE
Definition audiohook.c:57
@ AST_AUDIOHOOK_TYPE_MANIPULATE
Definition audiohook.h:38
@ AST_AUDIOHOOK_TYPE_SPY
Definition audiohook.h:36
@ AST_AUDIOHOOK_TYPE_WHISPER
Definition audiohook.h:37
@ AST_AUDIOHOOK_STATUS_RUNNING
Definition audiohook.h:43
void ast_channel_set_unbridged_nolock(struct ast_channel *chan, int value)
Variant of ast_channel_set_unbridged. Use this if the channel is already locked prior to calling.
#define ast_channel_lock(chan)
Definition channel.h:2983
@ AST_FLAG_ZOMBIE
Definition channel.h:1007
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
void ast_channel_audiohooks_set(struct ast_channel *chan, struct ast_audiohook_list *value)
struct ast_audiohook_list * ast_channel_audiohooks(const struct ast_channel *chan)
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition channel.c:10725
#define ast_channel_unlock(chan)
Definition channel.h:2984
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
struct ast_audiohook_list::@322 spy_list
int list_internal_samp_rate
Definition audiohook.c:78
struct ast_audiohook_list::@323 whisper_list
struct ast_audiohook_list::@324 manipulate_list
enum ast_audiohook_type type
Definition audiohook.h:107

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_audiohooks(), ast_channel_audiohooks_set(), ast_channel_flags(), ast_channel_is_bridged(), ast_channel_lock, ast_channel_set_unbridged_nolock(), ast_channel_unlock, AST_FLAG_ZOMBIE, AST_LIST_EMPTY, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_REMOVE, ast_test_flag, audiohook_list_set_samplerate_compatibility(), audiohook_set_internal_rate(), DEFAULT_INTERNAL_SAMPLE_RATE, ast_audiohook_list::list_internal_samp_rate, ast_audiohook_list::manipulate_list, ast_audiohook_list::spy_list, ast_audiohook::type, whisper_framehook_attach(), ast_audiohook_list::whisper_framehook_id, and ast_audiohook_list::whisper_list.

Referenced by audiohook_move(), audiohook_volume_get(), detect_write(), enable_jack_hook(), init_hook(), pitchshift_helper(), scramble_write(), set_talk_detect(), snoop_setup_audiohook(), speex_write(), start_spying(), start_spying(), start_whispering(), start_whispering(), startmon(), and volume_write().

◆ ast_audiohook_destroy()

int ast_audiohook_destroy ( struct ast_audiohook audiohook)

Destroys an audiohook structure.

Parameters
audiohook
Return values
0on success
-1on failure

Definition at line 348 of file audiohook.c.

349{
350 /* Drop the factories used by this audiohook type */
351 switch (audiohook->type) {
356 break;
357 default:
358 break;
359 }
360
361 /* Destroy translation path if present */
362 if (audiohook->trans_pvt)
364
365 ao2_cleanup(audiohook->format);
366
367 /* Lock and trigger be gone! */
368 ast_cond_destroy(&audiohook->trigger);
369 ast_mutex_destroy(&audiohook->lock);
370
371 return 0;
372}
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define ast_cond_destroy(cond)
Definition lock.h:209
#define ast_mutex_destroy(a)
Definition lock.h:195
void ast_slinfactory_destroy(struct ast_slinfactory *sf)
Destroy the contents of a slinfactory.
Definition slinfactory.c:58
ast_cond_t trigger
Definition audiohook.h:106
struct ast_slinfactory read_factory
Definition audiohook.h:112
struct ast_trans_pvt * trans_pvt
Definition audiohook.h:117
struct ast_format * format
Definition audiohook.h:116
ast_mutex_t lock
Definition audiohook.h:105
struct ast_slinfactory write_factory
Definition audiohook.h:113
void ast_translator_free_path(struct ast_trans_pvt *tr)
Frees a translator path Frees the given translator path structure.
Definition translate.c:533

References ao2_cleanup, AST_AUDIOHOOK_TYPE_SPY, AST_AUDIOHOOK_TYPE_WHISPER, ast_cond_destroy, ast_mutex_destroy, ast_slinfactory_destroy(), ast_translator_free_path(), ast_audiohook::format, 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(), datastore_destroy_cb(), destroy_callback(), destroy_callback(), destroy_callback(), destroy_callback(), destroy_callback(), destroy_jack_data(), destroy_monitor_audiohook(), hook_datastore_destroy_callback(), launch_monitor_thread(), multi_autochan_free(), and snoop_destroy().

◆ ast_audiohook_detach()

int ast_audiohook_detach ( struct ast_audiohook audiohook)

Detach audiohook from channel.

Parameters
audiohook
Returns
Returns 0 on success, -1 on failure

Definition at line 821 of file audiohook.c.

822{
823 if (audiohook->status == AST_AUDIOHOOK_STATUS_NEW || audiohook->status == AST_AUDIOHOOK_STATUS_DONE) {
824 return 0;
825 }
826
828
829 while (audiohook->status != AST_AUDIOHOOK_STATUS_DONE) {
831 }
832
833 return 0;
834}
void ast_audiohook_trigger_wait(struct ast_audiohook *audiohook)
Wait for audiohook trigger to be triggered.
Definition audiohook.c:1377
@ AST_AUDIOHOOK_STATUS_DONE
Definition audiohook.h:45
@ AST_AUDIOHOOK_STATUS_NEW
Definition audiohook.h:42
@ AST_AUDIOHOOK_STATUS_SHUTDOWN
Definition audiohook.h:44
enum ast_audiohook_status status
Definition audiohook.h:108

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_callback(), destroy_callback(), destroy_callback(), destroy_monitor_audiohook(), disable_jack_hook(), hook_datastore_destroy_callback(), multi_autochan_free(), snoop_hangup(), and speex_write().

◆ ast_audiohook_detach_list()

void ast_audiohook_detach_list ( struct ast_audiohook_list audiohook_list)

Detach audiohooks from list and destroy said list.

Parameters
audiohook_listList of audiohooks (NULL tolerant)

Definition at line 836 of file audiohook.c.

837{
838 int i;
839 struct ast_audiohook *audiohook;
840
841 if (!audiohook_list) {
842 return;
843 }
844
845 /* Drop any spies */
846 while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->spy_list, list))) {
848 }
849
850 /* Drop any whispering sources */
851 while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->whisper_list, list))) {
853 }
854
855 /* Drop any manipulators */
856 while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->manipulate_list, list))) {
858 audiohook->manipulate_callback(audiohook, NULL, NULL, 0);
859 }
860
861 /* Drop translation paths if present */
862 for (i = 0; i < 2; i++) {
863 if (audiohook_list->in_translate[i].trans_pvt) {
865 ao2_cleanup(audiohook_list->in_translate[i].format);
866 }
867 if (audiohook_list->out_translate[i].trans_pvt) {
869 ao2_cleanup(audiohook_list->out_translate[i].format);
870 }
871 }
872
873 /* Free ourselves */
874 ast_free(audiohook_list);
875}
#define ast_free(a)
Definition astmm.h:180
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
#define NULL
Definition resample.c:96
struct ast_audiohook_translate out_translate[2]
Definition audiohook.c:81
struct ast_audiohook_translate in_translate[2]
Definition audiohook.c:80
struct ast_trans_pvt * trans_pvt
Definition audiohook.c:60
struct ast_format * format
Definition audiohook.c:61
ast_audiohook_manipulate_callback manipulate_callback
Definition audiohook.h:118
struct ast_audiohook::@196 list

References ao2_cleanup, AST_AUDIOHOOK_STATUS_DONE, ast_audiohook_update_status(), ast_free, AST_LIST_REMOVE_HEAD, 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, NULL, 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_write_stream(), and destroy_hooks().

◆ ast_audiohook_detach_source()

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
Return values
0on success
-1on failure
Note
The channel does not need to be locked before calling this function.

Definition at line 969 of file audiohook.c.

970{
971 struct ast_audiohook *audiohook = NULL;
972
973 ast_channel_lock(chan);
974
975 /* Ensure the channel has audiohooks on it */
976 if (!ast_channel_audiohooks(chan)) {
977 ast_channel_unlock(chan);
978 return -1;
979 }
980
982
983 ast_channel_unlock(chan);
984
985 if (audiohook && audiohook->status != AST_AUDIOHOOK_STATUS_DONE) {
987 }
988
989 return (audiohook ? 0 : -1);
990}
static struct ast_audiohook * find_audiohook_by_source(struct ast_audiohook_list *audiohook_list, const char *source)
find an audiohook based on its source
Definition audiohook.c:883
const char * source
Definition audiohook.h:110

References AST_AUDIOHOOK_STATUS_DONE, AST_AUDIOHOOK_STATUS_SHUTDOWN, ast_audiohook_update_status(), ast_channel_audiohooks(), ast_channel_lock, ast_channel_unlock, find_audiohook_by_source(), NULL, ast_audiohook::source, and ast_audiohook::status.

◆ ast_audiohook_init()

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

Initialize an audiohook structure.

Parameters
audiohook
typeType of audiohook to initialize this as
sourceWho is initializing this audiohook
flags
Return values
0on success
-1on failure

Definition at line 324 of file audiohook.c.

325{
326 /* Need to keep the type and source */
327 audiohook->type = type;
328 audiohook->source = source;
329
330 /* Initialize lock that protects our audiohook */
331 ast_mutex_init(&audiohook->lock);
332 ast_cond_init(&audiohook->trigger, NULL);
333
334 audiohook->init_flags = init_flags;
335
336 /* Set direction to BOTH so that we feed frames in both directions */
338
339 /* initialize internal rate at 8khz, this will adjust if necessary */
341
342 /* Since we are just starting out... this audiohook is new */
344
345 return 0;
346}
@ AST_AUDIOHOOK_DIRECTION_BOTH
Definition audiohook.h:51
static const char type[]
#define ast_cond_init(cond, attr)
Definition lock.h:208
#define ast_mutex_init(pmutex)
Definition lock.h:193
enum ast_audiohook_init_flags init_flags
Definition audiohook.h:109
enum ast_audiohook_direction direction
Definition audiohook.h:121

References AST_AUDIOHOOK_DIRECTION_BOTH, AST_AUDIOHOOK_STATUS_NEW, ast_audiohook_update_status(), ast_cond_init, ast_mutex_init, audiohook_set_internal_rate(), DEFAULT_INTERNAL_SAMPLE_RATE, ast_audiohook::direction, ast_audiohook::init_flags, ast_audiohook::lock, NULL, ast_audiohook::source, ast_audiohook::trigger, type, and ast_audiohook::type.

Referenced by attach_barge(), attach_barge(), audiohook_volume_get(), channel_spy(), detect_write(), do_broadcast(), enable_jack_hook(), hook_state_alloc(), launch_monitor_thread(), pitchshift_helper(), scramble_write(), set_talk_detect(), snoop_setup_audiohook(), speex_write(), and volume_write().

◆ ast_audiohook_move_all()

void ast_audiohook_move_all ( struct ast_channel old_chan,
struct ast_channel new_chan 
)

Move all audiohooks from one channel to another.

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 audiohooks being moved
new_chanThe destination channel for the audiohooks to be moved to

Definition at line 943 of file audiohook.c.

944{
945 struct ast_audiohook *audiohook;
946 struct ast_audiohook_list *audiohook_list;
947
948 audiohook_list = ast_channel_audiohooks(old_chan);
949 if (!audiohook_list) {
950 return;
951 }
952
953 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->spy_list, audiohook, list) {
954 audiohook_move(old_chan, new_chan, audiohook);
955 }
957
958 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->whisper_list, audiohook, list) {
959 audiohook_move(old_chan, new_chan, audiohook);
960 }
962
963 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->manipulate_list, audiohook, list) {
964 audiohook_move(old_chan, new_chan, audiohook);
965 }
967}
static void audiohook_move(struct ast_channel *old_chan, struct ast_channel *new_chan, struct ast_audiohook *audiohook)
Definition audiohook.c:908
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.

References ast_channel_audiohooks(), AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, audiohook_move(), ast_audiohook_list::manipulate_list, ast_audiohook_list::spy_list, and ast_audiohook_list::whisper_list.

Referenced by channel_do_masquerade().

◆ ast_audiohook_move_by_source()

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 927 of file audiohook.c.

928{
929 struct ast_audiohook *audiohook;
930
931 if (!ast_channel_audiohooks(old_chan)) {
932 return;
933 }
934
936 if (!audiohook) {
937 return;
938 }
939
940 audiohook_move(old_chan, new_chan, audiohook);
941}

References ast_channel_audiohooks(), audiohook_move(), find_audiohook_by_source(), and ast_audiohook::source.

◆ ast_audiohook_read_frame()

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

Reads a frame in from the audiohook structure.

Parameters
audiohook
samplesNumber of samples wanted
directionDirection the audio frame came from
formatFormat of frame remote side wants back
Returns
frame on success
Return values
NULLon failure

Definition at line 707 of file audiohook.c.

708{
709 return audiohook_read_frame_helper(audiohook, samples, direction, format, NULL, NULL);
710}
static struct ast_frame * audiohook_read_frame_helper(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format, struct ast_frame **read_reference, struct ast_frame **write_reference)
Definition audiohook.c:645
direction

References audiohook_read_frame_helper(), NULL, and ast_frame::samples.

Referenced by snoop_read(), spy_generate(), and spy_generate().

◆ ast_audiohook_read_frame_all()

struct ast_frame * ast_audiohook_read_frame_all ( struct ast_audiohook audiohook,
size_t  samples,
struct ast_format format,
struct ast_frame **  read_frame,
struct ast_frame **  write_frame 
)

Reads a frame in from the audiohook structure in mixed audio mode and copies read and write frame data to provided arguments.

Parameters
audiohook
samplesNumber of samples wanted
formatFormat of frame remote side wants back
read_frameif available, we'll copy the read buffer to this.
write_frameif available, we'll copy the write buffer to this.
Returns
frame on success
Return values
NULLon failure
Note
The read_frame and write_frame may be in a different format from what was specified in format depending on the sample rate of the hooked channel's codec - ie; if we are requesting slin, but are hooked on channel using a 16K codec like g722, the read and write frames will be slin16.

Definition at line 712 of file audiohook.c.

713{
714 return audiohook_read_frame_helper(audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, format, read_frame, write_frame);
715}
static struct ast_frame * read_frame(struct ast_filestream *s, int *whennext)
Definition file.c:938

References AST_AUDIOHOOK_DIRECTION_BOTH, audiohook_read_frame_helper(), read_frame(), and ast_frame::samples.

Referenced by mixmonitor_thread(), and spy_generate().

◆ ast_audiohook_remove()

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
Return values
0on success
-1on failure
Note
The channel does not need to be locked before calling this function

Definition at line 992 of file audiohook.c.

993{
994 ast_channel_lock(chan);
995
996 if (!ast_channel_audiohooks(chan)) {
997 ast_channel_unlock(chan);
998 return -1;
999 }
1000
1001 if (audiohook->type == AST_AUDIOHOOK_TYPE_SPY) {
1002 AST_LIST_REMOVE(&ast_channel_audiohooks(chan)->spy_list, audiohook, list);
1003 } else if (audiohook->type == AST_AUDIOHOOK_TYPE_WHISPER) {
1004 AST_LIST_REMOVE(&ast_channel_audiohooks(chan)->whisper_list, audiohook, list);
1005 /* Detach the framehook if this was the last whisper audiohook */
1006 if (AST_LIST_EMPTY(&ast_channel_audiohooks(chan)->whisper_list)) {
1008 }
1009 } else if (audiohook->type == AST_AUDIOHOOK_TYPE_MANIPULATE) {
1010 AST_LIST_REMOVE(&ast_channel_audiohooks(chan)->manipulate_list, audiohook, list);
1011 }
1012
1015
1016 if (ast_channel_is_bridged(chan)) {
1018 }
1019
1020 ast_channel_unlock(chan);
1021
1022 return 0;
1023}
static void whisper_framehook_detach(struct ast_channel *chan, struct ast_audiohook_list *audiohook_list)
Definition audiohook.c:283

References AST_AUDIOHOOK_STATUS_DONE, AST_AUDIOHOOK_TYPE_MANIPULATE, AST_AUDIOHOOK_TYPE_SPY, AST_AUDIOHOOK_TYPE_WHISPER, ast_audiohook_update_status(), ast_channel_audiohooks(), ast_channel_is_bridged(), ast_channel_lock, ast_channel_set_unbridged_nolock(), ast_channel_unlock, AST_LIST_EMPTY, AST_LIST_REMOVE, audiohook_list_set_samplerate_compatibility(), ast_audiohook::list, ast_audiohook::type, and whisper_framehook_detach().

Referenced by audiohook_move(), remove_detect(), remove_scrambler(), remove_talk_detect(), and speex_write().

◆ ast_audiohook_set_frame_feed_direction()

int ast_audiohook_set_frame_feed_direction ( struct ast_audiohook audiohook,
enum ast_audiohook_direction  direction 
)

Sets direction on audiohook.

Parameters
audiohook
directionIn which direction should the audiohook feed frames, ie if we are snooping 'in', set direction to READ so that only the 'in' frames are fed to the slin factory
Return values
0on success
-1on failure due to audiohook already in use or in shutdown. Can only set direction on NEW audiohooks

Definition at line 374 of file audiohook.c.

375{
376 /* Only set the direction on new audiohooks */
377 if (audiohook->status != AST_AUDIOHOOK_STATUS_NEW) {
378 ast_debug(3, "Can not set direction on attached Audiohook %p\n", audiohook);
379 return -1;
380 }
381
382 audiohook->direction = direction;
383 return 0;
384}
#define ast_debug(level,...)
Log a DEBUG message.

References AST_AUDIOHOOK_STATUS_NEW, ast_debug, ast_audiohook::direction, and ast_audiohook::status.

Referenced by snoop_setup_audiohook(), start_spying(), and start_spying().

◆ ast_audiohook_set_mute()

int ast_audiohook_set_mute ( struct ast_channel chan,
const char *  source,
enum ast_audiohook_flags  flag,
int  clear 
)

Mute frames read from or written to a channel.

Parameters
chanChannel to muck with
sourceType of audiohook
flagwhich direction to set / clear
clearset or clear muted frames on direction based on flag parameter
Return values
0success
-1failure

Definition at line 1651 of file audiohook.c.

1652{
1653 struct ast_audiohook *audiohook = NULL;
1654
1655 ast_channel_lock(chan);
1656
1657 /* Ensure the channel has audiohooks on it */
1658 if (!ast_channel_audiohooks(chan)) {
1659 ast_channel_unlock(chan);
1660 return -1;
1661 }
1662
1664
1665 if (audiohook) {
1666 if (clear) {
1667 ast_clear_flag(audiohook, flag);
1668 } else {
1669 ast_set_flag(audiohook, flag);
1670 }
1671 }
1672
1673 ast_channel_unlock(chan);
1674
1675 return (audiohook ? 0 : -1);
1676}
long int flag
Definition f2c.h:83
#define ast_clear_flag(p, flag)
Definition utils.h:78
#define ast_set_flag(p, flag)
Definition utils.h:71

References ast_channel_audiohooks(), ast_channel_lock, ast_channel_unlock, ast_clear_flag, ast_set_flag, find_audiohook_by_source(), NULL, and ast_audiohook::source.

◆ ast_audiohook_set_mute_all()

int ast_audiohook_set_mute_all ( struct ast_channel chan,
const char *  source,
enum ast_audiohook_flags  flag,
int  clear 
)

Mute frames read from or written for all audiohooks on a channel.

Parameters
chanChannel to muck with
sourceType of audiohooks
flagwhich direction to set / clear
clearset or clear muted frames on direction based on flag parameter
Return values
>=0number of muted audiohooks
-1failure

Definition at line 1678 of file audiohook.c.

1679{
1680 struct ast_audiohook *audiohook = NULL;
1681 int count = 0;
1682
1683 ast_channel_lock(chan);
1684
1685 if (!ast_channel_audiohooks(chan)) {
1686 ast_channel_unlock(chan);
1687 return -1;
1688 }
1689
1690 AST_LIST_TRAVERSE(&ast_channel_audiohooks(chan)->spy_list, audiohook, list) {
1691 if (!strcasecmp(audiohook->source, source)) {
1692 count++;
1693 if (clearmute) {
1694 ast_clear_flag(audiohook, flag);
1695 } else {
1696 ast_set_flag(audiohook, flag);
1697 }
1698 }
1699 }
1700
1701 ast_test_suite_event_notify("AUDIOHOOK_GROUP_MUTE_TOGGLE", "Channel: %s\r\nSource: %s\r\nCount: %d\r\n",
1702 ast_channel_name(chan), source, count);
1703
1704 ast_channel_unlock(chan);
1705
1706 return count;
1707}
const char * ast_channel_name(const struct ast_channel *chan)
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define ast_test_suite_event_notify(s, f,...)
Definition test.h:189

References ast_channel_audiohooks(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_clear_flag, AST_LIST_TRAVERSE, ast_set_flag, ast_test_suite_event_notify, ast_audiohook::list, NULL, and ast_audiohook::source.

Referenced by manager_mute_mixmonitor().

◆ ast_audiohook_trigger_wait()

void ast_audiohook_trigger_wait ( struct ast_audiohook audiohook)

Wait for audiohook trigger to be triggered.

Parameters
audiohookAudiohook to wait on

Definition at line 1377 of file audiohook.c.

1378{
1379 struct timeval wait;
1380 struct timespec ts;
1381
1382 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(50000, 1000));
1383 ts.tv_sec = wait.tv_sec;
1384 ts.tv_nsec = wait.tv_usec * 1000;
1385
1386 ast_cond_timedwait(&audiohook->trigger, &audiohook->lock, &ts);
1387
1388 return;
1389}
#define ast_cond_timedwait(cond, mutex, time)
Definition lock.h:213
struct timeval ast_samp2tv(unsigned int _nsamp, unsigned int _rate)
Returns a timeval corresponding to the duration of n samples at rate r. Useful to convert samples to ...
Definition time.h:282
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition extconf.c:2280
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159

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

◆ ast_audiohook_update_status()

void ast_audiohook_update_status ( struct ast_audiohook audiohook,
enum ast_audiohook_status  status 
)

Update audiohook's status.

Parameters
audiohook
status
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 811 of file audiohook.c.

812{
813 ast_audiohook_lock(audiohook);
814 if (audiohook->status != AST_AUDIOHOOK_STATUS_DONE) {
815 audiohook->status = status;
816 ast_cond_signal(&audiohook->trigger);
817 }
818 ast_audiohook_unlock(audiohook);
819}
jack_status_t status
Definition app_jack.c:149
#define ast_audiohook_lock(ah)
Lock an audiohook.
Definition audiohook.h:316
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
Definition audiohook.h:321
#define ast_cond_signal(cond)
Definition lock.h:210

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(), dtmf_audiohook_write_list(), and stop_mixmonitor_full().

◆ ast_audiohook_volume_adjust()

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
Return values
0on success
-1on failure
Since
1.6.1

Definition at line 1626 of file audiohook.c.

1627{
1628 return ast_audiohook_volume_adjust_float(chan, direction, (float) volume);
1629}
int ast_audiohook_volume_adjust_float(struct ast_channel *chan, enum ast_audiohook_direction direction, float volume)
Adjust the volume on frames read from or written to a channel.
Definition audiohook.c:1631

References ast_audiohook_volume_adjust_float().

Referenced by execute_menu_entry().

◆ ast_audiohook_volume_adjust_float()

int ast_audiohook_volume_adjust_float ( struct ast_channel chan,
enum ast_audiohook_direction  direction,
float  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
Return values
0on success
-1on failure

Definition at line 1631 of file audiohook.c.

1632{
1634
1635 /* Attempt to find the audiohook volume information, and create an audiohook if none exists */
1636 if (!(audiohook_volume = audiohook_volume_get(chan, 1))) {
1637 return -1;
1638 }
1639
1640 /* Based on the direction change the specific adjustment value */
1643 }
1646 }
1647
1648 return 0;
1649}
static struct audiohook_volume * audiohook_volume_get(struct ast_channel *chan, int create)
Helper function which finds and optionally creates an audiohook_volume_datastore datastore on a chann...
Definition audiohook.c:1541
Audiohook volume adjustment structure.
Definition audiohook.c:1466

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

Referenced by ast_audiohook_volume_adjust(), and ast_audiohook_volume_set().

◆ ast_audiohook_volume_get()

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
adjustment value
Since
1.6.1

Definition at line 1601 of file audiohook.c.

1602{
1603 return (int) ast_audiohook_volume_get_float(chan, direction);
1604}
float ast_audiohook_volume_get_float(struct ast_channel *chan, enum ast_audiohook_direction direction)
Retrieve the volume adjustment value on frames read from or written to a channel.
Definition audiohook.c:1606

References ast_audiohook_volume_get_float().

Referenced by confbridge_exec().

◆ ast_audiohook_volume_get_float()

float ast_audiohook_volume_get_float ( 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
adjustment value

Definition at line 1606 of file audiohook.c.

1607{
1609 float adjustment = 0;
1610
1611 /* Attempt to find the audiohook volume information, but do not create it as we only want to look at the values */
1612 if (!(audiohook_volume = audiohook_volume_get(chan, 0))) {
1613 return 0;
1614 }
1615
1616 /* Grab the adjustment value based on direction given */
1618 adjustment = audiohook_volume->read_adjustment;
1620 adjustment = audiohook_volume->write_adjustment;
1621 }
1622
1623 return adjustment;
1624}

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

Referenced by ast_audiohook_volume_get().

◆ ast_audiohook_volume_set()

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
Return values
0on success
-1on failure
Since
1.6.1

Definition at line 1576 of file audiohook.c.

1577{
1578 return ast_audiohook_volume_adjust_float(chan, direction, (float) volume);
1579}

References ast_audiohook_volume_adjust_float().

Referenced by confbridge_exec(), and execute_menu_entry().

◆ ast_audiohook_volume_set_float()

int ast_audiohook_volume_set_float ( struct ast_channel chan,
enum ast_audiohook_direction  direction,
float  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
Return values
0on success
-1on failure

Definition at line 1581 of file audiohook.c.

1582{
1584
1585 /* Attempt to find the audiohook volume information, but only create it if we are not setting the adjustment value to zero */
1586 if (!(audiohook_volume = audiohook_volume_get(chan, (volume ? 1 : 0)))) {
1587 return -1;
1588 }
1589
1590 /* Now based on the direction set the proper value */
1593 }
1596 }
1597
1598 return 0;
1599}

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

◆ ast_audiohook_write_frame()

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
directionDirection the audio frame came from
frameFrame to write in
Return values
0on success
-1on failure

Definition at line 391 of file audiohook.c.

392{
393 struct ast_slinfactory *factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_factory : &audiohook->write_factory);
394 struct ast_slinfactory *other_factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->write_factory : &audiohook->read_factory);
395 struct timeval *rwtime = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_time : &audiohook->write_time), previous_time = *rwtime;
396 int our_factory_samples;
397 int our_factory_ms;
398 int other_factory_samples;
399 int other_factory_ms;
400
401 /* Don't feed the frame if we are set to read and this is a write frame or if set to
402 write and this is a read frame as we don't want it. Plus, it can cause mis-resampling
403 if the READ and WRITE frames have different bitrates */
404 if (audiohook->direction != AST_AUDIOHOOK_DIRECTION_BOTH && audiohook->direction != direction) {
405 return 0;
406 }
407
408 /* Update last feeding time to be current */
409 *rwtime = ast_tvnow();
410
411 our_factory_samples = ast_slinfactory_available(factory);
412 our_factory_ms = ast_tvdiff_ms(*rwtime, previous_time) + (our_factory_samples / (audiohook->hook_internal_samp_rate / 1000));
413 other_factory_samples = ast_slinfactory_available(other_factory);
414 other_factory_ms = other_factory_samples / (audiohook->hook_internal_samp_rate / 1000);
415
416 if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC) && (our_factory_ms - other_factory_ms > AST_AUDIOHOOK_SYNC_TOLERANCE)) {
417 ast_debug(4, "Flushing audiohook %p so it remains in sync\n", audiohook);
418 ast_slinfactory_flush(factory);
419 ast_slinfactory_flush(other_factory);
420 }
421
422 if (ast_test_flag(audiohook, AST_AUDIOHOOK_SMALL_QUEUE) && ((our_factory_ms > AST_AUDIOHOOK_SMALL_QUEUE_TOLERANCE) || (other_factory_ms > AST_AUDIOHOOK_SMALL_QUEUE_TOLERANCE))) {
423 ast_debug(4, "Audiohook %p has stale audio in its factories. Flushing them both\n", audiohook);
424 ast_slinfactory_flush(factory);
425 ast_slinfactory_flush(other_factory);
426 } else if ((our_factory_ms > AST_AUDIOHOOK_LONG_QUEUE_TOLERANCE) || (other_factory_ms > AST_AUDIOHOOK_LONG_QUEUE_TOLERANCE)) {
427 ast_debug(4, "Audiohook %p has stale audio in its factories. Flushing them both\n", audiohook);
428 ast_slinfactory_flush(factory);
429 ast_slinfactory_flush(other_factory);
430 }
431
432 /* Write frame out to respective factory */
433 ast_slinfactory_feed(factory, frame);
434
435 /* If we need to notify the respective handler of this audiohook, do so */
437 ast_cond_signal(&audiohook->trigger);
439 ast_cond_signal(&audiohook->trigger);
440 } else if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC)) {
441 ast_cond_signal(&audiohook->trigger);
442 }
443
444 return 0;
445}
#define AST_AUDIOHOOK_LONG_QUEUE_TOLERANCE
Definition audiohook.c:48
#define AST_AUDIOHOOK_SYNC_TOLERANCE
Definition audiohook.c:46
#define AST_AUDIOHOOK_SMALL_QUEUE_TOLERANCE
Definition audiohook.c:47
@ AST_AUDIOHOOK_TRIGGER_MODE
Definition audiohook.h:55
@ AST_AUDIOHOOK_SMALL_QUEUE
Definition audiohook.h:63
@ AST_AUDIOHOOK_TRIGGER_READ
Definition audiohook.h:56
@ AST_AUDIOHOOK_TRIGGER_WRITE
Definition audiohook.h:57
@ AST_AUDIOHOOK_TRIGGER_SYNC
Definition audiohook.h:59
unsigned int ast_slinfactory_available(const struct ast_slinfactory *sf)
Retrieve number of samples currently in a slinfactory.
void ast_slinfactory_flush(struct ast_slinfactory *sf)
Flush the contents of a slinfactory.
int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f)
Feed audio into a slinfactory.
Definition slinfactory.c:77
struct timeval write_time
Definition audiohook.h:115
struct timeval read_time
Definition audiohook.h:114
unsigned int hook_internal_samp_rate
Definition audiohook.h:120
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition time.h:107

References AST_AUDIOHOOK_DIRECTION_BOTH, AST_AUDIOHOOK_DIRECTION_READ, AST_AUDIOHOOK_DIRECTION_WRITE, AST_AUDIOHOOK_LONG_QUEUE_TOLERANCE, AST_AUDIOHOOK_SMALL_QUEUE, AST_AUDIOHOOK_SMALL_QUEUE_TOLERANCE, AST_AUDIOHOOK_SYNC_TOLERANCE, AST_AUDIOHOOK_TRIGGER_MODE, AST_AUDIOHOOK_TRIGGER_READ, AST_AUDIOHOOK_TRIGGER_SYNC, AST_AUDIOHOOK_TRIGGER_WRITE, ast_cond_signal, ast_debug, ast_slinfactory_available(), ast_slinfactory_feed(), ast_slinfactory_flush(), ast_test_flag, ast_tvdiff_ms(), ast_tvnow(), ast_audiohook::direction, ast_audiohook::hook_internal_samp_rate, 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(), channel_spy(), do_broadcast(), and snoop_write().

◆ ast_audiohook_write_list()

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
chanChannel that the list is coming off of
audiohook_listList of audiohooks
directionDirection frame is coming in from
frameThe frame itself
Returns
frame on success
Return values
NULLon failure

Definition at line 1362 of file audiohook.c.

1363{
1364 /* Pass off frame to it's respective list write function */
1365 if (frame->frametype == AST_FRAME_VOICE) {
1366 return audio_audiohook_write_list(chan, audiohook_list, direction, frame);
1367 } else if (frame->frametype == AST_FRAME_DTMF) {
1368 return dtmf_audiohook_write_list(chan, audiohook_list, direction, frame);
1369 } else {
1370 return frame;
1371 }
1372}
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)
Pass an AUDIO frame off to be handled by the audiohook core.
Definition audiohook.c:1189
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)
Pass a DTMF frame off to be handled by the audiohook core.
Definition audiohook.c:1033
#define AST_FRAME_DTMF
enum ast_frame_type frametype

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

◆ ast_audiohook_write_list_empty()

int ast_audiohook_write_list_empty ( struct ast_audiohook_list audiohook_list)

Determine if a audiohook_list is empty or not.

Parameters
audiohook_listAudiohook to check. (NULL also means empty)
Return values
0false
1true

Definition at line 1354 of file audiohook.c.

1355{
1356 return !audiohook_list
1357 || (AST_LIST_EMPTY(&audiohook_list->spy_list)
1358 && AST_LIST_EMPTY(&audiohook_list->whisper_list)
1359 && AST_LIST_EMPTY(&audiohook_list->manipulate_list));
1360}

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

Referenced by __ast_read(), ast_channel_has_audio_frame_or_monitor(), ast_channel_has_hook_requiring_audio(), and ast_write_stream().

◆ ast_channel_audiohook_count_by_source()

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
number of audiohooks which are from the source specified

Note: Function performs nlocking.

Definition at line 1392 of file audiohook.c.

1393{
1394 int count = 0;
1395 struct ast_audiohook *ah = NULL;
1396
1397 if (!ast_channel_audiohooks(chan)) {
1398 return -1;
1399 }
1400
1401 switch (type) {
1403 AST_LIST_TRAVERSE(&ast_channel_audiohooks(chan)->spy_list, ah, list) {
1404 if (!strcmp(ah->source, source)) {
1405 count++;
1406 }
1407 }
1408 break;
1410 AST_LIST_TRAVERSE(&ast_channel_audiohooks(chan)->whisper_list, ah, list) {
1411 if (!strcmp(ah->source, source)) {
1412 count++;
1413 }
1414 }
1415 break;
1417 AST_LIST_TRAVERSE(&ast_channel_audiohooks(chan)->manipulate_list, ah, list) {
1418 if (!strcmp(ah->source, source)) {
1419 count++;
1420 }
1421 }
1422 break;
1423 default:
1424 ast_debug(1, "Invalid audiohook type supplied, (%u)\n", type);
1425 return -1;
1426 }
1427
1428 return count;
1429}

References AST_AUDIOHOOK_TYPE_MANIPULATE, AST_AUDIOHOOK_TYPE_SPY, AST_AUDIOHOOK_TYPE_WHISPER, ast_channel_audiohooks(), ast_debug, AST_LIST_TRAVERSE, ast_audiohook::list, NULL, ast_audiohook::source, and type.

Referenced by feature_automixmonitor().

◆ ast_channel_audiohook_count_by_source_running()

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
number of running audiohooks which are from the source specified

Note: Function performs no locking.

Definition at line 1432 of file audiohook.c.

1433{
1434 int count = 0;
1435 struct ast_audiohook *ah = NULL;
1436 if (!ast_channel_audiohooks(chan))
1437 return -1;
1438
1439 switch (type) {
1441 AST_LIST_TRAVERSE(&ast_channel_audiohooks(chan)->spy_list, ah, list) {
1442 if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
1443 count++;
1444 }
1445 break;
1447 AST_LIST_TRAVERSE(&ast_channel_audiohooks(chan)->whisper_list, ah, list) {
1448 if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
1449 count++;
1450 }
1451 break;
1453 AST_LIST_TRAVERSE(&ast_channel_audiohooks(chan)->manipulate_list, ah, list) {
1454 if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
1455 count++;
1456 }
1457 break;
1458 default:
1459 ast_debug(1, "Invalid audiohook type supplied, (%u)\n", type);
1460 return -1;
1461 }
1462 return count;
1463}

References AST_AUDIOHOOK_STATUS_RUNNING, AST_AUDIOHOOK_TYPE_MANIPULATE, AST_AUDIOHOOK_TYPE_SPY, AST_AUDIOHOOK_TYPE_WHISPER, ast_channel_audiohooks(), ast_debug, AST_LIST_TRAVERSE, ast_audiohook::list, NULL, ast_audiohook::source, ast_audiohook::status, and type.

◆ audio_audiohook_write_list()

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. Part_3: Translate end_frame's audio back into the format of start frame if necessary. This is only necessary if manipulation of middle_frame occurred.

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

Definition at line 1189 of file audiohook.c.

1190{
1191 struct ast_frame *start_frame = frame, *middle_frame = frame, *end_frame = frame;
1192 struct ast_audiohook *audiohook = NULL;
1193 int samples;
1194 int middle_frame_manipulated = 0;
1195 int removed = 0;
1196 int internal_sample_rate;
1197
1198 /* ---Part_1. translate start_frame to SLINEAR if necessary. */
1199 if (!(middle_frame = audiohook_list_translate_to_slin(audiohook_list, direction, start_frame))) {
1200 return frame;
1201 }
1202
1203 /* If the translation resulted in an interpolated frame then immediately return as audiohooks
1204 * rely on actual media being present to do things.
1205 */
1206 if (!middle_frame->data.ptr) {
1207 if (middle_frame != start_frame) {
1208 ast_frfree(middle_frame);
1209 }
1210 return start_frame;
1211 }
1212
1213 samples = middle_frame->samples;
1214
1215 /*
1216 * While processing each audiohook check to see if the internal sample rate needs
1217 * to be adjusted (it should be the highest rate specified between formats and
1218 * hooks). The given audiohook_list's internal sample rate is then set to the
1219 * updated value before returning.
1220 *
1221 * If slin compatibility mode is turned on then an audiohook's internal sample
1222 * rate is set to its audiohook_list's rate. If an audiohook_list's rate is
1223 * adjusted during this pass then the change is picked up by the audiohooks
1224 * on the next pass.
1225 */
1226 internal_sample_rate = audiohook_list->list_internal_samp_rate;
1227
1228 /* ---Part_2: Send middle_frame to spy and manipulator lists. middle_frame is guaranteed to be SLINEAR here.*/
1229 /* Queue up signed linear frame to each spy */
1230 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->spy_list, audiohook, list) {
1231 ast_audiohook_lock(audiohook);
1232 if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
1234 removed = 1;
1236 ast_audiohook_unlock(audiohook);
1237 if (ast_channel_is_bridged(chan)) {
1239 }
1240 continue;
1241 }
1242 audiohook_list_set_hook_rate(audiohook_list, audiohook, &internal_sample_rate);
1243 ast_audiohook_write_frame(audiohook, direction, middle_frame);
1244 ast_audiohook_unlock(audiohook);
1245 }
1247
1248 /* If this frame is being written out to the channel then we need to use whisper sources */
1249 if (!AST_LIST_EMPTY(&audiohook_list->whisper_list)) {
1250 int i = 0;
1251 short read_buf[samples], combine_buf[samples], *data1 = NULL, *data2 = NULL;
1252 memset(&combine_buf, 0, sizeof(combine_buf));
1253 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->whisper_list, audiohook, list) {
1254 struct ast_slinfactory *factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_factory : &audiohook->write_factory);
1255 ast_audiohook_lock(audiohook);
1256 if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
1258 removed = 1;
1260 ast_audiohook_unlock(audiohook);
1261 if (ast_channel_is_bridged(chan)) {
1263 }
1264 continue;
1265 }
1266 audiohook_list_set_hook_rate(audiohook_list, audiohook, &internal_sample_rate);
1267 if (ast_slinfactory_available(factory) >= samples && ast_slinfactory_read(factory, read_buf, samples)) {
1268 /* Take audio from this whisper source and combine it into our main buffer */
1269 for (i = 0, data1 = combine_buf, data2 = read_buf; i < samples; i++, data1++, data2++) {
1270 ast_slinear_saturated_add(data1, data2);
1271 }
1272 }
1273 ast_audiohook_unlock(audiohook);
1274 }
1276 /* We take all of the combined whisper sources and combine them into the audio being written out */
1277 for (i = 0, data1 = middle_frame->data.ptr, data2 = combine_buf; i < samples; i++, data1++, data2++) {
1278 ast_slinear_saturated_add(data1, data2);
1279 }
1280 middle_frame_manipulated = 1;
1281 }
1282
1283 /* Pass off frame to manipulate audiohooks */
1284 if (!AST_LIST_EMPTY(&audiohook_list->manipulate_list)) {
1285 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->manipulate_list, audiohook, list) {
1286 ast_audiohook_lock(audiohook);
1287 if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
1289 removed = 1;
1291 ast_audiohook_unlock(audiohook);
1292 /* We basically drop all of our links to the manipulate audiohook and prod it to do it's own destructive things */
1293 audiohook->manipulate_callback(audiohook, chan, NULL, direction);
1294 if (ast_channel_is_bridged(chan)) {
1296 }
1297 continue;
1298 }
1299 audiohook_list_set_hook_rate(audiohook_list, audiohook, &internal_sample_rate);
1300 /*
1301 * Feed in frame to manipulation.
1302 */
1303 if (!audiohook->manipulate_callback(audiohook, chan, middle_frame, direction)) {
1304 /*
1305 * XXX FAILURES ARE IGNORED XXX
1306 * If the manipulation fails then the frame will be returned in its original state.
1307 * Since there are potentially more manipulator callbacks in the list, no action should
1308 * be taken here to exit early.
1309 */
1310 middle_frame_manipulated = 1;
1311 }
1312 ast_audiohook_unlock(audiohook);
1313 }
1315 }
1316
1317 /* ---Part_3: Decide what to do with the end_frame (whether to transcode or not) */
1318 if (middle_frame_manipulated) {
1319 if (!(end_frame = audiohook_list_translate_to_native(audiohook_list, direction, middle_frame, start_frame->subclass.format))) {
1320 /* translation failed, so just pass back the input frame */
1321 end_frame = start_frame;
1322 }
1323 } else {
1324 end_frame = start_frame;
1325 }
1326 /* clean up our middle_frame if required */
1327 if (middle_frame != end_frame) {
1328 ast_frfree(middle_frame);
1329 middle_frame = NULL;
1330 }
1331
1332 /* Before returning, if an audiohook got removed, reset samplerate compatibility */
1333 if (removed) {
1335 } else {
1336 /*
1337 * Set the audiohook_list's rate to the updated rate. Note that if a hook
1338 * was removed then the list's internal rate is reset to the default.
1339 */
1340 audiohook_list->list_internal_samp_rate = internal_sample_rate;
1341 /*
1342 * Update the whisper timer with the internal sample rate on WRITE only to
1343 * avoid overlapping writes.
1344 */
1346 whisper_framehook_timer_update(audiohook_list, start_frame,
1347 internal_sample_rate, samples);
1348 }
1349 }
1350
1351 return end_frame;
1352}
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.
Definition audiohook.c:391
static struct ast_frame * audiohook_list_translate_to_native(struct ast_audiohook_list *audiohook_list, enum ast_audiohook_direction direction, struct ast_frame *slin_frame, struct ast_format *outformat)
Definition audiohook.c:1111
static struct ast_frame * audiohook_list_translate_to_slin(struct ast_audiohook_list *audiohook_list, enum ast_audiohook_direction direction, struct ast_frame *frame)
Definition audiohook.c:1065
static void audiohook_list_set_hook_rate(struct ast_audiohook_list *audiohook_list, struct ast_audiohook *audiohook, int *rate)
Set the audiohook's internal sample rate to the audiohook_list's rate, but only when native slin comp...
Definition audiohook.c:1143
static void whisper_framehook_timer_update(struct ast_audiohook_list *audiohook_list, struct ast_frame *start_frame, int internal_sample_rate, int samples)
Definition audiohook.c:89
#define ast_frfree(fr)
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
int ast_slinfactory_read(struct ast_slinfactory *sf, short *buf, size_t samples)
Read samples from a slinfactory.
struct ast_format * format
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
static force_inline void ast_slinear_saturated_add(short *input, short *value)
Definition utils.h:484

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_channel_is_bridged(), ast_channel_set_unbridged_nolock(), 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(), audiohook_list_set_hook_rate(), audiohook_list_set_samplerate_compatibility(), audiohook_list_translate_to_native(), audiohook_list_translate_to_slin(), ast_frame_subclass::format, ast_audiohook::list, ast_audiohook_list::list_internal_samp_rate, ast_audiohook::manipulate_callback, ast_audiohook_list::manipulate_list, NULL, ast_audiohook::read_factory, ast_frame::samples, ast_audiohook_list::spy_list, ast_audiohook::status, ast_frame::subclass, whisper_framehook_timer_update(), ast_audiohook_list::whisper_list, and ast_audiohook::write_factory.

Referenced by ast_audiohook_write_list().

◆ audiohook_list_set_hook_rate()

static void audiohook_list_set_hook_rate ( struct ast_audiohook_list audiohook_list,
struct ast_audiohook audiohook,
int *  rate 
)
static

Set the audiohook's internal sample rate to the audiohook_list's rate, but only when native slin compatibility is turned on.

Parameters
audiohook_listaudiohook_list data object
audiohookthe audiohook to update
ratethe current max internal sample rate

Definition at line 1143 of file audiohook.c.

1145{
1146 /* The rate should always be the max between itself and the hook */
1147 if (audiohook->hook_internal_samp_rate > *rate) {
1148 *rate = audiohook->hook_internal_samp_rate;
1149 }
1150
1151 /*
1152 * If native slin compatibility is turned on then update the audiohook
1153 * with the audiohook_list's current rate. Note, the audiohook's rate is
1154 * set to the audiohook_list's rate and not the given rate. If there is
1155 * a change in rate the hook's rate is changed on its next check.
1156 */
1157 if (audiohook_list->native_slin_compatible) {
1159 audiohook_set_internal_rate(audiohook, audiohook_list->list_internal_samp_rate, 1);
1160 } else {
1162 }
1163}
@ AST_AUDIOHOOK_COMPATIBLE
Definition audiohook.h:66

References AST_AUDIOHOOK_COMPATIBLE, ast_clear_flag, ast_set_flag, audiohook_set_internal_rate(), ast_audiohook::hook_internal_samp_rate, ast_audiohook_list::list_internal_samp_rate, and ast_audiohook_list::native_slin_compatible.

Referenced by audio_audiohook_write_list().

◆ audiohook_list_set_samplerate_compatibility()

static void audiohook_list_set_samplerate_compatibility ( struct ast_audiohook_list audiohook_list)
static

Definition at line 717 of file audiohook.c.

718{
719 struct ast_audiohook *ah = NULL;
720
721 /*
722 * Anytime the samplerate compatibility is set (attach/remove an audiohook) the
723 * list's internal sample rate needs to be reset so that the next time processing
724 * through write_list, if needed, it will get updated to the correct rate.
725 *
726 * A list's internal rate always chooses the higher between its own rate and a
727 * given rate. If the current rate is being driven by an audiohook that wanted a
728 * higher rate then when this audiohook is removed the list's rate would remain
729 * at that level when it should be lower, and with no way to lower it since any
730 * rate compared against it would be lower.
731 *
732 * By setting it back to the lowest rate it can recalculate the new highest rate.
733 */
735
736 audiohook_list->native_slin_compatible = 1;
737 AST_LIST_TRAVERSE(&audiohook_list->manipulate_list, ah, list) {
739 audiohook_list->native_slin_compatible = 0;
740 return;
741 }
742 }
743}
@ AST_AUDIOHOOK_MANIPULATE_ALL_RATES
Definition audiohook.h:75

References AST_AUDIOHOOK_MANIPULATE_ALL_RATES, AST_LIST_TRAVERSE, DEFAULT_INTERNAL_SAMPLE_RATE, ast_audiohook::init_flags, ast_audiohook::list, ast_audiohook_list::list_internal_samp_rate, ast_audiohook_list::manipulate_list, ast_audiohook_list::native_slin_compatible, and NULL.

Referenced by ast_audiohook_attach(), ast_audiohook_remove(), audio_audiohook_write_list(), and dtmf_audiohook_write_list().

◆ audiohook_list_translate_to_native()

static struct ast_frame * audiohook_list_translate_to_native ( struct ast_audiohook_list audiohook_list,
enum ast_audiohook_direction  direction,
struct ast_frame slin_frame,
struct ast_format outformat 
)
static

Definition at line 1111 of file audiohook.c.

1113{
1114 struct ast_audiohook_translate *out_translate = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook_list->out_translate[0] : &audiohook_list->out_translate[1]);
1115 struct ast_frame *outframe = NULL;
1116 if (ast_format_cmp(slin_frame->subclass.format, outformat) == AST_FORMAT_CMP_NOT_EQUAL) {
1117 /* rebuild translators if necessary */
1118 if (ast_format_cmp(out_translate->format, outformat) == AST_FORMAT_CMP_NOT_EQUAL) {
1119 if (out_translate->trans_pvt) {
1120 ast_translator_free_path(out_translate->trans_pvt);
1121 }
1122 if (!(out_translate->trans_pvt = ast_translator_build_path(outformat, slin_frame->subclass.format))) {
1123 return NULL;
1124 }
1125 ao2_replace(out_translate->format, outformat);
1126 }
1127 /* translate back to the format the frame came in as. */
1128 if (!(outframe = ast_translate(out_translate->trans_pvt, slin_frame, 0))) {
1129 return NULL;
1130 }
1131 }
1132 return outframe;
1133}
#define ao2_replace(dst, src)
Replace one object reference with another cleaning up the original.
Definition astobj2.h:501
enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
Compare two formats.
Definition format.c:201
@ AST_FORMAT_CMP_NOT_EQUAL
Definition format.h:38
struct ast_frame * ast_translate(struct ast_trans_pvt *tr, struct ast_frame *f, int consume)
translates one or more frames Apply an input frame into the translator and receive zero or one output...
Definition translate.c:623
struct ast_trans_pvt * ast_translator_build_path(struct ast_format *dest, struct ast_format *source)
Builds a translator path Build a path (possibly NULL) from source to dest.
Definition translate.c:543

References ao2_replace, AST_AUDIOHOOK_DIRECTION_READ, ast_format_cmp(), AST_FORMAT_CMP_NOT_EQUAL, ast_translate(), ast_translator_build_path(), ast_translator_free_path(), ast_frame_subclass::format, ast_audiohook_translate::format, NULL, ast_audiohook_list::out_translate, ast_frame::subclass, and ast_audiohook_translate::trans_pvt.

Referenced by audio_audiohook_write_list().

◆ audiohook_list_translate_to_slin()

static struct ast_frame * audiohook_list_translate_to_slin ( struct ast_audiohook_list audiohook_list,
enum ast_audiohook_direction  direction,
struct ast_frame frame 
)
static

Definition at line 1065 of file audiohook.c.

1067{
1069 &audiohook_list->in_translate[0] : &audiohook_list->in_translate[1]);
1070 struct ast_frame *new_frame = frame;
1071 struct ast_format *slin;
1072
1073 /*
1074 * If we are capable of sample rates other that 8khz, update the internal
1075 * audiohook_list's rate and higher sample rate audio arrives. If native
1076 * slin compatibility is turned on all audiohooks in the list will be
1077 * updated as well during read/write processing.
1078 */
1079 audiohook_list->list_internal_samp_rate =
1081
1083 if (ast_format_cmp(frame->subclass.format, slin) == AST_FORMAT_CMP_EQUAL) {
1084 return new_frame;
1085 }
1086
1087 if (!in_translate->format ||
1088 ast_format_cmp(frame->subclass.format, in_translate->format) != AST_FORMAT_CMP_EQUAL) {
1089 struct ast_trans_pvt *new_trans;
1090
1091 new_trans = ast_translator_build_path(slin, frame->subclass.format);
1092 if (!new_trans) {
1093 return NULL;
1094 }
1095
1096 if (in_translate->trans_pvt) {
1097 ast_translator_free_path(in_translate->trans_pvt);
1098 }
1099 in_translate->trans_pvt = new_trans;
1100
1101 ao2_replace(in_translate->format, frame->subclass.format);
1102 }
1103
1104 if (!(new_frame = ast_translate(in_translate->trans_pvt, frame, 0))) {
1105 return NULL;
1106 }
1107
1108 return new_frame;
1109}
unsigned int ast_format_get_sample_rate(const struct ast_format *format)
Get the sample rate of a media format.
Definition format.c:379
@ AST_FORMAT_CMP_EQUAL
Definition format.h:36
struct ast_format * ast_format_cache_get_slin_by_rate(unsigned int rate)
Retrieve the best signed linear format given a sample rate.
Definition of a media format.
Definition format.c:43
Default structure for translators, with the basic fields and buffers, all allocated as part of the sa...
Definition translate.h:213
#define MAX(a, b)
Definition utils.h:254

References ao2_replace, AST_AUDIOHOOK_DIRECTION_READ, ast_format_cache_get_slin_by_rate(), ast_format_cmp(), AST_FORMAT_CMP_EQUAL, ast_format_get_sample_rate(), ast_translate(), ast_translator_build_path(), ast_translator_free_path(), ast_frame_subclass::format, ast_audiohook_translate::format, ast_audiohook_list::in_translate, ast_audiohook_list::list_internal_samp_rate, MAX, NULL, ast_frame::subclass, and ast_audiohook_translate::trans_pvt.

Referenced by audio_audiohook_write_list().

◆ audiohook_move()

static void audiohook_move ( struct ast_channel old_chan,
struct ast_channel new_chan,
struct ast_audiohook audiohook 
)
static

Definition at line 908 of file audiohook.c.

909{
910 enum ast_audiohook_status oldstatus;
911
912 /* By locking both channels and the audiohook, we can assure that
913 * another thread will not have a chance to read the audiohook's status
914 * as done, even though ast_audiohook_remove signals the trigger
915 * condition.
916 */
917 ast_audiohook_lock(audiohook);
918 oldstatus = audiohook->status;
919
920 ast_audiohook_remove(old_chan, audiohook);
921 ast_audiohook_attach(new_chan, audiohook);
922
923 audiohook->status = oldstatus;
924 ast_audiohook_unlock(audiohook);
925}
int ast_audiohook_remove(struct ast_channel *chan, struct ast_audiohook *audiohook)
Remove an audiohook from a specified channel.
Definition audiohook.c:992
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition audiohook.c:745
ast_audiohook_status
Definition audiohook.h:41

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

Referenced by ast_audiohook_move_all(), and ast_audiohook_move_by_source().

◆ audiohook_read_frame_both()

static struct ast_frame * audiohook_read_frame_both ( struct ast_audiohook audiohook,
size_t  samples,
struct ast_frame **  read_reference,
struct ast_frame **  write_reference 
)
static

Definition at line 481 of file audiohook.c.

482{
483 int count;
484 int usable_read;
485 int usable_write;
486 short adjust_value;
487 short buf1[samples];
488 short buf2[samples];
489 short *read_buf = NULL;
490 short *write_buf = NULL;
491 struct ast_frame frame = {
493 .datalen = sizeof(buf1),
494 .samples = samples,
495 };
496
497 /* Make sure both factories have the required samples */
498 usable_read = (ast_slinfactory_available(&audiohook->read_factory) >= samples ? 1 : 0);
499 usable_write = (ast_slinfactory_available(&audiohook->write_factory) >= samples ? 1 : 0);
500
501 if (!usable_read && !usable_write) {
502 /* If both factories are unusable bail out */
503 ast_debug(3, "Read factory %p and write factory %p both fail to provide %zu samples\n", &audiohook->read_factory, &audiohook->write_factory, samples);
504 return NULL;
505 }
506
507 /* usable_read=1: indicates that read factory have the required samples
508 * usable_write=0: indicates that write factory have not the required samples
509 * usable_write, follows:
510 * 1. Due to RTT issues, the direction write frame has not been received,
511 * and it may take more than (samples/8)*2ms to receive it.
512 * 2. Due to packet loss, the direction write frame could not been received.
513 *
514 * (ast_tvdiff_ms(ast_tvnow(), audiohook->write_time) < (samples/8)*2)(Expression A): This ensures that
515 * packets on both sides can be read correctly even with RTT; however, if the RTT exceeds
516 * (samples/8)*2ms, it may result in the number of packets reading on both sides being greater than the
517 * actual number of packets. for example, this may cause the recording length of mixmonitor to be greater
518 * than the actual duration. Additionally, when RTT = 0 and packet loss is 50%, some packets in the
519 * write direction will never arrive. In this case, continuously waiting will only cause the read
520 * factory to exceed the safe length limit, resulting in both the read factory and write factory
521 * being cleared, thus same packets received in the read direction cannot be read.
522 *
523 * (ast_slinfactory_available(&audiohook->read_factory) < 2 * samples)(Expression B): This ensures that
524 * packets on both sides can be read correctly, even in the presence of packet loss; regardless of
525 * the amount of packet loss.
526 *
527 * (Expression A)&&(Expression B): This combination can comprehensively solve both RTT and packet loss
528 * issues; however when RTT exceeds (samples/8)*2ms, it may result in the number of packets read
529 * on both sides being greater than the actual number of packets, causing the recording length of
530 * mixmonitor to be longer than the actual duration. We can adjust (ast_tvdiff_ms(ast_tvnow(),
531 * audiohook->write_time)<(samples/8)*2) && (ast_slinfactory_available(&audiohook->read_factory) <
532 * 2 * samples) according to actual needs, for example, setting it to (ast_tvdiff_ms(ast_tvnow(),
533 * audiohook->write_time) < (samples/8)*4) && (ast_slinfactory_available(&audiohook->read_factory)
534 * < 4 * samples).
535 *
536 * Update:
537 * Increased time and sample thresholds allow for better handling of asymmetric streams
538 * (e.g., mixed codecs like alaw and G.722) and high RTT conditions.
539 * This avoids premature frame reads when one direction is delayed, which can cause
540 * audio tearing or broken recordings.
541 * Specifically addresses issues with MixMonitor when recording directly on a channel
542 * that is part of a bridge with different sample rates or codecs.
543 * A slight overrun in recording duration is acceptable in exchange for audio stability.
544 */
545 if (usable_read && !usable_write && (ast_tvdiff_ms(ast_tvnow(), audiohook->write_time) < (samples/8)*4) && (ast_slinfactory_available(&audiohook->read_factory) < 4 * samples)) {
546 ast_debug(3, "Write factory %p was pretty quick last time, waiting for them.\n", &audiohook->write_factory);
547 return NULL;
548 }
549
550 /* As shown in the above comment. */
551 if (usable_write && !usable_read && (ast_tvdiff_ms(ast_tvnow(), audiohook->read_time) < (samples/8)*4) && (ast_slinfactory_available(&audiohook->write_factory) < 4 * samples)) {
552 ast_debug(3, "Read factory %p was pretty quick last time, waiting for them.\n", &audiohook->read_factory);
553 return NULL;
554 }
555
556 /* Start with the read factory... if there are enough samples, read them in */
557 if (usable_read) {
558 if (ast_slinfactory_read(&audiohook->read_factory, buf1, samples)) {
559 read_buf = buf1;
560
561 if ((ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_READ))) {
562 /* Clear the frame data if we are muting */
563 memset(buf1, 0, sizeof(buf1));
564 } else if (audiohook->options.read_volume) {
565 /* Adjust read volume if need be */
566 adjust_value = abs(audiohook->options.read_volume);
567 for (count = 0; count < samples; count++) {
568 if (audiohook->options.read_volume > 0) {
569 ast_slinear_saturated_multiply(&buf1[count], &adjust_value);
570 } else if (audiohook->options.read_volume < 0) {
571 ast_slinear_saturated_divide(&buf1[count], &adjust_value);
572 }
573 }
574 }
575 }
576 } else {
577 ast_debug(1, "Failed to get %d samples from read factory %p\n", (int)samples, &audiohook->read_factory);
578 }
579
580 /* Move on to the write factory... if there are enough samples, read them in */
581 if (usable_write) {
582 if (ast_slinfactory_read(&audiohook->write_factory, buf2, samples)) {
583 write_buf = buf2;
584
585 if ((ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_WRITE))) {
586 /* Clear the frame data if we are muting */
587 memset(buf2, 0, sizeof(buf2));
588 } else if (audiohook->options.write_volume) {
589 /* Adjust write volume if need be */
590 adjust_value = abs(audiohook->options.write_volume);
591 for (count = 0; count < samples; count++) {
592 if (audiohook->options.write_volume > 0) {
593 ast_slinear_saturated_multiply(&buf2[count], &adjust_value);
594 } else if (audiohook->options.write_volume < 0) {
595 ast_slinear_saturated_divide(&buf2[count], &adjust_value);
596 }
597 }
598 }
599 }
600 } else {
601 ast_debug(3, "Failed to get %d samples from write factory %p\n", (int)samples, &audiohook->write_factory);
602 }
603
605
606 /* Should we substitute silence if one side lacks audio? */
608 if (read_reference && !read_buf && write_buf) {
609 read_buf = buf1;
610 memset(buf1, 0, sizeof(buf1));
611 } else if (write_reference && read_buf && !write_buf) {
612 write_buf = buf2;
613 memset(buf2, 0, sizeof(buf2));
614 }
615 }
616
617 /* Basically we figure out which buffer to use... and if mixing can be done here */
618 if (read_buf && read_reference) {
619 frame.data.ptr = read_buf;
620 *read_reference = ast_frdup(&frame);
621 }
622 if (write_buf && write_reference) {
623 frame.data.ptr = write_buf;
624 *write_reference = ast_frdup(&frame);
625 }
626
627 /* Make the correct buffer part of the built frame, so it gets duplicated. */
628 if (read_buf) {
629 frame.data.ptr = read_buf;
630 if (write_buf) {
631 for (count = 0; count < samples; count++) {
633 }
634 }
635 } else if (write_buf) {
636 frame.data.ptr = write_buf;
637 } else {
638 return NULL;
639 }
640
641 /* Yahoo, a combined copy of the audio! */
642 return ast_frdup(&frame);
643}
@ AST_AUDIOHOOK_SUBSTITUTE_SILENCE
Definition audiohook.h:68
void write_buf(int file, char *buffer, int num)
Definition eagi_proxy.c:312
#define abs(x)
Definition f2c.h:195
#define ast_frdup(fr)
Copies a frame.
struct ast_audiohook_options options
Definition audiohook.h:119
union ast_frame::@237 data
static force_inline void ast_slinear_saturated_multiply(short *input, short *value)
Definition utils.h:510
static force_inline void ast_slinear_saturated_divide(short *input, short *value)
Definition utils.h:539

References abs, AST_AUDIOHOOK_MUTE_READ, AST_AUDIOHOOK_MUTE_WRITE, AST_AUDIOHOOK_SUBSTITUTE_SILENCE, ast_debug, ast_format_cache_get_slin_by_rate(), AST_FRAME_VOICE, ast_frdup, ast_slinear_saturated_add(), ast_slinear_saturated_divide(), ast_slinear_saturated_multiply(), ast_slinfactory_available(), ast_slinfactory_read(), ast_test_flag, ast_tvdiff_ms(), ast_tvnow(), ast_frame::data, ast_frame_subclass::format, ast_frame::frametype, ast_audiohook::hook_internal_samp_rate, NULL, ast_audiohook::options, ast_frame::ptr, ast_audiohook::read_factory, ast_audiohook::read_time, ast_audiohook_options::read_volume, ast_frame::samples, ast_frame::subclass, write_buf(), ast_audiohook::write_factory, ast_audiohook::write_time, and ast_audiohook_options::write_volume.

Referenced by audiohook_read_frame_helper().

◆ audiohook_read_frame_helper()

static struct ast_frame * audiohook_read_frame_helper ( struct ast_audiohook audiohook,
size_t  samples,
enum ast_audiohook_direction  direction,
struct ast_format format,
struct ast_frame **  read_reference,
struct ast_frame **  write_reference 
)
static

Definition at line 645 of file audiohook.c.

646{
647 struct ast_frame *read_frame = NULL, *final_frame = NULL;
648 struct ast_format *slin;
649
650 /*
651 * Update the rate if compatibility mode is turned off or if it is
652 * turned on and the format rate is higher than the current rate.
653 *
654 * This makes it so any unnecessary rate switching/resetting does
655 * not take place and also any associated audiohook_list's internal
656 * sample rate maintains the highest sample rate between hooks.
657 */
658 if (!ast_test_flag(audiohook, AST_AUDIOHOOK_COMPATIBLE) ||
662 }
663
664 /* If the sample rate of the requested format differs from that of the underlying audiohook
665 * sample rate determine how many samples we actually need to get from the audiohook. This
666 * needs to occur as the signed linear factory stores them at the rate of the audiohook.
667 * We do this by determining the duration of audio they've requested and then determining
668 * how many samples that would be in the audiohook format.
669 */
670 if (ast_format_get_sample_rate(format) != audiohook->hook_internal_samp_rate) {
671 samples = (audiohook->hook_internal_samp_rate / 1000) * (samples / (ast_format_get_sample_rate(format) / 1000));
672 }
673
675 audiohook_read_frame_both(audiohook, samples, read_reference, write_reference) :
676 audiohook_read_frame_single(audiohook, samples, direction)))) {
677 return NULL;
678 }
679
681
682 /* If they don't want signed linear back out, we'll have to send it through the translation path */
683 if (ast_format_cmp(format, slin) != AST_FORMAT_CMP_EQUAL) {
684 /* Rebuild translation path if different format then previously */
685 if (ast_format_cmp(format, audiohook->format) == AST_FORMAT_CMP_NOT_EQUAL) {
686 if (audiohook->trans_pvt) {
688 audiohook->trans_pvt = NULL;
689 }
690
691 /* 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 */
692 if (!(audiohook->trans_pvt = ast_translator_build_path(format, slin))) {
694 return NULL;
695 }
696 ao2_replace(audiohook->format, format);
697 }
698 /* Convert to requested format, and allow the read in frame to be freed */
699 final_frame = ast_translate(audiohook->trans_pvt, read_frame, 1);
700 } else {
701 final_frame = read_frame;
702 }
703
704 return final_frame;
705}
static struct ast_frame * audiohook_read_frame_single(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction)
Definition audiohook.c:447
static struct ast_frame * audiohook_read_frame_both(struct ast_audiohook *audiohook, size_t samples, struct ast_frame **read_reference, struct ast_frame **write_reference)
Definition audiohook.c:481

References ao2_replace, AST_AUDIOHOOK_COMPATIBLE, AST_AUDIOHOOK_DIRECTION_BOTH, ast_format_cache_get_slin_by_rate(), ast_format_cmp(), AST_FORMAT_CMP_EQUAL, AST_FORMAT_CMP_NOT_EQUAL, ast_format_get_sample_rate(), ast_frfree, ast_test_flag, ast_translate(), ast_translator_build_path(), ast_translator_free_path(), audiohook_read_frame_both(), audiohook_read_frame_single(), audiohook_set_internal_rate(), ast_audiohook::format, ast_audiohook::hook_internal_samp_rate, NULL, read_frame(), and ast_audiohook::trans_pvt.

Referenced by ast_audiohook_read_frame(), and ast_audiohook_read_frame_all().

◆ audiohook_read_frame_single()

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

Definition at line 447 of file audiohook.c.

448{
449 struct ast_slinfactory *factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_factory : &audiohook->write_factory);
450 int vol = (direction == AST_AUDIOHOOK_DIRECTION_READ ? audiohook->options.read_volume : audiohook->options.write_volume);
451 short buf[samples];
452 struct ast_frame frame = {
454 .subclass.format = ast_format_cache_get_slin_by_rate(audiohook->hook_internal_samp_rate),
455 .data.ptr = buf,
456 .datalen = sizeof(buf),
457 .samples = samples,
458 };
459
460 /* Ensure the factory is able to give us the samples we want */
461 if (samples > ast_slinfactory_available(factory)) {
462 return NULL;
463 }
464
465 /* Read data in from factory */
466 if (!ast_slinfactory_read(factory, buf, samples)) {
467 return NULL;
468 }
469
470 if (SHOULD_MUTE(audiohook, direction)) {
471 /* Swap frame data for zeros if mute is required */
472 ast_frame_clear(&frame);
473 } else if (vol) {
474 /* If a volume adjustment needs to be applied apply it */
475 ast_frame_adjust_volume(&frame, vol);
476 }
477
478 return ast_frdup(&frame);
479}
#define SHOULD_MUTE(hook, dir)
Definition audiohook.c:386
char buf[BUFSIZE]
Definition eagi_proxy.c:66
int ast_frame_clear(struct ast_frame *frame)
Clear all audio samples from an ast_frame. The frame must be AST_FRAME_VOICE and AST_FORMAT_SLINEAR.
Definition main/frame.c:857
int ast_frame_adjust_volume(struct ast_frame *f, int adjustment)
Adjusts the volume of the audio samples contained in a frame.
Definition main/frame.c:787

References AST_AUDIOHOOK_DIRECTION_READ, ast_format_cache_get_slin_by_rate(), ast_frame_adjust_volume(), ast_frame_clear(), AST_FRAME_VOICE, ast_frdup, ast_slinfactory_available(), ast_slinfactory_read(), buf, ast_frame::frametype, ast_audiohook::hook_internal_samp_rate, NULL, ast_audiohook::options, ast_audiohook::read_factory, ast_audiohook_options::read_volume, ast_frame::samples, SHOULD_MUTE, ast_audiohook::write_factory, and ast_audiohook_options::write_volume.

Referenced by audiohook_read_frame_helper().

◆ audiohook_set_internal_rate()

static int audiohook_set_internal_rate ( struct ast_audiohook audiohook,
int  rate,
int  reset 
)
static

Definition at line 294 of file audiohook.c.

295{
296 struct ast_format *slin;
297
298 if (audiohook->hook_internal_samp_rate == rate) {
299 return 0;
300 }
301
302 audiohook->hook_internal_samp_rate = rate;
303
305
306 /* Setup the factories that are needed for this audiohook type */
307 switch (audiohook->type) {
310 if (reset) {
313 }
316 break;
317 default:
318 break;
319 }
320
321 return 0;
322}
int ast_slinfactory_init_with_format(struct ast_slinfactory *sf, struct ast_format *slin_out)
Initialize a slinfactory.
Definition slinfactory.c:46

References AST_AUDIOHOOK_TYPE_SPY, AST_AUDIOHOOK_TYPE_WHISPER, ast_format_cache_get_slin_by_rate(), ast_slinfactory_destroy(), ast_slinfactory_init_with_format(), ast_audiohook::hook_internal_samp_rate, ast_audiohook::read_factory, ast_audiohook::type, and ast_audiohook::write_factory.

Referenced by ast_audiohook_attach(), ast_audiohook_init(), audiohook_list_set_hook_rate(), and audiohook_read_frame_helper().

◆ audiohook_volume_callback()

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
Return values
0on success
-1on failure

Definition at line 1502 of file audiohook.c.

1503{
1504 struct ast_datastore *datastore = NULL;
1506 float *gain = NULL;
1507
1508 /* If the audiohook is shutting down don't even bother */
1510 return 0;
1511 }
1512
1513 /* Try to find the datastore containing adjustment information, if we can't just bail out */
1514 if (!(datastore = ast_channel_datastore_find(chan, &audiohook_volume_datastore, NULL))) {
1515 return 0;
1516 }
1517
1518 audiohook_volume = datastore->data;
1519
1520 /* Based on direction grab the appropriate adjustment value */
1525 }
1526
1527 /* If an adjustment value is present modify the frame */
1528 if (gain && *gain) {
1529 ast_frame_adjust_volume_float(frame, *gain);
1530 }
1531
1532 return 0;
1533}
static const struct ast_datastore_info audiohook_volume_datastore
Datastore used to store audiohook volume information.
Definition audiohook.c:1489
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition channel.c:2390
int ast_frame_adjust_volume_float(struct ast_frame *f, float adjustment)
Adjusts the volume of the audio samples contained in a frame.
Definition main/frame.c:812
Structure for a data store object.
Definition datastore.h:64
void * data
Definition datastore.h:66
struct ast_audiohook audiohook
Definition audiohook.c:1467

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

Referenced by audiohook_volume_get().

◆ audiohook_volume_destroy()

static void audiohook_volume_destroy ( void *  data)
static

Callback used to destroy the audiohook volume datastore.

Parameters
dataVolume information structure

Definition at line 1475 of file audiohook.c.

1476{
1477 struct audiohook_volume *audiohook_volume = data;
1478
1479 /* Destroy the audiohook as it is no longer in use */
1481
1482 /* Finally free ourselves, we are of no more use */
1484
1485 return;
1486}
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition audiohook.c:348

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

◆ audiohook_volume_get()

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
chanChannel to look on
createWhether to create the datastore if not found
Returns
audiohook_volume structure on success
Return values
NULLon failure

Definition at line 1541 of file audiohook.c.

1542{
1543 struct ast_datastore *datastore = NULL;
1545
1546 /* If we are able to find the datastore return the contents (which is actually an audiohook_volume structure) */
1547 if ((datastore = ast_channel_datastore_find(chan, &audiohook_volume_datastore, NULL))) {
1548 return datastore->data;
1549 }
1550
1551 /* 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 */
1552 if (!create || !(datastore = ast_datastore_alloc(&audiohook_volume_datastore, NULL))) {
1553 return NULL;
1554 }
1555
1556 /* Create a new audiohook_volume structure to contain our adjustments and audiohook */
1557 if (!(audiohook_volume = ast_calloc(1, sizeof(*audiohook_volume)))) {
1558 ast_datastore_free(datastore);
1559 return NULL;
1560 }
1561
1562 /* Setup our audiohook structure so we can manipulate the audio */
1565
1566 /* Attach the audiohook_volume blob to the datastore and attach to the channel */
1567 datastore->data = audiohook_volume;
1568 ast_channel_datastore_add(chan, datastore);
1569
1570 /* All is well... put the audiohook into motion */
1572
1573 return audiohook_volume;
1574}
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.
Definition audiohook.c:1502
int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source, enum ast_audiohook_init_flags init_flags)
Initialize an audiohook structure.
Definition audiohook.c:324
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition channel.c:2376
#define ast_datastore_alloc(info, uid)
Definition datastore.h:85
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition datastore.c:68

References ast_audiohook_attach(), ast_audiohook_init(), AST_AUDIOHOOK_MANIPULATE_ALL_RATES, 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(), audiohook_volume_datastore, ast_datastore::data, ast_audiohook::manipulate_callback, and NULL.

Referenced by ast_audiohook_volume_adjust_float(), ast_audiohook_volume_get_float(), and ast_audiohook_volume_set_float().

◆ dtmf_audiohook_write_list()

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
chanChannel that the list is coming off of
audiohook_listList of audiohooks
directionDirection frame is coming in from
frameThe frame itself
Returns
frame on success
Return values
NULLon failure

Definition at line 1033 of file audiohook.c.

1034{
1035 struct ast_audiohook *audiohook = NULL;
1036 int removed = 0;
1037
1038 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->manipulate_list, audiohook, list) {
1039 ast_audiohook_lock(audiohook);
1040 if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
1042 removed = 1;
1044 ast_audiohook_unlock(audiohook);
1045 audiohook->manipulate_callback(audiohook, NULL, NULL, 0);
1046 if (ast_channel_is_bridged(chan)) {
1048 }
1049 continue;
1050 }
1051 if (ast_test_flag(audiohook, AST_AUDIOHOOK_WANTS_DTMF)) {
1052 audiohook->manipulate_callback(audiohook, chan, frame, direction);
1053 }
1054 ast_audiohook_unlock(audiohook);
1055 }
1057
1058 /* if an audiohook got removed, reset samplerate compatibility */
1059 if (removed) {
1061 }
1062 return frame;
1063}
@ AST_AUDIOHOOK_WANTS_DTMF
Definition audiohook.h:58

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

Referenced by ast_audiohook_write_list().

◆ find_audiohook_by_source()

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_listThe list of audiohooks to search in
sourceThe source of the audiohook we wish to find
Returns
corresponding audiohook
Return values
NULLif it cannot be found

Definition at line 883 of file audiohook.c.

884{
885 struct ast_audiohook *audiohook = NULL;
886
887 AST_LIST_TRAVERSE(&audiohook_list->spy_list, audiohook, list) {
888 if (!strcasecmp(audiohook->source, source)) {
889 return audiohook;
890 }
891 }
892
893 AST_LIST_TRAVERSE(&audiohook_list->whisper_list, audiohook, list) {
894 if (!strcasecmp(audiohook->source, source)) {
895 return audiohook;
896 }
897 }
898
899 AST_LIST_TRAVERSE(&audiohook_list->manipulate_list, audiohook, list) {
900 if (!strcasecmp(audiohook->source, source)) {
901 return audiohook;
902 }
903 }
904
905 return NULL;
906}

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

Referenced by ast_audiohook_detach_source(), ast_audiohook_move_by_source(), and ast_audiohook_set_mute().

◆ whisper_framehook_attach()

static int whisper_framehook_attach ( struct ast_channel chan,
struct ast_audiohook_list audiohook_list 
)
static

Definition at line 248 of file audiohook.c.

249{
250 struct ast_framehook_interface interface = {
252 .event_cb = whisper_framehook_event_cb,
253 .destroy_cb = whisper_framehook_destroy_cb,
254 };
255 struct whisper_framehook_data *hook_data;
256 int framehook_id;
257
258 if (audiohook_list->whisper_framehook_id >= 0) {
259 return 0;
260 }
261
262 hook_data = ast_calloc(1, sizeof(*hook_data));
263 if (!hook_data) {
264 return -1;
265 }
266 hook_data->timer_fd = -1;
267 hook_data->timer_fd_slot = -1;
269
270 interface.data = hook_data;
271 framehook_id = ast_framehook_attach(chan, &interface);
272 if (framehook_id < 0) {
273 ast_free(hook_data);
274 return -1;
275 }
276
277 audiohook_list->whisper_framehook_id = framehook_id;
278 audiohook_list->whisper_framehook_data = hook_data;
279
280 return 0;
281}
static void whisper_framehook_destroy_cb(void *data)
Definition audiohook.c:117
#define AST_WHISPER_TIMER_INTERVAL
Definition audiohook.c:49
static struct ast_frame * whisper_framehook_event_cb(struct ast_channel *chan, struct ast_frame *frame, enum ast_framehook_event event, void *data)
Definition audiohook.c:122
int ast_framehook_attach(struct ast_channel *chan, struct ast_framehook_interface *i)
Attach an framehook onto a channel for frame interception.
Definition framehook.c:132
#define AST_FRAMEHOOK_INTERFACE_VERSION
Definition framehook.h:227
struct whisper_framehook_data * whisper_framehook_data
Definition audiohook.c:86

References ast_calloc, ast_framehook_attach(), AST_FRAMEHOOK_INTERFACE_VERSION, ast_free, AST_WHISPER_TIMER_INTERVAL, ast_framehook_interface::data, whisper_framehook_data::timer_fd, whisper_framehook_data::timer_fd_slot, whisper_framehook_data::timer_interval, ast_framehook_interface::version, ast_audiohook_list::whisper_framehook_data, whisper_framehook_destroy_cb(), whisper_framehook_event_cb(), and ast_audiohook_list::whisper_framehook_id.

Referenced by ast_audiohook_attach().

◆ whisper_framehook_destroy_cb()

static void whisper_framehook_destroy_cb ( void *  data)
static

Definition at line 117 of file audiohook.c.

118{
119 ast_free(data);
120}

References ast_free.

Referenced by whisper_framehook_attach().

◆ whisper_framehook_detach()

static void whisper_framehook_detach ( struct ast_channel chan,
struct ast_audiohook_list audiohook_list 
)
static

Definition at line 283 of file audiohook.c.

284{
285 if (audiohook_list->whisper_framehook_id < 0) {
286 return;
287 }
288
289 ast_framehook_detach(chan, audiohook_list->whisper_framehook_id);
290 audiohook_list->whisper_framehook_id = -1;
291 audiohook_list->whisper_framehook_data = NULL;
292}
int ast_framehook_detach(struct ast_channel *chan, int framehook_id)
Detach an framehook from a channel.
Definition framehook.c:177

References ast_framehook_detach(), NULL, ast_audiohook_list::whisper_framehook_data, and ast_audiohook_list::whisper_framehook_id.

Referenced by ast_audiohook_remove().

◆ whisper_framehook_event_cb()

static struct ast_frame * whisper_framehook_event_cb ( struct ast_channel chan,
struct ast_frame frame,
enum ast_framehook_event  event,
void *  data 
)
static

Definition at line 122 of file audiohook.c.

126{
127 struct whisper_framehook_data *hook_data = data;
128 struct ast_audiohook_list *audiohook_list;
129 int rate;
130 int samples;
131 int write_res;
133 struct ast_frame tmp_frame = {
135 .offset = AST_FRIENDLY_OFFSET,
136 .data.ptr = buf,
137 .datalen = sizeof(buf),
139 };
140 struct ast_frame *dup;
141
142 switch (event) {
144 /* We only care about timer driven READ events */
145 if (ast_channel_fdno(chan) != hook_data->timer_fd_slot
146 || !hook_data->timer
147 || ast_timer_ack(hook_data->timer, 1) < 0) {
148 return frame;
149 }
150 break;
152 /*
153 * Track WRITEs that are not triggered by the framehook so we can
154 * avoid overlapping with WRITEs that are triggered by the framehook.
155 */
156 if (frame && frame->frametype == AST_FRAME_VOICE
157 && (!frame->src || strcmp(frame->src, AST_WHISPER_TIMER_SRC))) {
158 hook_data->last_external_write_tv = ast_tvnow();
159 }
160 return frame;
162 /* Initialize the timer */
163 if (!hook_data->timer) {
164 hook_data->timer = ast_timer_open();
165 if (!hook_data->timer) {
166 return frame;
167 }
168 hook_data->timer_fd = ast_timer_fd(hook_data->timer);
169 hook_data->timer_fd_slot = ast_channel_fd_add(chan, hook_data->timer_fd);
170 if (hook_data->timer_fd_slot < 0) {
171 ast_timer_close(hook_data->timer);
172 hook_data->timer = NULL;
173 hook_data->timer_fd = -1;
174 return frame;
175 }
176 ast_timer_set_rate(hook_data->timer, 1000 / hook_data->timer_interval);
177 }
178 return frame;
180 /* Clean up the timer */
181 if (hook_data->timer_fd_slot >= 0) {
182 ast_channel_set_fd(chan, hook_data->timer_fd_slot, -1);
183 }
184 if (hook_data->timer) {
185 ast_timer_close(hook_data->timer);
186 }
187 hook_data->timer = NULL;
188 hook_data->timer_fd = -1;
189 hook_data->timer_fd_slot = -1;
190 return frame;
191 }
192
193 /*
194 * If normal outbound media frames are actively flowing (determined by tracking the
195 * WRITE events above,) skip timer-based fallback injection. This avoids overlapping
196 * WRITE frames and the resulting garbled audio.
197 */
198 if (!ast_tvzero(hook_data->last_external_write_tv)
200 <= (hook_data->timer_interval * 2)) {
201 return frame;
202 }
203
204 audiohook_list = ast_channel_audiohooks(chan);
205
206 /*
207 * As this framehook is dependant on the whisper audiohook(s) existing, this check
208 * should never fail.
209 */
210 if (!audiohook_list || AST_LIST_EMPTY(&audiohook_list->whisper_list)) {
211 return frame;
212 }
213
214 rate = audiohook_list->list_internal_samp_rate;
215 if (rate <= 0) {
217 }
218 samples = (rate / 1000) * hook_data->timer_interval;
219 if (!samples || samples > ARRAY_LEN(buf)) {
220 return frame;
221 }
222
223 memset(buf, 0, samples * sizeof(buf[0]));
225 tmp_frame.samples = samples;
226 tmp_frame.datalen = samples * sizeof(buf[0]);
227
228 dup = ast_frdup(&tmp_frame);
229 if (!dup) {
230 return frame;
231 }
232
233 /*
234 * Invoke a write on the channel with our frame to trigger mixing in
235 * audio from the whisper audiohook list.
236 */
237 ast_channel_unlock(chan);
238 write_res = ast_write(chan, dup);
239 ast_channel_lock(chan);
240
241 if (write_res < 0) {
242 ast_frfree(dup);
243 }
244
245 return &ast_null_frame;
246}
#define AST_WHISPER_TIMER_SRC
Definition audiohook.c:55
int ast_channel_fdno(const struct ast_channel *chan)
int ast_channel_fd_add(struct ast_channel *chan, int value)
Add a file descriptor to the channel without a fixed position.
int ast_write(struct ast_channel *chan, struct ast_frame *frame)
Write a frame to a channel This function writes the given frame to the indicated channel.
Definition channel.c:5167
void ast_channel_set_fd(struct ast_channel *chan, int which, int fd)
Definition channel.c:2417
@ AST_FRAMEHOOK_EVENT_ATTACHED
Definition framehook.h:154
@ AST_FRAMEHOOK_EVENT_DETACHED
Definition framehook.h:155
@ AST_FRAMEHOOK_EVENT_WRITE
Definition framehook.h:153
@ AST_FRAMEHOOK_EVENT_READ
Definition framehook.h:152
#define AST_FRIENDLY_OFFSET
Offset into a frame's data buffer.
struct ast_frame ast_null_frame
Definition main/frame.c:79
struct ast_timer * timer
Definition audiohook.c:65
struct timeval last_external_write_tv
Definition audiohook.c:69
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition time.h:117
void ast_timer_close(struct ast_timer *handle)
Close an opened timing handle.
Definition timing.c:154
int ast_timer_ack(const struct ast_timer *handle, unsigned int quantity)
Acknowledge a timer event.
Definition timing.c:171
int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate)
Set the timing tick rate.
Definition timing.c:166
struct ast_timer * ast_timer_open(void)
Open a timer.
Definition timing.c:122
int ast_timer_fd(const struct ast_timer *handle)
Get a poll()-able file descriptor for a timer.
Definition timing.c:161
#define ARRAY_LEN(a)
Definition utils.h:706

References ARRAY_LEN, ast_channel_audiohooks(), ast_channel_fd_add(), ast_channel_fdno(), ast_channel_lock, ast_channel_set_fd(), ast_channel_unlock, ast_format_cache_get_slin_by_rate(), AST_FRAME_VOICE, AST_FRAMEHOOK_EVENT_ATTACHED, AST_FRAMEHOOK_EVENT_DETACHED, AST_FRAMEHOOK_EVENT_READ, AST_FRAMEHOOK_EVENT_WRITE, ast_frdup, ast_frfree, AST_FRIENDLY_OFFSET, AST_LIST_EMPTY, ast_null_frame, ast_timer_ack(), ast_timer_close(), ast_timer_fd(), ast_timer_open(), ast_timer_set_rate(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), AST_WHISPER_TIMER_INTERVAL_MAX, AST_WHISPER_TIMER_SRC, ast_write(), buf, ast_frame::datalen, DEFAULT_INTERNAL_SAMPLE_RATE, ast_frame_subclass::format, ast_frame::frametype, whisper_framehook_data::last_external_write_tv, ast_audiohook_list::list_internal_samp_rate, NULL, ast_frame::samples, ast_frame::src, ast_frame::subclass, whisper_framehook_data::timer, whisper_framehook_data::timer_fd, whisper_framehook_data::timer_fd_slot, whisper_framehook_data::timer_interval, and ast_audiohook_list::whisper_list.

Referenced by whisper_framehook_attach().

◆ whisper_framehook_timer_update()

static void whisper_framehook_timer_update ( struct ast_audiohook_list audiohook_list,
struct ast_frame start_frame,
int  internal_sample_rate,
int  samples 
)
static

Definition at line 89 of file audiohook.c.

93{
94 struct whisper_framehook_data *hook_data;
95 int interval;
96
97 hook_data = audiohook_list->whisper_framehook_data;
98 if (!hook_data || internal_sample_rate <= 0 || samples <= 0) {
99 return;
100 }
101
102 if (start_frame->src && !strcmp(start_frame->src, AST_WHISPER_TIMER_SRC)) {
103 return;
104 }
105
106 interval = AST_WHISPER_TIMER_CLAMP((samples * 1000) / internal_sample_rate);
107 if (interval == hook_data->timer_interval) {
108 return;
109 }
110
111 hook_data->timer_interval = interval;
112 if (hook_data->timer) {
113 ast_timer_set_rate(hook_data->timer, 1000 / interval);
114 }
115}
#define AST_WHISPER_TIMER_CLAMP(interval)
Definition audiohook.c:52

References ast_timer_set_rate(), AST_WHISPER_TIMER_CLAMP, AST_WHISPER_TIMER_SRC, ast_frame::src, whisper_framehook_data::timer, whisper_framehook_data::timer_interval, and ast_audiohook_list::whisper_framehook_data.

Referenced by audio_audiohook_write_list().

Variable Documentation

◆ audiohook_volume_datastore

const struct ast_datastore_info audiohook_volume_datastore
static
Initial value:
= {
.type = "Volume",
}
static void audiohook_volume_destroy(void *data)
Callback used to destroy the audiohook volume datastore.
Definition audiohook.c:1475

Datastore used to store audiohook volume information.

Definition at line 1489 of file audiohook.c.

1489 {
1490 .type = "Volume",
1491 .destroy = audiohook_volume_destroy,
1492};

Referenced by audiohook_volume_callback(), and audiohook_volume_get().