dect
/
asterisk
Archived
13
0
Fork 0

Removing applications that wasn't ready for svn trunk, as trunk now has

pre-release status.


git-svn-id: http://svn.digium.com/svn/asterisk/trunk@101271 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
oej 2008-01-30 17:12:06 +00:00
parent 115173f021
commit 4e78a9454e
2 changed files with 0 additions and 572 deletions

View File

@ -1,552 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2007, Andreas 'MacBrody' Brodmann
*
* Andreas 'MacBrody' Brodmann <andreas.brodmann@gmail.com>
*
* Information on how multicast paging works with linksys
* phones was used from FreeSWITCH's mod_esf with permission
* from Brian West.
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*! \file
*
* \brief Application to stream a channel's input to a specified uni-/multicast address
*
* \author Andreas 'MacBrody' Brodmann <andreas.brodmann@gmail.com>
*
* \ingroup applications
*/
/*** MODULEINFO
<defaultenabled>yes</defaultenabled>
***/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/app.h"
#include "asterisk/config.h"
#include "asterisk/acl.h"
#define RTP_PT_ULAW 0
#define RTP_PT_GSM 3
#define RTP_PT_ALAW 8
#define RTP_PT_G729 18
/*! \brief Multicast Group Receiver Type object */
enum grouptype {
MGT_BASIC = 1, /*!< simple multicast enabled client/receiver like snom, barix */
MGT_LINKSYS = 2, /*!< linksys ipphones; they need a start/stop packet */
MGT_CISCO = 3 /*!< cisco phones; they need a http request to their internal web server // NOT YET IMPLEMENTED */
};
/*! \brief Multicast Group object */
struct mcast_group {
char name[32]; /*!< name of the group */
enum grouptype type; /*!< type, see grouptype */
int socket; /*!< socket used for streaming to this group (each group has got its own socket */
int ttl; /*!< timetolive to be set on this socket */
struct sockaddr_in rtp_address; /*!< address/port pair where the traffic is sent to */
struct sockaddr_in control_address; /*!< address/port for linksys phones to send the start/stop packet to */
AST_LIST_ENTRY(mcast_group) list; /*!< next element int group list */
};
/*! \brief RTP header object */
struct rtp_header {
uint16_t flags;
uint16_t seqno;
uint32_t timestamp;
uint32_t ssrc;
};
/*! \brief Control Packet object as used for linksys phones for start/stop packets */
struct control_packet {
uint32_t unique_id; /*!< unique id per command start or stop - not the same for both commands */
uint32_t command; /*!< the command: 6=start, 7=stop */
uint32_t ip; /*!< multicast address in network byte order */
uint32_t port; /*!< udp port to send the data to */
};
/*! \brief List to hold all the multicast groups defined in the config file */
static AST_LIST_HEAD_STATIC(groups, mcast_group);
static char *app = "RTPPage";
static char *synopsis = "RTPPage Application";
static char *descrip = " RTPPage(direct|multicast, ip:port[&ip:port]|group[&group2[&group3...]][,codec]): Sends the channel's input to the\n"
"specified group(s) defined in the config file rtppage.conf.\n"
"The optional codec may be one of the following:\n"
" ulaw - default\n"
" alaw\n"
" gsm\n"
" g729\n"
"as long as asterisk does not have to translate or respective translators are\n"
"installed with your asterisk installation. If none or any other codec is\n"
"specified the application will fall back to ulaw.\n";
static const char config[] = "rtppage.conf";
static int default_ttl = -1;
static unsigned int tos = -1;
/*! \brief Read input from channel and send it to the specified group(s) as rtp traffic */
static int rtppage_exec(struct ast_channel *chan, void *data)
{
int res = 0;
struct ast_module_user *u = NULL;
struct ast_frame *f = NULL;
char *parse = NULL;
char *rest = NULL, *cur = NULL;
char *rest2 = NULL;
char *ip = NULL, *port = NULL;
int ms = -1;
unsigned char *databuf = NULL;
struct sockaddr_in destaddr;
struct mcast_group *group;
struct control_packet cpk;
struct rtp_header *rtph = NULL;
uint8_t rtp_pt = RTP_PT_ULAW;
int chan_format = AST_FORMAT_ULAW;
uint16_t rtpflags = 0;
int ttl = 0;
int pagetype = 0;
/* you can specify three arguments:
* 1) pagetype (0 = direct, 1 = multicast)
* 2) groups, e.g. NameOfGroup or Name1&Name2 etc) / or ip:port in case of direct
* 3) optional: codec, if specified and valid
* this codec will be used for streaming
*/
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(pagetype);
AST_APP_ARG(groups);
AST_APP_ARG(codec);
);
AST_LIST_HEAD(, mcast_group) activegroups;
AST_LIST_HEAD_INIT(&activegroups);
/* make sure there is at least one parameter */
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "%s requires argument (group(s)[,codec])\n", app);
return -1;
}
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
/* pagetype is a mandatory parameter */
if (!args.pagetype) {
ast_log(LOG_WARNING, "%s requires arguments (pagetype, group(s) | ip:port[,codec])\n", app);
return(-1);
}
if (!strcasecmp(args.pagetype, "direct")) {
pagetype = 0;
} else if (!strcasecmp(args.pagetype, "multicast")) {
pagetype = 1;
} else {
ast_log(LOG_ERROR, "%s is an invalid grouptype! valid types are: direct, multicast.\n", args.pagetype);
return(-1);
}
/* group is a mandatory parameter */
if (!args.groups) {
ast_log(LOG_WARNING, "%s requires arguments (pagetype, group(s) | ip:port[,codec])\n", app);
return(-1);
}
/* setup variables for the desired codec */
if (args.codec) {
if (!strcasecmp(args.codec, "ulaw")) {
/* use default settings */
} else if (!strcasecmp(args.codec, "alaw")) {
rtp_pt = RTP_PT_ALAW;
chan_format = AST_FORMAT_ALAW;
} else if (!strcasecmp(args.codec, "gsm")) {
rtp_pt = RTP_PT_GSM;
chan_format = AST_FORMAT_GSM;
} else if (!strcasecmp(args.codec, "g729")) {
rtp_pt = RTP_PT_G729;
chan_format = AST_FORMAT_G729A;
} else {
/* use ulaw as fallback */
rtp_pt = RTP_PT_ULAW;
chan_format = AST_FORMAT_ULAW;
}
}
u = ast_module_user_add(chan);
/* Check if the channel is answered, if not
* do answer it */
if (chan->_state != AST_STATE_UP) {
res = ast_answer(chan);
if (res) {
ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
goto end;
}
}
/* allocate memory for the rtp send buffer */
if ((databuf = ast_calloc(1, 172)) == NULL) {
ast_log(LOG_WARNING, "Failed to allocate memory for the data buffer, give up\n");
goto end;
}
/* initialize rtp buffer header
* with rtp version and
* payload type
*/
rtph = (struct rtp_header *)databuf;
rtpflags = (0x02 << 14); /* rtp v2 */
rtpflags = (rtpflags & 0xFF80) | rtp_pt;
rtph->flags = htons(rtpflags);
rtph->ssrc = htonl((u_long)time(NULL));
/* first create a temporary table for this page session
* containing all groups which will be used
*/
AST_LIST_LOCK(&groups);
rest = ast_strdup(args.groups);
if (pagetype == 0) {
/* a direct page call. this can actually be used
* for multicast paging too by passing the ip:port as
* argument 2
*/
while ((cur = strsep(&rest, "&"))) {
struct mcast_group *agroup = ast_calloc(1, sizeof(*agroup));
rest2 = ast_strdup(cur);
ip = strsep(&rest2, ":");
port = strsep(&rest2, ":");
if (ip == NULL || port == NULL) {
ast_log(LOG_WARNING, "invalid ip:port pair in call to RTPPage (%s)!\n", cur);
free(agroup);
continue;
}
agroup->rtp_address.sin_family = AF_INET;
agroup->rtp_address.sin_port = htons(atoi(port));
if (inet_pton(AF_INET, ip, &agroup->rtp_address.sin_addr) <= 0) {
ast_log(LOG_WARNING, "invalid ip in call to RTPPage (%s)!\n", cur);
free(agroup);
continue;
}
agroup->type = MGT_BASIC;
agroup->socket = -1;
agroup->ttl = -1;
AST_LIST_INSERT_TAIL(&activegroups, agroup, list);
}
} else if (pagetype == 1) {
/* a multicast page call */
while ((cur = strsep(&rest, "&"))) {
AST_LIST_TRAVERSE(&groups, group, list) {
if (!strcasecmp(group->name, cur)) {
struct mcast_group *agroup = ast_calloc(1, sizeof(*agroup));
memcpy(agroup->name, group->name, 32);
agroup->type = group->type;
agroup->socket = group->socket;
agroup->ttl = group->ttl;
memcpy(&agroup->rtp_address, &group->rtp_address, sizeof(agroup->rtp_address));
memcpy(&agroup->control_address, &group->control_address, sizeof(agroup->control_address));
AST_LIST_INSERT_TAIL(&activegroups, agroup, list);
}
}
}
}
AST_LIST_UNLOCK(&groups);
/* now initialize these groups, e.g. create a udp socket for each,
* set ttl and tos if requested by config, and
* in case of linksys type groups send the multicast start signal
*/
AST_LIST_TRAVERSE(&activegroups, group, list) {
group->socket = socket(AF_INET, SOCK_DGRAM, 0);
/* set ttl if configured
* ttl can be configured either globally in the
* category 'general' or locally within
* the respective groups
*/
if (group->ttl >= 0 || default_ttl >= 0) {
ttl = default_ttl;
if (group->ttl >= 0) {
ttl = group->ttl;
}
if (setsockopt(group->socket, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) {
ast_log(LOG_WARNING, "Failed to set ttl on socket for group %s!\n", group->name);
}
}
/* set tos if requested
* tos can only be configured globally ('general')
*/
if (tos >= 0) {
if (setsockopt(group->socket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) {
ast_log(LOG_WARNING, "Failed to set tos field on socket for group %s!\n", group->name);
}
}
/* for linksys device groups send multicast start command */
if (group->type == MGT_LINKSYS) {
cpk.unique_id = htonl((u_long)time(NULL));
cpk.command = htonl(6); /* multicast start command */
memcpy(&cpk.ip, &group->rtp_address.sin_addr, sizeof(cpk.ip));
cpk.port = htonl(ntohs(group->rtp_address.sin_port));
memcpy(&destaddr, &group->control_address, sizeof(destaddr));
sendto(group->socket, &cpk, sizeof(cpk), 0, (struct sockaddr *)&destaddr, sizeof(destaddr));
sendto(group->socket, &cpk, sizeof(cpk), 0, (struct sockaddr *)&destaddr, sizeof(destaddr));
}
}
/* Set read format as configured - this codec will be used for streaming */
res = ast_set_read_format(chan, chan_format);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set channel read mode, giving up\n");
res = -1;
goto end;
}
/* Play a beep to let the caller know he can start talking */
res = ast_streamfile(chan, "beep", chan->language);
if (!res) {
res = ast_waitstream(chan, "");
} else {
ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", chan->name);
}
ast_stopstream(chan);
/* main loop:
* read frames from the input channel and, if they are voice frames,
* send them to all requested multi-/unicast listeners.
*/
for (;;) {
ms = ast_waitfor(chan, 1000);
if (ms < 0) {
ast_log(LOG_DEBUG, "Hangup detected\n");
goto end;
}
f = ast_read(chan);
if (!f)
break;
/* if the speaker pressed '#', then quit */
if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
res = 0;
ast_frfree(f);
ast_log(LOG_DEBUG, "Received DTMF key: %d\n", f->subclass);
goto end;
}
if (f->frametype == AST_FRAME_VOICE) {
/* update the rtp header */
rtph = (struct rtp_header *)databuf;
rtph->seqno = htons(f->seqno);
rtph->timestamp = htonl(f->ts * 8);
memcpy(databuf+12, f->data, f->datalen);
/* now send that frame to the destination groups */
AST_LIST_TRAVERSE(&activegroups, group, list) {
memcpy(&destaddr, &group->rtp_address, sizeof(destaddr));
if (sendto(group->socket, databuf, f->datalen+12, 0, (struct sockaddr *)&destaddr, sizeof(destaddr)) <= 0) {
ast_log(LOG_DEBUG, "sendto() failed!\n");
}
}
}
ast_frfree(f);
f = NULL;
}
end:
/* send a stop multicast signal to all linksys devices */
AST_LIST_TRAVERSE(&activegroups, group, list) {
if (group->socket > 0) {
if (group->type == MGT_LINKSYS) {
cpk.unique_id = htonl((u_long)time(NULL));
cpk.command = htonl(7); /* multicast stop command */
memcpy(&cpk.ip, &group->rtp_address.sin_addr, sizeof(cpk.ip));
cpk.port = htonl(ntohs(group->rtp_address.sin_port));
memcpy(&destaddr, &group->control_address, sizeof(destaddr));
sendto(group->socket, &cpk, 8, 0, (struct sockaddr *)&destaddr, sizeof(destaddr));
sendto(group->socket, &cpk, 8, 0, (struct sockaddr *)&destaddr, sizeof(destaddr));
}
close(group->socket);
}
}
/* free activegroups list */
while ((group = AST_LIST_REMOVE_HEAD(&activegroups, list))) {
free(group);
}
/* free the rtp data buffer */
if (databuf != NULL) {
free(databuf);
}
ast_module_user_remove(u);
ast_log(LOG_DEBUG, "Exit RTPPage(%s)\n", args.groups);
return res;
}
static int load_config(int reload) {
int res = 0;
const char *cat = NULL;
struct ast_config *cfg = NULL;
struct mcast_group *group = NULL;
const char *var = NULL;
struct ast_flags config_flags = { 0 };
AST_LIST_LOCK(&groups);
if (reload) {
/* if this is a reload, then free the config structure before
* filling it again
*/
while ((group = AST_LIST_REMOVE_HEAD(&groups, list))) {
free(group);
}
/* reset default_ttl & tos */
default_ttl = -1; /* means not set */
tos = -1;
}
/* load config file */
if (!(cfg = ast_config_load(config, config_flags))) {
ast_log(LOG_NOTICE, "Failed to load config!\n");
AST_LIST_UNLOCK(&groups);
return(-1);
}
while ((cat = ast_category_browse(cfg, cat)) != NULL) {
/* 'general' is reserved for generic options */
if (!strcasecmp(cat, "general")) {
var = ast_variable_retrieve(cfg, cat, "ttl");
if (var) {
default_ttl = atoi(var);
}
var = ast_variable_retrieve(cfg, cat, "tos");
if (var) {
ast_str2tos(var, &tos);
}
continue;
}
group = ast_calloc(1, sizeof(*group));
var = ast_variable_retrieve(cfg, cat, "type");
if (!strcasecmp(var, "basic")) {
ast_copy_string(group->name, cat, sizeof(group->name));
group->type = MGT_BASIC;
group->socket = -1;
group->ttl = -1;
if (ast_variable_retrieve(cfg, cat, "ttl") != NULL) {
group->ttl = atoi(ast_variable_retrieve(cfg, cat, "ttl"));
}
memset(&group->rtp_address, 0, sizeof(group->rtp_address));
group->rtp_address.sin_family = AF_INET;
group->rtp_address.sin_port = htons(atoi(ast_variable_retrieve(cfg, cat, "rtp_port")));
if (inet_pton(AF_INET, ast_variable_retrieve(cfg, cat, "rtp_address"), &group->rtp_address.sin_addr) <= 0) {
ast_log(LOG_NOTICE, "Invalid ip address in group %s!\n", cat);
ast_free(group);
group = NULL;
continue;
}
} else if (!strcasecmp(var, "linksys")) {
ast_copy_string(group->name, cat, sizeof(group->name));
group->type = MGT_LINKSYS;
group->socket = -1;
group->ttl = -1;
if (ast_variable_retrieve(cfg, cat, "ttl") != NULL) {
group->ttl = atoi(ast_variable_retrieve(cfg, cat, "ttl"));
}
memset(&group->rtp_address, 0, sizeof(group->rtp_address));
group->rtp_address.sin_family = AF_INET;
group->rtp_address.sin_port = htons(atoi(ast_variable_retrieve(cfg, cat, "rtp_port")));
if (inet_pton(AF_INET, ast_variable_retrieve(cfg, cat, "rtp_address"), &group->rtp_address.sin_addr) <= 0) {
ast_log(LOG_NOTICE, "Invalid ip address in group %s!\n", cat);
ast_free(group);
group = NULL;
continue;
}
memset(&group->control_address, 0, sizeof(group->control_address));
group->control_address.sin_family = AF_INET;
group->control_address.sin_port = htons(atoi(ast_variable_retrieve(cfg, cat, "control_port")));
if (inet_pton(AF_INET, ast_variable_retrieve(cfg, cat, "control_address"), &group->control_address.sin_addr) <= 0) {
ast_log(LOG_NOTICE, "Invalid ip address in group %s!\n", cat);
ast_free(group);
group = NULL;
continue;
}
} else {
group->type = -1;
group->socket = -1;
group->ttl = -1;
ast_log(LOG_NOTICE, "Invalid mcast group %s!\n", cat);
continue;
}
/* now add it to the linked list */
AST_LIST_INSERT_TAIL(&groups, group, list);
ast_log(LOG_NOTICE, "loaded category %s\n", group->name);
group = NULL;
var = NULL;
}
AST_LIST_UNLOCK(&groups);
ast_config_destroy(cfg);
return(res);
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
load_config(0);
return ast_register_application(app, rtppage_exec, synopsis, descrip);
}
static int reload(void)
{
return load_config(1);
}
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RTPPage Application",
.load = load_module,
.unload = unload_module,
.reload = reload,
);

View File

@ -1,20 +0,0 @@
; Configuration for the rtppage() application
; that sends audio in multicast or unicast mode to phones
; for paging
[general]
ttl=10
tos=ef
[testgroup]
type=basic
rtp_address=192.168.83.147
rtp_port=12346
[linksysgroup]
type=linksys
rtp_address=224.168.168.168
rtp_port=34567
control_address=224.168.168.168
control_port=6061