func_volume.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2011, Digium, Inc.
00005  *
00006  * Joshua Colp <jcolp@digium.com> 
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Technology independent volume control
00022  *
00023  * \author Joshua Colp <jcolp@digium.com> 
00024  *
00025  * \ingroup functions
00026  *
00027  */
00028 
00029 /*** MODULEINFO
00030    <support_level>core</support_level>
00031  ***/
00032 
00033 #include "asterisk.h"
00034 
00035 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 411328 $")
00036 
00037 #include "asterisk/module.h"
00038 #include "asterisk/channel.h"
00039 #include "asterisk/pbx.h"
00040 #include "asterisk/utils.h"
00041 #include "asterisk/audiohook.h"
00042 #include "asterisk/app.h"
00043 
00044 /*** DOCUMENTATION
00045    <function name="VOLUME" language="en_US">
00046       <synopsis>
00047          Set the TX or RX volume of a channel.
00048       </synopsis>
00049       <syntax>
00050          <parameter name="direction" required="true">
00051             <para>Must be <literal>TX</literal> or <literal>RX</literal>.</para>
00052          </parameter>
00053          <parameter name="options">
00054             <optionlist>
00055                <option name="p">
00056                   <para>Enable DTMF volume control</para>
00057                </option>
00058             </optionlist>
00059          </parameter>
00060       </syntax>
00061       <description>
00062          <para>The VOLUME function can be used to increase or decrease the <literal>tx</literal> or
00063          <literal>rx</literal> gain of any channel.</para>
00064          <para>For example:</para>
00065          <para>Set(VOLUME(TX)=3)</para>
00066          <para>Set(VOLUME(RX)=2)</para>
00067          <para>Set(VOLUME(TX,p)=3)</para>
00068          <para>Set(VOLUME(RX,p)=3)</para>
00069       </description>
00070    </function>
00071  ***/
00072 
00073 struct volume_information {
00074    struct ast_audiohook audiohook;
00075    int tx_gain;
00076    int rx_gain;
00077    unsigned int flags;
00078 };
00079 
00080 enum volume_flags {
00081    VOLUMEFLAG_CHANGE = (1 << 1),
00082 };
00083 
00084 AST_APP_OPTIONS(volume_opts, {
00085    AST_APP_OPTION('p', VOLUMEFLAG_CHANGE),
00086 });
00087 
00088 static void destroy_callback(void *data)
00089 {
00090    struct volume_information *vi = data;
00091 
00092    /* Destroy the audiohook, and destroy ourselves */
00093    ast_audiohook_lock(&vi->audiohook);
00094    ast_audiohook_detach(&vi->audiohook);
00095    ast_audiohook_unlock(&vi->audiohook);
00096    ast_audiohook_destroy(&vi->audiohook);
00097    ast_free(vi);
00098 
00099    return;
00100 }
00101 
00102 /*! \brief Static structure for datastore information */
00103 static const struct ast_datastore_info volume_datastore = {
00104    .type = "volume",
00105    .destroy = destroy_callback
00106 };
00107 
00108 static int volume_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
00109 {
00110    struct ast_datastore *datastore = NULL;
00111    struct volume_information *vi = NULL;
00112    int *gain = NULL;
00113 
00114    /* If the audiohook is stopping it means the channel is shutting down.... but we let the datastore destroy take care of it */
00115    if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
00116       return 0;
00117 
00118    /* Grab datastore which contains our gain information */
00119    if (!(datastore = ast_channel_datastore_find(chan, &volume_datastore, NULL)))
00120       return 0;
00121 
00122    vi = datastore->data;
00123 
00124    /* If this is DTMF then allow them to increase/decrease the gains */
00125    if (ast_test_flag(vi, VOLUMEFLAG_CHANGE)) {
00126       if (frame->frametype == AST_FRAME_DTMF) {
00127          /* Only use DTMF coming from the source... not going to it */
00128          if (direction != AST_AUDIOHOOK_DIRECTION_READ)
00129             return 0; 
00130          if (frame->subclass.integer == '*') {
00131             vi->tx_gain += 1;
00132             vi->rx_gain += 1;
00133          } else if (frame->subclass.integer == '#') {
00134             vi->tx_gain -= 1;
00135             vi->rx_gain -= 1;
00136          }
00137       }
00138    }
00139 
00140    
00141    if (frame->frametype == AST_FRAME_VOICE) {
00142       /* Based on direction of frame grab the gain, and confirm it is applicable */
00143       if (!(gain = (direction == AST_AUDIOHOOK_DIRECTION_READ) ? &vi->rx_gain : &vi->tx_gain) || !*gain)
00144          return 0;
00145       /* Apply gain to frame... easy as pi */
00146       ast_frame_adjust_volume(frame, *gain);
00147    }
00148 
00149    return 0;
00150 }
00151 
00152 static int volume_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00153 {
00154    struct ast_datastore *datastore = NULL;
00155    struct volume_information *vi = NULL;
00156    int is_new = 0;
00157 
00158    /* Separate options from argument */
00159 
00160    AST_DECLARE_APP_ARGS(args,
00161       AST_APP_ARG(direction);
00162       AST_APP_ARG(options);
00163    );
00164 
00165    if (!chan) {
00166       ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
00167       return -1;
00168    }
00169 
00170    AST_STANDARD_APP_ARGS(args, data);
00171 
00172    ast_channel_lock(chan);
00173    if (!(datastore = ast_channel_datastore_find(chan, &volume_datastore, NULL))) {
00174       ast_channel_unlock(chan);
00175       /* Allocate a new datastore to hold the reference to this volume and audiohook information */
00176       if (!(datastore = ast_datastore_alloc(&volume_datastore, NULL)))
00177          return 0;
00178       if (!(vi = ast_calloc(1, sizeof(*vi)))) {
00179          ast_datastore_free(datastore);
00180          return 0;
00181       }
00182       ast_audiohook_init(&vi->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Volume", AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
00183       vi->audiohook.manipulate_callback = volume_callback;
00184       ast_set_flag(&vi->audiohook, AST_AUDIOHOOK_WANTS_DTMF);
00185       is_new = 1;
00186    } else {
00187       ast_channel_unlock(chan);
00188       vi = datastore->data;
00189    }
00190 
00191    /* Adjust gain on volume information structure */
00192    if (ast_strlen_zero(args.direction)) {
00193       ast_log(LOG_ERROR, "Direction must be specified for VOLUME function\n");
00194       return -1;
00195    }
00196 
00197    if (!strcasecmp(args.direction, "tx")) { 
00198       vi->tx_gain = atoi(value); 
00199    } else if (!strcasecmp(args.direction, "rx")) {
00200       vi->rx_gain = atoi(value);
00201    } else {
00202       ast_log(LOG_ERROR, "Direction must be either RX or TX\n");
00203    }
00204 
00205    if (is_new) {
00206       datastore->data = vi;
00207       ast_channel_lock(chan);
00208       ast_channel_datastore_add(chan, datastore);
00209       ast_channel_unlock(chan);
00210       ast_audiohook_attach(chan, &vi->audiohook);
00211    }
00212 
00213    /* Add Option data to struct */
00214    
00215    if (!ast_strlen_zero(args.options)) {
00216       struct ast_flags flags = { 0 };
00217       ast_app_parse_options(volume_opts, &flags, NULL, args.options);
00218       vi->flags = flags.flags;
00219    } else { 
00220       vi->flags = 0; 
00221    }
00222 
00223    return 0;
00224 }
00225 
00226 static struct ast_custom_function volume_function = {
00227    .name = "VOLUME",
00228    .write = volume_write,
00229 };
00230 
00231 static int unload_module(void)
00232 {
00233    return ast_custom_function_unregister(&volume_function);
00234 }
00235 
00236 static int load_module(void)
00237 {
00238    return ast_custom_function_register(&volume_function);
00239 }
00240 
00241 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Technology independent volume control");

Generated on Thu Apr 16 06:27:36 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6