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:
parent
115173f021
commit
4e78a9454e
|
@ -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,
|
||||
);
|
||||
|
||||
|
|
@ -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
|
||||
|
Reference in New Issue