00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "asterisk.h"
00026
00027 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 286059 $")
00028
00029 #include <regex.h>
00030
00031 #include "asterisk/module.h"
00032 #include "asterisk/channel.h"
00033 #include "asterisk/pbx.h"
00034 #include "asterisk/utils.h"
00035 #include "asterisk/app.h"
00036 #include "asterisk/indications.h"
00037 #include "asterisk/stringfields.h"
00038
00039 #define locked_copy_string(chan, dest, source, len) \
00040 do { \
00041 ast_channel_lock(chan); \
00042 ast_copy_string(dest, source, len); \
00043 ast_channel_unlock(chan); \
00044 } while (0)
00045 #define locked_string_field_set(chan, field, source) \
00046 do { \
00047 ast_channel_lock(chan); \
00048 ast_string_field_set(chan, field, source); \
00049 ast_channel_unlock(chan); \
00050 } while (0)
00051
00052 char *transfercapability_table[0x20] = {
00053 "SPEECH", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK",
00054 "DIGITAL", "RESTRICTED_DIGITAL", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK",
00055 "3K1AUDIO", "DIGITAL_W_TONES", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK",
00056 "VIDEO", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", };
00057
00058 static int func_channel_read(struct ast_channel *chan, char *function,
00059 char *data, char *buf, size_t len)
00060 {
00061 int ret = 0;
00062
00063 if (!strcasecmp(data, "audionativeformat"))
00064
00065
00066 ast_copy_string(buf, ast_getformatname(chan->nativeformats & AST_FORMAT_AUDIO_MASK), len);
00067 else if (!strcasecmp(data, "videonativeformat"))
00068
00069
00070 ast_copy_string(buf, ast_getformatname(chan->nativeformats & AST_FORMAT_VIDEO_MASK), len);
00071 else if (!strcasecmp(data, "audioreadformat"))
00072 ast_copy_string(buf, ast_getformatname(chan->readformat), len);
00073 else if (!strcasecmp(data, "audiowriteformat"))
00074 ast_copy_string(buf, ast_getformatname(chan->writeformat), len);
00075 else if (!strcasecmp(data, "tonezone") && chan->zone)
00076 locked_copy_string(chan, buf, chan->zone->country, len);
00077 else if (!strcasecmp(data, "language"))
00078 locked_copy_string(chan, buf, chan->language, len);
00079 else if (!strcasecmp(data, "musicclass"))
00080 locked_copy_string(chan, buf, chan->musicclass, len);
00081 else if (!strcasecmp(data, "state"))
00082 locked_copy_string(chan, buf, ast_state2str(chan->_state), len);
00083 else if (!strcasecmp(data, "channeltype"))
00084 locked_copy_string(chan, buf, chan->tech->type, len);
00085 else if (!strcasecmp(data, "transfercapability"))
00086 locked_copy_string(chan, buf, transfercapability_table[chan->transfercapability & 0x1f], len);
00087 else if (!strcasecmp(data, "callgroup")) {
00088 char groupbuf[256];
00089 locked_copy_string(chan, buf, ast_print_group(groupbuf, sizeof(groupbuf), chan->callgroup), len);
00090 } else if (!chan->tech->func_channel_read
00091 || chan->tech->func_channel_read(chan, function, data, buf, len)) {
00092 ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data);
00093 ret = -1;
00094 }
00095
00096 return ret;
00097 }
00098
00099 static int func_channel_write_real(struct ast_channel *chan, char *function,
00100 char *data, const char *value)
00101 {
00102 int ret = 0;
00103 signed char gainset;
00104
00105 if (!strcasecmp(data, "language"))
00106 locked_string_field_set(chan, language, value);
00107 else if (!strcasecmp(data, "musicclass"))
00108 locked_string_field_set(chan, musicclass, value);
00109 else if (!strcasecmp(data, "tonezone")) {
00110 struct tone_zone *new_zone;
00111 if (!(new_zone = ast_get_indication_zone(value))) {
00112 ast_log(LOG_ERROR, "Unknown country code '%s' for tonezone. Check indications.conf for available country codes.\n", value);
00113 ret = -1;
00114 } else
00115 chan->zone = new_zone;
00116 } else if (!strcasecmp(data, "callgroup"))
00117 chan->callgroup = ast_get_group(value);
00118 else if (!strcasecmp(data, "txgain")) {
00119 sscanf(value, "%4hhd", &gainset);
00120 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &gainset, sizeof(gainset), 0);
00121 } else if (!strcasecmp(data, "rxgain")) {
00122 sscanf(value, "%4hhd", &gainset);
00123 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &gainset, sizeof(gainset), 0);
00124 } else if (!strcasecmp(data, "transfercapability")) {
00125 unsigned short i;
00126 for (i = 0; i < 0x20; i++) {
00127 if (!strcasecmp(transfercapability_table[i], value) && strcmp(value, "UNK")) {
00128 chan->transfercapability = i;
00129 break;
00130 }
00131 }
00132 } else if (!chan->tech->func_channel_write
00133 || chan->tech->func_channel_write(chan, function, data, value)) {
00134 ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n",
00135 data);
00136 ret = -1;
00137 }
00138
00139 return ret;
00140 }
00141
00142 static int func_channel_write(struct ast_channel *chan, char *function, char *data, const char *value)
00143 {
00144 int res;
00145 ast_chan_write_info_t write_info = {
00146 .version = AST_CHAN_WRITE_INFO_T_VERSION,
00147 .write_fn = func_channel_write_real,
00148 .chan = chan,
00149 .function = function,
00150 .data = data,
00151 .value = value,
00152 };
00153
00154 res = func_channel_write_real(chan, function, data, value);
00155 ast_channel_setoption(chan, AST_OPTION_CHANNEL_WRITE, &write_info, sizeof(write_info), 0);
00156
00157 return res;
00158 }
00159
00160 static struct ast_custom_function channel_function = {
00161 .name = "CHANNEL",
00162 .synopsis = "Gets/sets various pieces of information about the channel.",
00163 .syntax = "CHANNEL(item)",
00164 .desc = "Gets/set various pieces of information about the channel.\n"
00165 "Standard items (provided by all channel technologies) are:\n"
00166 "R/O audioreadformat format currently being read\n"
00167 "R/O audionativeformat format used natively for audio\n"
00168 "R/O audiowriteformat format currently being written\n"
00169 "R/W callgroup call groups for call pickup\n"
00170 "R/O channeltype technology used for channel\n"
00171 "R/W language language for sounds played\n"
00172 "R/W musicclass class (from musiconhold.conf) for hold music\n"
00173 "R/W rxgain set rxgain level on channel drivers that support it\n"
00174 "R/O state state for channel\n"
00175 "R/W tonezone zone for indications played\n"
00176 "R/W transfercapability ISDN transfer capability (one of SPEECH, DIGITAL,\n"
00177 " RESTRICTED_DIGITAL, 3K1AUDIO, DIGITAL_W_TONES, or VIDEO).\n"
00178 "R/W txgain set txgain level on channel drivers that support it\n"
00179 "R/O videonativeformat format used natively for video\n"
00180 "\n"
00181 "chan_sip provides the following additional options:\n"
00182 "R/O rtpqos Get QOS information about the RTP stream\n"
00183 " This option takes two additional arguments:\n"
00184 " Argument 1:\n"
00185 " audio Get data about the audio stream\n"
00186 " video Get data about the video stream\n"
00187 " Argument 2:\n"
00188 " local_ssrc Local SSRC (stream ID)\n"
00189 " local_lostpackets Local lost packets\n"
00190 " local_jitter Local calculated jitter\n"
00191 " local_count Number of received packets\n"
00192 " remote_ssrc Remote SSRC (stream ID)\n"
00193 " remote_lostpackets Remote lost packets\n"
00194 " remote_jitter Remote reported jitter\n"
00195 " remote_count Number of transmitted packets\n"
00196 " rtt Round trip time\n"
00197 " all All statistics (in a form suited to logging, but not for parsing)\n"
00198 "\n"
00199 "Additional items may be available from the channel driver providing\n"
00200 "the channel; see its documentation for details.\n"
00201 "\n"
00202 "Any item requested that is not available on the current channel will\n"
00203 "return an empty string.\n",
00204 .read = func_channel_read,
00205 .write = func_channel_write,
00206 };
00207
00208 static int unload_module(void)
00209 {
00210 return ast_custom_function_unregister(&channel_function);
00211 }
00212
00213 static int load_module(void)
00214 {
00215 return ast_custom_function_register(&channel_function);
00216 }
00217
00218 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Channel information dialplan function");