[svn-commits] branch file/txc r15894 - in /team/file/txc: ./
include/asterisk/ txc/
svn-commits at lists.digium.com
svn-commits at lists.digium.com
Tue Mar 28 17:12:31 MST 2006
Author: file
Date: Tue Mar 28 18:12:27 2006
New Revision: 15894
URL: http://svn.digium.com/view/asterisk?rev=15894&view=rev
Log:
Introducting TXC (Transcoding eXpansion Community): A method of doing clustered/distributed transcoding with automatic resource discovery and configuration. Stay tuned for more information and documentation!
Added:
team/file/txc/txc/
team/file/txc/txc/txc-parser.c (with props)
team/file/txc/txc/txc-parser.h (with props)
team/file/txc/txc/txc-protocol.h (with props)
team/file/txc/txc/txc.c (with props)
team/file/txc/txc/txc.h (with props)
Modified:
team/file/txc/Makefile
team/file/txc/asterisk.c
team/file/txc/include/asterisk/translate.h
team/file/txc/translate.c
Modified: team/file/txc/Makefile
URL: http://svn.digium.com/view/asterisk/team/file/txc/Makefile?rev=15894&r1=15893&r2=15894&view=diff
==============================================================================
--- team/file/txc/Makefile (original)
+++ team/file/txc/Makefile Tue Mar 28 18:12:27 2006
@@ -364,7 +364,7 @@
astmm.o enum.o srv.o dns.o aescrypt.o aestab.o aeskey.o \
utils.o plc.o jitterbuf.o dnsmgr.o devicestate.o \
netsock.o slinfactory.o ast_expr2.o ast_expr2f.o \
- cryptostub.o sha1.o http.o
+ cryptostub.o sha1.o http.o txc/txc.o txc/txc-parser.o
# we need to link in the objects statically, not as a library, because
# otherwise modules will not have them available if none of the static
@@ -551,6 +551,7 @@
clean-depend:
for x in $(SUBDIRS); do $(MAKE) -C $$x clean-depend || exit 1 ; done
rm -f .depend .tags-depend
+ rm -rf txc/*.o
clean: clean-depend
for x in $(SUBDIRS); do $(MAKE) -C $$x clean || exit 1 ; done
Modified: team/file/txc/asterisk.c
URL: http://svn.digium.com/view/asterisk/team/file/txc/asterisk.c?rev=15894&r1=15893&r2=15894&view=diff
==============================================================================
--- team/file/txc/asterisk.c (original)
+++ team/file/txc/asterisk.c Tue Mar 28 18:12:27 2006
@@ -123,6 +123,8 @@
#include "asterisk/linkedlists.h"
#include "asterisk/devicestate.h"
#include "asterisk/compat.h"
+
+#include "txc/txc.h"
#include "asterisk/doxyref.h" /* Doxygen documentation */
@@ -2319,6 +2321,10 @@
printf(term_quit());
exit(1);
}
+ if (txc_init()) {
+ printf(term_quit());
+ exit(1);
+ }
/* load 'preload' modules, required for access to Realtime-mapped configuration files */
if (load_modules(1)) {
printf(term_quit());
Modified: team/file/txc/include/asterisk/translate.h
URL: http://svn.digium.com/view/asterisk/team/file/txc/include/asterisk/translate.h?rev=15894&r1=15893&r2=15894&view=diff
==============================================================================
--- team/file/txc/include/asterisk/translate.h (original)
+++ team/file/txc/include/asterisk/translate.h Tue Mar 28 18:12:27 2006
@@ -96,6 +96,7 @@
* Returns ast_trans_pvt on success, NULL on failure
* */
extern struct ast_trans_pvt *ast_translator_build_path(int dest, int source);
+extern struct ast_trans_pvt *ast_translator_build_path_txc(int dest, int source, int use_txc);
/*!
* \brief Frees a translator path
Modified: team/file/txc/translate.c
URL: http://svn.digium.com/view/asterisk/team/file/txc/translate.c?rev=15894&r1=15893&r2=15894&view=diff
==============================================================================
--- team/file/txc/translate.c (original)
+++ team/file/txc/translate.c Tue Mar 28 18:12:27 2006
@@ -45,6 +45,8 @@
#include "asterisk/cli.h"
#include "asterisk/term.h"
+#include "txc/txc.h"
+
#define MAX_RECALC 200 /* max sample recalc */
/*! \note
@@ -71,6 +73,7 @@
static struct ast_translator_dir tr_matrix[MAX_FORMAT][MAX_FORMAT];
struct ast_trans_pvt {
+ txc_session_t *session;
struct ast_translator *step;
struct ast_translator_pvt *state;
struct ast_trans_pvt *next;
@@ -92,6 +95,15 @@
void ast_translator_free_path(struct ast_trans_pvt *p)
{
struct ast_trans_pvt *pl, *pn;
+
+ /* If a session exists... simply destroy it */
+ if (p->session != NULL) {
+ txc_session_destroy(p->session);
+ free(p);
+ p = NULL;
+ return;
+ }
+
pn = p;
while(pn) {
pl = pn;
@@ -102,10 +114,26 @@
}
}
+struct ast_trans_pvt *ast_translator_build_path(int dest, int source)
+{
+ return ast_translator_build_path_txc(dest, source, 1);
+}
+
/*! Build a set of translators based upon the given source and destination formats */
-struct ast_trans_pvt *ast_translator_build_path(int dest, int source)
-{
+struct ast_trans_pvt *ast_translator_build_path_txc(int dest, int source, int use_txc)
+{
+ txc_session_t *session = NULL;
struct ast_trans_pvt *tmpr = NULL, *tmp = NULL;
+
+ /* If TXC is enabled... */
+ if (use_txc) {
+ session = txc_session_create(source, dest);
+ if (session != NULL) {
+ tmp = ast_calloc(1, sizeof(*tmp));
+ tmp->session = session;
+ return tmp;
+ }
+ }
source = powerof(source);
dest = powerof(dest);
@@ -123,7 +151,7 @@
tmp = tmp->next;
} else
tmp = malloc(sizeof(*tmp));
-
+
if (!tmp) {
ast_log(LOG_WARNING, "Out of memory\n");
if (tmpr)
@@ -135,6 +163,7 @@
if (!tmpr)
tmpr = tmp;
+ tmp->session = NULL;
tmp->next = NULL;
tmp->nextin = tmp->nextout = ast_tv(0, 0);
tmp->step = tr_matrix[source][dest].step;
@@ -157,6 +186,15 @@
struct ast_trans_pvt *p;
struct ast_frame *out;
struct timeval delivery;
+
+ /* See if this is using a TXC session - if so, do it! */
+ if (path->session != NULL) {
+ out = txc_session_translate(path->session, f);
+ if (consume)
+ ast_frfree(f);
+ return out;
+ }
+
p = path;
/* Feed the first frame into the first translator */
p->step->framein(p->state, f);
Added: team/file/txc/txc/txc-parser.c
URL: http://svn.digium.com/view/asterisk/team/file/txc/txc/txc-parser.c?rev=15894&view=auto
==============================================================================
--- team/file/txc/txc/txc-parser.c (added)
+++ team/file/txc/txc/txc-parser.c Tue Mar 28 18:12:27 2006
@@ -1,0 +1,170 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2006, Joshua Colp
+ *
+ * Joshua Colp <jcolp at joshua-colp.com>
+ *
+ * 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 Implementation of Transcoding eXpansion Community, v 1
+ *
+ * \author Joshua Colp <jcolp at joshua-colp.com>
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "asterisk.h"
+
+#include "asterisk/frame.h"
+#include "asterisk/utils.h"
+#include "asterisk/unaligned.h"
+#include "txc-protocol.h"
+#include "txc-parser.h"
+
+int txc_ie_append_raw(struct txc_ie_data *ied, unsigned char ie, const void *data, int datalen)
+{
+ if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
+ return -1;
+ }
+ ied->buf[ied->pos++] = ie;
+ ied->buf[ied->pos++] = datalen;
+ memcpy(ied->buf + ied->pos, data, datalen);
+ ied->pos += datalen;
+ return 0;
+}
+
+int txc_ie_append_addr(struct txc_ie_data *ied, unsigned char ie, const struct sockaddr_in *sin)
+{
+ return txc_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
+}
+
+int txc_ie_append_int(struct txc_ie_data *ied, unsigned char ie, unsigned int value)
+{
+ unsigned int newval;
+ newval = htonl(value);
+ return txc_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
+}
+
+int txc_ie_append_short(struct txc_ie_data *ied, unsigned char ie, unsigned short value)
+{
+ unsigned short newval;
+ newval = htons(value);
+ return txc_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
+}
+
+int txc_ie_append_str(struct txc_ie_data *ied, unsigned char ie, const char *str)
+{
+ if (str == NULL)
+ return 0;
+ return txc_ie_append_raw(ied, ie, str, strlen(str));
+}
+
+int txc_ie_append_byte(struct txc_ie_data *ied, unsigned char ie, unsigned char dat)
+{
+ return txc_ie_append_raw(ied, ie, &dat, 1);
+}
+
+int txc_ie_append(struct txc_ie_data *ied, unsigned char ie)
+{
+ return txc_ie_append_raw(ied, ie, NULL, 0);
+}
+
+int txc_parse_ies(struct txc_ies *ies, unsigned char *data, int datalen)
+{
+ /* Parse data into information elements */
+ int len;
+ int ie;
+ char tmp[256];
+
+ memset(ies, 0, (int)sizeof(struct txc_ies));
+
+ while(datalen >= 2) {
+ ie = data[0];
+ len = data[1];
+ if (len > datalen - 2) {
+ return -1;
+ }
+ switch(ie) {
+ case TXC_IE_SOURCE_UID:
+ ies->source_uid = (char *)data + 2;
+ break;
+ case TXC_IE_TARGET_UID:
+ ies->target_uid = (char *)data + 2;
+ break;
+ case TXC_IE_REASON:
+ ies->reason = (char *)data + 2;
+ break;
+ case TXC_IE_TYPE:
+ if (len != (int)sizeof(unsigned int)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting type to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+ } else
+ ies->type = ntohl(get_unaligned_uint32(data + 2));
+ break;
+ case TXC_IE_SESSION_ID:
+ if (len != (int)sizeof(unsigned int)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting type to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+ } else
+ ies->session_id = ntohl(get_unaligned_uint32(data + 2));
+ break;
+ case TXC_IE_REMOTE_SESSION_ID:
+ if (len != (int)sizeof(unsigned int)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting type to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+ } else
+ ies->remote_session_id = ntohl(get_unaligned_uint32(data + 2));
+ break;
+ case TXC_IE_CAPABILITY:
+ if (len != (int)sizeof(unsigned int)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+ } else
+ ies->capability = ntohl(get_unaligned_uint32(data + 2));
+ break;
+ case TXC_IE_SRC_FORMAT:
+ if (len != (int)sizeof(unsigned int)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+ } else
+ ies->src_format = ntohl(get_unaligned_uint32(data + 2));
+ break;
+ case TXC_IE_DST_FORMAT:
+ if (len != (int)sizeof(unsigned int)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+ } else
+ ies->dst_format = ntohl(get_unaligned_uint32(data + 2));
+ break;
+ case TXC_IE_VERSION:
+ if (len != (int)sizeof(unsigned short)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
+ } else
+ ies->version = ntohs(get_unaligned_uint16(data + 2));
+ break;
+ }
+ /* Overwrite information element with 0, to null terminate previous portion */
+ data[0] = 0;
+ datalen -= (len + 2);
+ data += (len + 2);
+ }
+ /* Null-terminate last field */
+ *data = '\0';
+ if (datalen) {
+ return -1;
+ }
+ return 0;
+}
Propchange: team/file/txc/txc/txc-parser.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/file/txc/txc/txc-parser.c
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/file/txc/txc/txc-parser.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: team/file/txc/txc/txc-parser.h
URL: http://svn.digium.com/view/asterisk/team/file/txc/txc/txc-parser.h?rev=15894&view=auto
==============================================================================
--- team/file/txc/txc/txc-parser.h (added)
+++ team/file/txc/txc/txc-parser.h Tue Mar 28 18:12:27 2006
@@ -1,0 +1,52 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Implementation of Transcoding eXpansion Community
+ *
+ * Copyright (C) 2006, Joshua Colp
+ *
+ * Joshua Colp <jcolp at joshua-colp.com>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License
+ */
+
+/*!\file
+ * \brief Implementation of the Transcoding eXpansion Community Protocol
+ */
+
+#ifndef _TXC_PARSER_H
+#define _TXC_PARSER_H
+
+struct txc_ies {
+ unsigned int type;
+ char *source_uid;
+ char *target_uid;
+ char *reason;
+ unsigned int capability;
+ unsigned int src_format;
+ unsigned int dst_format;
+ unsigned int session_id;
+ unsigned int remote_session_id;
+ int version;
+};
+
+typedef struct txc_ies txc_ies_t;
+
+struct txc_ie_data {
+ unsigned char buf[1024];
+ int pos;
+};
+
+typedef struct txc_ie_data txc_ie_data_t;
+
+int txc_ie_append_raw(struct txc_ie_data *ied, unsigned char ie, const void *data, int datalen);
+int txc_ie_append_addr(struct txc_ie_data *ied, unsigned char ie, const struct sockaddr_in *sin);
+int txc_ie_append_int(struct txc_ie_data *ied, unsigned char ie, unsigned int value);
+int txc_ie_append_short(struct txc_ie_data *ied, unsigned char ie, unsigned short value);
+int txc_ie_append_str(struct txc_ie_data *ied, unsigned char ie, const char *str);
+int txc_ie_append_byte(struct txc_ie_data *ied, unsigned char ie, unsigned char dat);
+int txc_ie_append(struct txc_ie_data *ied, unsigned char ie);
+int txc_parse_ies(struct txc_ies *ies, unsigned char *data, int datalen);
+
+#endif
Propchange: team/file/txc/txc/txc-parser.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/file/txc/txc/txc-parser.h
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/file/txc/txc/txc-parser.h
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: team/file/txc/txc/txc-protocol.h
URL: http://svn.digium.com/view/asterisk/team/file/txc/txc/txc-protocol.h?rev=15894&view=auto
==============================================================================
--- team/file/txc/txc/txc-protocol.h (added)
+++ team/file/txc/txc/txc-protocol.h Tue Mar 28 18:12:27 2006
@@ -1,0 +1,51 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Implementation of Transcoding eXpansion Community
+ *
+ * Copyright (C) 2006, Joshua Colp
+ *
+ * Joshua Colp <jcolp at joshua-colp.com>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License
+ */
+
+#ifndef _TXC_PROTOCOL_H
+#define _TXC_PROTOCOL_H
+
+/* Current support TXC protocol version */
+#define TXC_PROTO_VERSION 1
+
+/* Announcement packet types */
+#define TXC_ANNOUNCE_REQUEST 1 /* Request that all TXC nodes announce themselves */
+#define TXC_ANNOUNCE_REPLY 2 /* Reply with TXC node information */
+#define TXC_ANNOUNCE_SUSPEND 3 /* Announce suspension of a TXC node from service */
+#define TXC_ANNOUNCE_FAILURE 4 /* Announce failure of a TXC node as perceived by another TXC node */
+
+/* Session packet types */
+#define TXC_SESSION_NEW 5 /* Create a new TXC session */
+#define TXC_SESSION_REJECT 6 /* Reject session creation request */
+#define TXC_SESSION_ACK 7 /* Acknowledge session start */
+#define TXC_SESSION_END 8 /* End a TXC session */
+
+/* Node packet types */
+#define TXC_NODE_PING 9 /* Hey - are you alive? */
+#define TXC_NODE_PONG 10 /* Yes... I'm alive */
+
+/* Default port number */
+#define TXC_DEFAULT_PORTNO 2657
+
+/* TXC Information elements */
+#define TXC_IE_TYPE 1 /* What type of packet is this? - unsigned int */
+#define TXC_IE_SOURCE_UID 2 /* Unique source ID - string */
+#define TXC_IE_TARGET_UID 3 /* Target source ID - string */
+#define TXC_IE_CAPABILITY 4 /* TXC node capabilities - unsigned int */
+#define TXC_IE_SRC_FORMAT 5 /* Source transcoding format - unsigned int */
+#define TXC_IE_DST_FORMAT 6 /* Destination transcoding format - unsigned int */
+#define TXC_IE_VERSION 7 /* Protocol version - short */
+#define TXC_IE_SESSION_ID 8 /* Session ID - unsigned int */
+#define TXC_IE_REMOTE_SESSION_ID 9 /* Remote Session ID - unsigned int */
+#define TXC_IE_REASON 10 /* Reason for a reply to happen - string */
+
+#endif
Propchange: team/file/txc/txc/txc-protocol.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/file/txc/txc/txc-protocol.h
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/file/txc/txc/txc-protocol.h
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: team/file/txc/txc/txc.c
URL: http://svn.digium.com/view/asterisk/team/file/txc/txc/txc.c?rev=15894&view=auto
==============================================================================
--- team/file/txc/txc/txc.c (added)
+++ team/file/txc/txc/txc.c Tue Mar 28 18:12:27 2006
@@ -1,0 +1,1138 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2006, Joshua Colp.
+ *
+ * Joshua Colp <jcolp at joshua-colp.com>
+ *
+ * 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 Transcoding eXchange Community
+ *
+ * \author Joshua Colp <jcolp at joshua-colp.com>
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <regex.h>
+#include <signal.h>
+
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(SOLARIS) || defined(__Darwin__)
+#include <sys/types.h>
+#include <netinet/in_systm.h>
+#endif
+#include <netinet/ip.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__Darwin__)
+#include <net/if_dl.h>
+#include <ifaddrs.h>
+#endif
+
+#include "asterisk.h"
+
+#include "asterisk/astobj.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/utils.h"
+#include "asterisk/config.h"
+#include "asterisk/logger.h"
+#include "asterisk/sched.h"
+#include "asterisk/options.h"
+#include "asterisk/cli.h"
+#include "asterisk/frame.h"
+#include "asterisk/translate.h"
+#include "asterisk/netsock.h"
+
+#include "txc.h"
+#include "txc-protocol.h"
+#include "txc-parser.h"
+
+#define TESTING_LOOPBACK /* Loop back data for testing cause you know */
+
+/* Configuration Information */
+static unsigned int capabilities = AST_FORMAT_ULAW;
+static char uid[80] = "";
+static struct ast_codec_pref default_prefs;
+
+/* Community information (socket/thread/etc) */
+static pthread_t community_thread = AST_PTHREADT_NULL;
+static int community_recv_sock = -1;
+static struct sockaddr_in community_recv_saddr;
+static time_t last_community_update;
+/* Socket information for sending */
+AST_MUTEX_DEFINE_STATIC(community_lock);
+static int community_send_sock = -1;
+static struct sockaddr_in community_send_saddr;
+
+/* Node monitoring */
+static pthread_t node_thread = AST_PTHREADT_NULL;
+
+/* Global session information */
+AST_MUTEX_DEFINE_STATIC(session_id_lock);
+#define TXC_MAX_SESSIONS 1000
+static int session_ids[TXC_MAX_SESSIONS];
+static struct ast_netsock_list *netsock = NULL;
+
+/* Community nodes */
+static struct txc_node_list {
+ ASTOBJ_CONTAINER_COMPONENTS(struct txc_node);
+} nodes;
+
+/* Sessions - local or remote */
+static struct txc_session_list {
+ ASTOBJ_CONTAINER_COMPONENTS(struct txc_session);
+} sessions;
+
+/* Session IO Thread */
+static void *io_thread_exec(void *data)
+{
+ txc_session_t *session = data;
+ struct io_context *io = session->io;
+
+ for (;;) {
+ /* See if I/O thread needs to exit */
+ ast_mutex_lock(&session->lock);
+ if (ast_test_flag(session, TXC_SESSION_EXIT)) {
+ ast_mutex_unlock(&session->lock);
+ break;
+ }
+ ast_mutex_unlock(&session->lock);
+ ast_io_wait(io, -1);
+ }
+
+ return NULL;
+}
+
+/* State conversions (int to string) */
+static char *state_to_str(int state)
+{
+ switch (state) {
+ case TXC_NODE_STATE_ALIVE:
+ return "Alive";
+ case TXC_NODE_STATE_SUSPENDED:
+ return "Suspended";
+ case TXC_NODE_STATE_FAILED:
+ return "Failed";
+ default:
+ return "Unknown";
+ }
+}
+
+/* Append standarding TXC information about ourselves */
+static void txc_append_standard_ied(txc_ie_data_t *ied)
+{
+ /* Append our UID */
+ txc_ie_append_str(ied, TXC_IE_SOURCE_UID, uid);
+ /* Append version */
+ txc_ie_append_short(ied, TXC_IE_VERSION, TXC_PROTO_VERSION);
+}
+
+/* Transmit to a node via P2P */
+static int txc_node_transmit(int type, txc_node_t *node, txc_ie_data_t *ied)
+{
+ socklen_t len = sizeof(struct sockaddr_in);
+ int res = 0;
+
+ /* Add type of packet */
+ txc_ie_append_int(ied, TXC_IE_TYPE, type);
+
+ /* Deliver to the node */
+ res = sendto(node->sock, (unsigned char*)ied->buf, ied->pos, 0, (struct sockaddr *)&node->addr, len);
+
+ return 1;
+}
+
+/* Return a free session ID */
+static int new_session_id(void)
+{
+ int id = 0, i = 0;
+
+ /* Find a free session ID */
+ ast_mutex_lock(&session_id_lock);
+ for (i=0; i<TXC_MAX_SESSIONS; i++) {
+ if (session_ids[i] == 0) {
+ session_ids[i] = 1;
+ id = i;
+ break;
+ }
+ }
+ ast_mutex_unlock(&session_id_lock);
+
+ return id;
+}
+
+/* Find a free TXC node to set a session up on */
+static txc_node_t *find_txc_node(int src_format, int dst_format)
+{
+ txc_node_t *node = NULL;
+
+ return node;
+}
+
+/* Find a node given a node UID */
+static txc_node_t *find_node(char *uid)
+{
+ txc_node_t *node = NULL;
+
+ node = ASTOBJ_CONTAINER_FIND(&nodes, uid);
+
+ return node;
+}
+
+/* Find a session given a session ID */
+static txc_session_t *find_session(unsigned int session_id)
+{
+ char tmp[128] = "";
+ txc_session_t *session = NULL;
+
+ snprintf(tmp, sizeof(tmp), "%u", session_id);
+ session = ASTOBJ_CONTAINER_FIND(&sessions, tmp);
+
+ return session;
+}
+
+/* Session Audio Port Callback via netsock */
+static int audio_read(int *id, int fd, short events, void *cbdata)
+{
+ struct ast_netsock *ns = cbdata;
+ txc_session_t *session = ast_netsock_data(ns);
+ int res = 0;
+ unsigned char buf[2048];
+ socklen_t len = sizeof(ast_netsock_boundaddr(ns));
+ struct ast_frame received_frame, *extra_frame = NULL;
+
+ memset(&received_frame, 0, sizeof(received_frame));
+
+ ast_mutex_lock(&session->lock);
+
+ res = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)ast_netsock_boundaddr(ns), &len);
+
+ received_frame.frametype = AST_FRAME_VOICE;
+ received_frame.data = buf;
+ received_frame.datalen = res;
+
+ /* See what type of session this is... */
+ if (session->type == TXC_SESSION_LOCAL) {
+ /* Okay we need to transcode this and send it back out */
+ received_frame.subclass = session->src_format;
+ /* Now that we have created a sorta frame... translate it */
+ extra_frame = ast_translate(session->trans, &received_frame, 0);
+ if (extra_frame != NULL) {
+ sendto(session->sock, extra_frame->data, extra_frame->datalen, 0, (struct sockaddr *)&session->addr, sizeof(session->addr));
+ ast_frfree(extra_frame);
+ } else {
+ ast_log(LOG_ERROR, "Failed to translate inbound audio\n");
+ }
+ extra_frame = NULL;
+ } else if (session->type == TXC_SESSION_REMOTE) {
+ /* This is a transcoded frame coming back */
+ received_frame.subclass = session->dst_format;
+ session->fr = ast_frdup(&received_frame);
+ /* Signal that a frame is available */
+ ast_cond_signal(&session->cond);
+ }
+
+ ast_mutex_unlock(&session->lock);
+
+ return 1;
+}
+
+/* Setup a new TXC session via P2P */
+static txc_session_t *txc_session_new(txc_node_t *node, int src_format, int dst_format)
+{
+ int id = 0;
+ txc_ie_data_t ied;
+ txc_session_t *session = NULL;
+
+ memset(&ied, 0, sizeof(ied));
+
+ /* Make sure source and destination formats are not the same */
+ if (src_format == dst_format) {
+ return NULL;
+ }
+
+ /* Get a new ID now */
+ id = new_session_id();
+
+ /* Setup a new session */
+ session = ast_calloc(1, sizeof(*session));
+ snprintf(session->name, sizeof(session->name), "%u", id);
+ session->local_session_id = id;
+ session->type = TXC_SESSION_REMOTE;
+ session->node = node;
+ session->ns = NULL;
+
+ session->src_format = src_format;
+ session->dst_format = dst_format;
+
+ /* Initialize mutex and condition */
+ ast_mutex_init(&session->lock);
+ ast_cond_init(&session->cond, NULL);
+
+ /* Setup I/O Context */
+ session->io = io_context_create();
+
+ /* Spawn audio netsock stuff */
+ session->ns = ast_netsock_bind(netsock, session->io, "0.0.0.0", id+TXC_DEFAULT_PORTNO+1, 0, audio_read, session);
+ if (session->ns == NULL) {
+ ast_log(LOG_ERROR, "Failed to setup netsock callback stuff\n");
+ }
+
+ /* Spawn I/O Thread */
+ ast_pthread_create(&session->io_thread, NULL, io_thread_exec, session);
+
+ /* Before we add it to the list, lock it */
+ ast_mutex_lock(&session->lock);
+
+ /* Add to the session list */
+ ASTOBJ_CONTAINER_LINK(&sessions, session);
+
+ /* Setup request for new session for transmitting */
+ txc_append_standard_ied(&ied);
+
+ /* Add formats in */
+ txc_ie_append_int(&ied, TXC_IE_SRC_FORMAT, src_format);
+ txc_ie_append_int(&ied, TXC_IE_DST_FORMAT, dst_format);
+
+ /* Add session ID */
+ txc_ie_append_int(&ied, TXC_IE_SESSION_ID, id);
+
+ /* Transmit */
+ txc_node_transmit(TXC_SESSION_NEW, node, &ied);
+ /* Wait for a reply */
+ ast_cond_wait(&session->cond, &session->lock);
+
+ /* Make sure the session is setup okay */
+ if (ast_test_flag(session, TXC_SESSION_FAILED)) {
+ ast_log(LOG_ERROR, "Failed to set session up\n");
+ }
+
+ ast_mutex_unlock(&session->lock);
+
+ return session;
+}
+
+/* Create a session to transcode between two formats */
+txc_session_t *txc_session_create(int src_format, int dst_format)
+{
+ txc_session_t *session = NULL;
+ txc_node_t *node = find_node("proton");
+
+ session = txc_session_new(node, src_format, dst_format);
+
+ return session;
+}
+
+/* Translate using a TXC session */
+struct ast_frame *txc_session_translate(txc_session_t *session, struct ast_frame *frame)
+{
+ int res = 0;
+ struct ast_frame *fr = NULL;
+ struct timeval tv;
+ struct timespec ts;
+
+ /* Acquire session lock */
+ ast_mutex_lock(&session->lock);
+
+ /* This is where it gets fun... we send out the data and wait for a reply - note this is a literal audio stream */
+ res = sendto(session->sock, frame->data, frame->datalen, 0, (struct sockaddr *)&session->addr, sizeof(session->addr));
+
+ /* Calculate a suitable timeout */
+ tv = ast_tvadd(ast_tvnow(), ast_samp2tv(1000, 1000));
+ ts.tv_sec = tv.tv_sec;
+ ts.tv_nsec = tv.tv_usec * 1000;
+
+ /* Wait for a response -- note we have a timeout... */
+ if (ast_cond_timedwait(&session->cond, &session->lock, &ts) < 0) {
+ /* We did not get a reply in the minimum amount of time... */
+ ast_log(LOG_ERROR, "Did not get a reply in time...\n");
+ } else {
+ /* Grab the translated frame */
+ fr = session->fr;
+ session->fr = NULL;
+ }
+
+ ast_mutex_unlock(&session->lock);
+
+ return fr;
+}
+
+/* Destroy a TXC session */
+int txc_session_destroy(txc_session_t *session)
+{
+ txc_ie_data_t ied;
+
+ ast_mutex_lock(&session->lock);
+
+ /* If this is a remote session then we need to send a TXC_SESSION_END to the other node */
+ if (session->type == TXC_SESSION_REMOTE) {
+ memset(&ied, 0, sizeof(ied));
+ txc_append_standard_ied(&ied);
+
+ txc_ie_append_int(&ied, TXC_IE_SESSION_ID, session->remote_session_id);
+
+ txc_node_transmit(TXC_SESSION_END, session->node, &ied);
+ }
+
+ /* If a translator path exists -- free it */
+ if (session->trans != NULL) {
+ ast_translator_free_path(session->trans);
+ session->trans = NULL;
+ }
+
+ /* Kill I/O Thread */
+ if (session->io_thread != AST_PTHREADT_NULL) {
+ ast_set_flag(session, TXC_SESSION_EXIT);
+ /* This will knock the thread out of the poll if it is stuck there */
+ pthread_kill(session->io_thread, SIGURG);
+ ast_mutex_unlock(&session->lock);
+ pthread_join(session->io_thread, NULL);
+ ast_mutex_lock(&session->lock);
+ session->io_thread = AST_PTHREADT_NULL;
+ }
+
+ /* If netsock is setup... get rid of it */
+ if (session->ns != NULL) {
+ /* Work around a strange astobj/netsock bug */
+ ast_netsock_unref(session->ns);
+ ast_netsock_unref(session->ns);
+ session->ns = NULL;
+ }
+
+ /* Get rid of I/O Context */
+ io_context_destroy(session->io);
+ session->io = NULL;
+
+ /* Close sending socket */
+ close(session->sock);
+ session->sock = -1;
+
+ /* Finally remove from the list */
+ ASTOBJ_CONTAINER_UNLINK(&sessions, session);
+
+ /* Mark this session ID as unused now */
+ ast_mutex_lock(&session_id_lock);
+ session_ids[session->local_session_id] = 0;
+ ast_mutex_unlock(&session_id_lock);
+
+ /* Free any used memory */
+ ast_mutex_unlock(&session->lock);
+ free(session);
+ session = NULL;
+
+ return 1;
+}
+
+/* Handle a TXC Session New request */
+static int txc_session_handle_new(txc_node_t *node, txc_ies_t *ies)
+{
+ int id = 0;
+ txc_ie_data_t ied;
+ txc_session_t *session = NULL;
+ struct ast_trans_pvt *translator = NULL;
+
+ memset(&ied, 0, sizeof(ied));
+ txc_append_standard_ied(&ied);
+
+ /* Add the session ID cause we know we will need it */
+ txc_ie_append_int(&ied, TXC_IE_SESSION_ID, ies->session_id);
+
+ /* Make sure we can translate this... if not = send back a TXC_SESSION_REJECT */
+ translator = ast_translator_build_path_txc(ies->dst_format, ies->src_format, 0);
+ if (translator == NULL) {
+ ast_log(LOG_ERROR, "Rejected TXC_SESSION_NEW because translator path could not be built from %d to %d\n", ies->src_format, ies->dst_format);
+ txc_node_transmit(TXC_SESSION_REJECT, node, &ied);
+ return 1;
+ }
+
+ /* Get the ID of this session */
+ id = new_session_id();
+
+ /* Setup a new local session */
+ session = ast_calloc(1, sizeof(*session));
+ snprintf(session->name, sizeof(session->name), "%u", id);
+ session->local_session_id = id;
+ session->remote_session_id = ies->session_id;
+ session->type = TXC_SESSION_LOCAL;
+ session->node = node;
+ session->trans = translator;
+
+ /* Record formats */
+ session->src_format = ies->src_format;
+ session->dst_format = ies->dst_format;
+
+ /* Setup I/O Context */
+ session->io = io_context_create();
+
+ /* Spawn audio netsock stuff */
+ session->ns = ast_netsock_bind(netsock, session->io, "0.0.0.0", id+TXC_DEFAULT_PORTNO+1, 0, audio_read, session);
+ if (session->ns == NULL) {
+ ast_log(LOG_ERROR, "Failed to setup netsock callback stuff\n");
+ }
+
+ /* Spawn I/O Thread */
+ ast_pthread_create(&session->io_thread, NULL, io_thread_exec, session);
+
+ ast_log(LOG_NOTICE, "Remote Audio port on NEW is %d\n", ies->session_id+TXC_DEFAULT_PORTNO+1);
+
+ /* Setup stuff so we can reply back frames to the sender */
+ memcpy(&session->addr, &node->addr, sizeof(session->addr));
+ session->addr.sin_family = AF_INET;
+ session->addr.sin_port = htons(ies->session_id+TXC_DEFAULT_PORTNO+1);
+ session->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+
+ /* Add to the list */
+ ASTOBJ_CONTAINER_LINK(&sessions, session);
+
+ /* Send the acknowledgement back */
+ txc_ie_append_int(&ied, TXC_IE_REMOTE_SESSION_ID, id);
+
+ txc_node_transmit(TXC_SESSION_ACK, node, &ied);
+
+ ast_log(LOG_NOTICE, "Have a TXC Session New request from %s with remote session ID of %u\n", node->name, ies->session_id);
+ return 1;
+}
+
+/* Handle a TXC Session ACK response */
+static int txc_session_handle_ack(txc_node_t *node, txc_ies_t *ies)
+{
+ txc_session_t *session = find_session(ies->session_id);
+
+ ast_mutex_lock(&session->lock);
+
+ /* Update session information */
+ session->remote_session_id = ies->remote_session_id;
+
+ /* Setup sending audio port */
+ memcpy(&session->addr, &node->addr, sizeof(session->addr));
+ session->addr.sin_family = AF_INET;
+ session->addr.sin_port = htons(ies->remote_session_id+TXC_DEFAULT_PORTNO+1);
+ session->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+
+ /* Signal wakeup */
+ ast_cond_signal(&session->cond);
+ ast_mutex_unlock(&session->lock);
+
+ return 1;
+}
+
+/* Handle a TXC Session Reject response */
+static int txc_session_handle_reject(txc_node_t *node, txc_ies_t *ies)
+{
+ txc_session_t *session = find_session(ies->session_id);
+
+ ast_mutex_lock(&session->lock);
+
+ ast_set_flag(session, TXC_SESSION_FAILED);
+
+ ast_cond_signal(&session->cond);
+
+ ast_mutex_unlock(&session->lock);
+
+ return 1;
+}
+
+/* Handle a TXC Session End request */
+static int txc_session_handle_end(txc_node_t *node, txc_ies_t *ies)
+{
+ txc_session_t *session = find_session(ies->session_id);
+
+ /* Destroy anything on the session */
+ txc_session_destroy(session);
+
+ return 1;
+}
+
+/* Ping a node */
+static int txc_node_ping(txc_node_t *node)
+{
+ txc_ie_data_t ied;
+
+ ast_mutex_lock(&node->lock);
+
+ /* Change flag to indicate they were pinged */
+ ast_set_flag(node, TXC_NODE_PINGED);
+
+ memset(&ied, 0, sizeof(ied));
+
+ /* Standard information */
+ txc_append_standard_ied(&ied);
+
+ txc_node_transmit(TXC_NODE_PING, node, &ied);
+
+ ast_mutex_unlock(&node->lock);
+
+ return 1;
+}
+
+/* Reply to the ping from a node */
+static int txc_node_pong(txc_node_t *node)
+{
+ txc_ie_data_t ied;
+
+ ast_mutex_lock(&node->lock);
+
+ memset(&ied, 0, sizeof(ied));
+
+ txc_append_standard_ied(&ied);
+
+ txc_node_transmit(TXC_NODE_PONG, node, &ied);
+
+ ast_mutex_unlock(&node->lock);
+
+ return 1;
+}
+
+/* Transmit to the TXC community */
+static int txc_community_transmit(int type, txc_ie_data_t *ied)
+{
+ socklen_t len = sizeof(struct sockaddr_in);
+ int res = 0;
+
+ /* Add our type in */
+ txc_ie_append_int(ied, TXC_IE_TYPE, type);
+
+ ast_mutex_lock(&community_lock);
+ res = sendto(community_send_sock, (unsigned char*)ied->buf, ied->pos, 0, (struct sockaddr *)&community_send_saddr, len);
+ ast_mutex_unlock(&community_lock);
+
+ return 1;
+}
+
+/* Transmit a TXC Request */
+static int txc_community_request(char *target_uid)
+{
+ txc_ie_data_t ied;
+
+ memset(&ied, 0, sizeof(ied));
+
+ /* Setup standard information */
+ txc_append_standard_ied(&ied);
+
+ /* If a target UID is specified, add it in as well */
+ if (target_uid != NULL) {
+ txc_ie_append_str(&ied, TXC_IE_TARGET_UID, target_uid);
+ }
+
+ /* Now send out the request */
+ txc_community_transmit(TXC_ANNOUNCE_REQUEST, &ied);
+
+ return 1;
+}
+
+/* Transmit a TXC Failure */
+static int txc_community_failure(txc_node_t *node)
+{
+ txc_ie_data_t ied;
+
+ ast_mutex_lock(&node->lock);
+
+ memset(&ied, 0, sizeof(ied));
+
+ txc_append_standard_ied(&ied);
+
+ txc_community_transmit(TXC_ANNOUNCE_FAILURE, &ied);
+
+ ast_mutex_unlock(&node->lock);
+
+ return 1;
+}
+
+/* Transmit a TXC Reply */
+static int txc_community_reply(void)
+{
+ txc_ie_data_t ied;
+
+ memset(&ied, 0, sizeof(ied));
+
+ /* Standard information */
+ txc_append_standard_ied(&ied);
+
+ /* Add our capabilities */
+ txc_ie_append_int(&ied, TXC_IE_CAPABILITY, capabilities);
+
+ /* Finally transmit it */
+ txc_community_transmit(TXC_ANNOUNCE_REPLY, &ied);
+
+ return 1;
+}
+
+/* Process community data */
+static void community_process(unsigned char *data, int size)
+{
+ txc_node_t *node = NULL, *failed_node = NULL;
+ txc_ies_t ies;
+
+ /* Parse information elements */
+ if (txc_parse_ies(&ies, data, size) || ies.source_uid == NULL)
+ return;
+
+ /* If the packet is from ourselves -- ignore it */
+#if 0
+ if (!strcasecmp(ies.source_uid, uid)) {
+ return;
+ }
+#endif
+
+ /* Get the node information (if available) */
+ node = ASTOBJ_CONTAINER_FIND(&nodes, ies.source_uid);
+
+ /* If the node does not exist, and this is not a reply... do a request on them so we get their information */
+ if (node == NULL && (ies.type != TXC_ANNOUNCE_REPLY && ies.type != TXC_ANNOUNCE_REQUEST)) {
+ txc_community_request(ies.source_uid);
+ return;
+ }
+
+ switch (ies.type) {
+ /* Community announce frame types */
+ case TXC_ANNOUNCE_REQUEST:
+ /* If there is no target UID OR the target UID is us, send a reply */
+ if (ies.target_uid == NULL || !strcasecmp(ies.target_uid, uid))
+ txc_community_reply();
+ time(&last_community_update);
+ break;
+ case TXC_ANNOUNCE_REPLY:
+ if (node == NULL) {
+ /* Create a new node */
+ node = ast_calloc(1, sizeof(*node));
+ strncpy(node->name, ies.source_uid, sizeof(node->name));
+ node->sessions = 0;
+ /* Set state */
+ node->state = TXC_NODE_STATE_ALIVE;
+ /* Set capability to the ones they specified */
+ node->capability = ies.capability;
+ /* Figure out where they came from for direct non-multicast communication */
+ memcpy(&node->addr, &community_recv_saddr, sizeof(node->addr));
+ node->addr.sin_port = htons(TXC_DEFAULT_PORTNO);
+ /* Setup a socket to them */
+ node->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ /* They are definitely a community member since we found out about them that way */
+ ast_set_flag(node, TXC_NODE_COMMUNITY_MEMBER);
+ /* Finally add them to the node list */
+ ASTOBJ_CONTAINER_LINK(&nodes, node);
+ /* Chances are they don't know about us... so send out a reply */
+ txc_community_reply();
+ } else {
+ if (node->state == TXC_NODE_STATE_FAILED) {
+ /* Put them back into service */
+ node->state = TXC_NODE_STATE_ALIVE;
+ }
+ if (node->capability != ies.capability) {
+ node->capability = ies.capability;
+ }
+ }
+ break;
+ case TXC_ANNOUNCE_SUSPEND:
+ ast_mutex_lock(&node->lock);
+ node->state = TXC_NODE_STATE_SUSPENDED;
+ ast_mutex_unlock(&node->lock);
+ break;
+ case TXC_ANNOUNCE_FAILURE:
+ if (ies.target_uid != NULL) {
+ failed_node = ASTOBJ_CONTAINER_FIND(&nodes, ies.target_uid);
+ } else {
+ failed_node = node;
+ }
+ break;
+ /* Session frame types */
+ case TXC_SESSION_NEW:
+ txc_session_handle_new(node, &ies);
+ break;
+ case TXC_SESSION_ACK:
+ txc_session_handle_ack(node, &ies);
+ break;
+ case TXC_SESSION_REJECT:
+ txc_session_handle_reject(node, &ies);
+ break;
+ case TXC_SESSION_END:
+ txc_session_handle_end(node, &ies);
+ break;
+ /* Node frame types */
+ case TXC_NODE_PING:
+ /* Send a pong reply back to the sender */
+ txc_node_pong(node);
+ break;
+ case TXC_NODE_PONG:
+ /* Received a pong reply back so clear pinged flag and update last time */
+ ast_clear_flag(node, TXC_NODE_PINGED);
+ break;
+ }
+
+ return;
+}
+
+/* Node monitoring thread */
+static void *node_monitor_exec(void *ignore)
+{
+ time_t now;
+
+ for (;;) {
+ /* Go through the list of nodes */
+ ASTOBJ_CONTAINER_TRAVERSE(&nodes, 1, {
+ ASTOBJ_WRLOCK(iterator);
+ ast_mutex_lock(&iterator->lock);
+ if (iterator->state == TXC_NODE_STATE_ALIVE) {
[... 478 lines stripped ...]
More information about the svn-commits
mailing list