Mon Mar 19 11:30:27 2012

Asterisk developer's documentation


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: 328209 $")
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_destroy(&vi->audiohook);
00094    ast_free(vi);
00095 
00096    return;
00097 }
00098 
00099 /*! \brief Static structure for datastore information */
00100 static const struct ast_datastore_info volume_datastore = {
00101    .type = "volume",
00102    .destroy = destroy_callback
00103 };
00104 
00105 static int volume_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
00106 {
00107    struct ast_datastore *datastore = NULL;
00108    struct volume_information *vi = NULL;
00109    int *gain = NULL;
00110 
00111    /* If the audiohook is stopping it means the channel is shutting down.... but we let the datastore destroy take care of it */
00112    if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
00113       return 0;
00114 
00115    /* Grab datastore which contains our gain information */
00116    if (!(datastore = ast_channel_datastore_find(chan, &volume_datastore, NULL)))
00117       return 0;
00118 
00119    vi = datastore->data;
00120 
00121    /* If this is DTMF then allow them to increase/decrease the gains */
00122    if (ast_test_flag(vi, VOLUMEFLAG_CHANGE)) {
00123       if (frame->frametype == AST_FRAME_DTMF) {
00124          /* Only use DTMF coming from the source... not going to it */
00125          if (direction != AST_AUDIOHOOK_DIRECTION_READ)
00126             return 0; 
00127          if (frame->subclass.integer == '*') {
00128             vi->tx_gain += 1;
00129             vi->rx_gain += 1;
00130          } else if (frame->subclass.integer == '#') {
00131             vi->tx_gain -= 1;
00132             vi->rx_gain -= 1;
00133          }
00134       }
00135    }
00136 
00137    
00138    if (frame->frametype == AST_FRAME_VOICE) {
00139       /* Based on direction of frame grab the gain, and confirm it is applicable */
00140       if (!(gain = (direction == AST_AUDIOHOOK_DIRECTION_READ) ? &vi->rx_gain : &vi->tx_gain) || !*gain)
00141          return 0;
00142       /* Apply gain to frame... easy as pi */
00143       ast_frame_adjust_volume(frame, *gain);
00144    }
00145 
00146    return 0;
00147 }
00148 
00149 static int volume_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00150 {
00151    struct ast_datastore *datastore = NULL;
00152    struct volume_information *vi = NULL;
00153    int is_new = 0;
00154 
00155    /* Separate options from argument */
00156    
00157    AST_DECLARE_APP_ARGS(args,
00158       AST_APP_ARG(direction);
00159       AST_APP_ARG(options);
00160    );
00161    
00162    AST_STANDARD_APP_ARGS(args, data);
00163 
00164    ast_channel_lock(chan);
00165    if (!(datastore = ast_channel_datastore_find(chan, &volume_datastore, NULL))) {
00166       ast_channel_unlock(chan);
00167       /* Allocate a new datastore to hold the reference to this volume and audiohook information */
00168       if (!(datastore = ast_datastore_alloc(&volume_datastore, NULL)))
00169          return 0;
00170       if (!(vi = ast_calloc(1, sizeof(*vi)))) {
00171          ast_datastore_free(datastore);
00172          return 0;
00173       }
00174       ast_audiohook_init(&vi->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Volume");
00175       vi->audiohook.manipulate_callback = volume_callback;
00176       ast_set_flag(&vi->audiohook, AST_AUDIOHOOK_WANTS_DTMF);
00177       is_new = 1;
00178    } else {
00179       ast_channel_unlock(chan);
00180       vi = datastore->data;
00181    }
00182 
00183    /* Adjust gain on volume information structure */
00184    if (ast_strlen_zero(args.direction)) {
00185       ast_log(LOG_ERROR, "Direction must be specified for VOLUME function\n");
00186       return -1;
00187    }
00188 
00189    if (!strcasecmp(args.direction, "tx")) { 
00190       vi->tx_gain = atoi(value); 
00191    } else if (!strcasecmp(args.direction, "rx")) {
00192       vi->rx_gain = atoi(value);
00193    } else {
00194       ast_log(LOG_ERROR, "Direction must be either RX or TX\n");
00195    }
00196 
00197    if (is_new) {
00198       datastore->data = vi;
00199       ast_channel_lock(chan);
00200       ast_channel_datastore_add(chan, datastore);
00201       ast_channel_unlock(chan);
00202       ast_audiohook_attach(chan, &vi->audiohook);
00203    }
00204 
00205    /* Add Option data to struct */
00206    
00207    if (!ast_strlen_zero(args.options)) {
00208       struct ast_flags flags = { 0 };
00209       ast_app_parse_options(volume_opts, &flags, &data, args.options);
00210       vi->flags = flags.flags;
00211    } else { 
00212       vi->flags = 0; 
00213    }
00214 
00215    return 0;
00216 }
00217 
00218 static struct ast_custom_function volume_function = {
00219    .name = "VOLUME",
00220    .write = volume_write,
00221 };
00222 
00223 static int unload_module(void)
00224 {
00225    return ast_custom_function_unregister(&volume_function);
00226 }
00227 
00228 static int load_module(void)
00229 {
00230    return ast_custom_function_register(&volume_function);
00231 }
00232 
00233 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Technology independent volume control");

Generated on Mon Mar 19 11:30:27 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7