From c78240b06b3a33180423caa38053548ac8d98b31 Mon Sep 17 00:00:00 2001 From: file Date: Fri, 21 Mar 2008 17:58:59 +0000 Subject: Merge over ast_audiohook_volume branch. This adds API calls for use by developers to adjust the volume on a channel. git-svn-id: http://svn.digium.com/svn/asterisk/trunk@110542 f38db490-d61c-443f-a65b-d21fe96a405b --- include/asterisk/audiohook.h | 23 ++++++ main/audiohook.c | 184 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 207 insertions(+) diff --git a/include/asterisk/audiohook.h b/include/asterisk/audiohook.h index ba5d3b899..4ebd19e5d 100644 --- a/include/asterisk/audiohook.h +++ b/include/asterisk/audiohook.h @@ -206,6 +206,29 @@ int ast_channel_audiohook_count_by_source_running(struct ast_channel *chan, cons */ #define ast_audiohook_unlock(ah) ast_mutex_unlock(&(ah)->lock) +/*! \brief Adjust the volume on frames read from or written to a channel + * \param chan Channel to muck with + * \param direction Direction to set on + * \param volume Value to adjust the volume by + * \return Returns 0 on success, -1 on failure + */ +int ast_audiohook_volume_set(struct ast_channel *chan, enum ast_audiohook_direction direction, int volume); + +/*! \brief Retrieve the volume adjustment value on frames read from or written to a channel + * \param chan Channel to retrieve volume adjustment from + * \param direction Direction to retrieve + * \return Returns adjustment value + */ +int ast_audiohook_volume_get(struct ast_channel *chan, enum ast_audiohook_direction direction); + +/*! \brief Adjust the volume on frames read from or written to a channel + * \param chan Channel to muck with + * \param direction Direction to increase + * \param volume Value to adjust the adjustment by + * \return Returns 0 on success, -1 on failure + */ +int ast_audiohook_volume_adjust(struct ast_channel *chan, enum ast_audiohook_direction direction, int volume); + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/main/audiohook.c b/main/audiohook.c index 5581037d7..61834aad3 100644 --- a/main/audiohook.c +++ b/main/audiohook.c @@ -712,3 +712,187 @@ int ast_channel_audiohook_count_by_source_running(struct ast_channel *chan, cons return count; } +/*! \brief Audiohook volume adjustment structure */ +struct audiohook_volume { + struct ast_audiohook audiohook; /*!< Audiohook attached to the channel */ + int read_adjustment; /*!< Value to adjust frames read from the channel by */ + int write_adjustment; /*!< Value to adjust frames written to the channel by */ +}; + +/*! \brief Callback used to destroy the audiohook volume datastore + * \param data Volume information structure + * \return Returns nothing + */ +static void audiohook_volume_destroy(void *data) +{ + struct audiohook_volume *audiohook_volume = data; + + /* Destroy the audiohook as it is no longer in use */ + ast_audiohook_destroy(&audiohook_volume->audiohook); + + /* Finally free ourselves, we are of no more use */ + ast_free(audiohook_volume); + + return; +} + +/*! \brief Datastore used to store audiohook volume information */ +static const struct ast_datastore_info audiohook_volume_datastore = { + .type = "Volume", + .destroy = audiohook_volume_destroy, +}; + +/*! \brief Helper function which actually gets called by audiohooks to perform the adjustment + * \param audiohook Audiohook attached to the channel + * \param chan Channel we are attached to + * \param frame Frame of audio we want to manipulate + * \param direction Direction the audio came in from + * \return Returns 0 on success, -1 on failure + */ +static int audiohook_volume_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction) +{ + struct ast_datastore *datastore = NULL; + struct audiohook_volume *audiohook_volume = NULL; + int *gain = NULL; + + /* If the audiohook is shutting down don't even bother */ + if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) { + return 0; + } + + /* Try to find the datastore containg adjustment information, if we can't just bail out */ + if (!(datastore = ast_channel_datastore_find(chan, &audiohook_volume_datastore, NULL))) { + return 0; + } + + audiohook_volume = datastore->data; + + /* Based on direction grab the appropriate adjustment value */ + if (direction == AST_AUDIOHOOK_DIRECTION_READ) { + gain = &audiohook_volume->read_adjustment; + } else if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) { + gain = &audiohook_volume->write_adjustment; + } + + /* If an adjustment value is present modify the frame */ + if (gain && *gain) { + ast_frame_adjust_volume(frame, *gain); + } + + return 0; +} + +/*! \brief Helper function which finds and optionally creates an audiohook_volume_datastore datastore on a channel + * \param chan Channel to look on + * \param create Whether to create the datastore if not found + * \return Returns audiohook_volume structure on success, NULL on failure + */ +static struct audiohook_volume *audiohook_volume_get(struct ast_channel *chan, int create) +{ + struct ast_datastore *datastore = NULL; + struct audiohook_volume *audiohook_volume = NULL; + + /* If we are able to find the datastore return the contents (which is actually an audiohook_volume structure) */ + if ((datastore = ast_channel_datastore_find(chan, &audiohook_volume_datastore, NULL))) { + return datastore->data; + } + + /* If we are not allowed to create a datastore or if we fail to create a datastore, bail out now as we have nothing for them */ + if (!create || !(datastore = ast_channel_datastore_alloc(&audiohook_volume_datastore, NULL))) { + return NULL; + } + + /* Create a new audiohook_volume structure to contain our adjustments and audiohook */ + if (!(audiohook_volume = ast_calloc(1, sizeof(*audiohook_volume)))) { + ast_channel_datastore_free(datastore); + return NULL; + } + + /* Setup our audiohook structure so we can manipulate the audio */ + ast_audiohook_init(&audiohook_volume->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Volume"); + audiohook_volume->audiohook.manipulate_callback = audiohook_volume_callback; + + /* Attach the audiohook_volume blob to the datastore and attach to the channel */ + datastore->data = audiohook_volume; + ast_channel_datastore_add(chan, datastore); + + /* All is well... put the audiohook into motion */ + ast_audiohook_attach(chan, &audiohook_volume->audiohook); + + return audiohook_volume; +} + +/*! \brief Adjust the volume on frames read from or written to a channel + * \param chan Channel to muck with + * \param direction Direction to set on + * \param volume Value to adjust the volume by + * \return Returns 0 on success, -1 on failure + */ +int ast_audiohook_volume_set(struct ast_channel *chan, enum ast_audiohook_direction direction, int volume) +{ + struct audiohook_volume *audiohook_volume = NULL; + + /* Attempt to find the audiohook volume information, but only create it if we are not setting the adjustment value to zero */ + if (!(audiohook_volume = audiohook_volume_get(chan, (volume ? 1 : 0)))) { + return -1; + } + + /* Now based on the direction set the proper value */ + if (direction == AST_AUDIOHOOK_DIRECTION_READ || direction == AST_AUDIOHOOK_DIRECTION_BOTH) { + audiohook_volume->read_adjustment = volume; + } else if (direction == AST_AUDIOHOOK_DIRECTION_WRITE || direction == AST_AUDIOHOOK_DIRECTION_BOTH) { + audiohook_volume->write_adjustment = volume; + } + + return 0; +} + +/*! \brief Retrieve the volume adjustment value on frames read from or written to a channel + * \param chan Channel to retrieve volume adjustment from + * \param direction Direction to retrieve + * \return Returns adjustment value + */ +int ast_audiohook_volume_get(struct ast_channel *chan, enum ast_audiohook_direction direction) +{ + struct audiohook_volume *audiohook_volume = NULL; + int adjustment = 0; + + /* Attempt to find the audiohook volume information, but do not create it as we only want to look at the values */ + if (!(audiohook_volume = audiohook_volume_get(chan, 0))) { + return 0; + } + + /* Grab the adjustment value based on direction given */ + if (direction == AST_AUDIOHOOK_DIRECTION_READ) { + adjustment = audiohook_volume->read_adjustment; + } else if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) { + adjustment = audiohook_volume->write_adjustment; + } + + return adjustment; +} + +/*! \brief Adjust the volume on frames read from or written to a channel + * \param chan Channel to muck with + * \param direction Direction to increase + * \param volume Value to adjust the adjustment by + * \return Returns 0 on success, -1 on failure + */ +int ast_audiohook_volume_adjust(struct ast_channel *chan, enum ast_audiohook_direction direction, int volume) +{ + struct audiohook_volume *audiohook_volume = NULL; + + /* Attempt to find the audiohook volume information, and create an audiohook if none exists */ + if (!(audiohook_volume = audiohook_volume_get(chan, 1))) { + return -1; + } + + /* Based on the direction change the specific adjustment value */ + if (direction == AST_AUDIOHOOK_DIRECTION_READ || direction == AST_AUDIOHOOK_DIRECTION_BOTH) { + audiohook_volume->read_adjustment += volume; + } else if (direction == AST_AUDIOHOOK_DIRECTION_WRITE || direction == AST_AUDIOHOOK_DIRECTION_BOTH) { + audiohook_volume->write_adjustment += volume; + } + + return 0; +} -- cgit v1.2.3