[asterisk-commits] may: branch may/chan_mcu r396414 - /team/may/chan_mcu/branches/10/addons/
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu Aug 8 14:02:30 CDT 2013
Author: may
Date: Thu Aug 8 14:02:28 2013
New Revision: 396414
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=396414
Log:
initial public chan_mcu/res_xml_rpc code
Added:
team/may/chan_mcu/branches/10/addons/chan_mcu.c (with props)
team/may/chan_mcu/branches/10/addons/mcu_common.h (with props)
team/may/chan_mcu/branches/10/addons/res_xmlrpc_mcu.c (with props)
team/may/chan_mcu/branches/10/addons/res_xmlrpc_mcu.exports.in (with props)
Modified:
team/may/chan_mcu/branches/10/addons/Makefile
Modified: team/may/chan_mcu/branches/10/addons/Makefile
URL: http://svnview.digium.com/svn/asterisk/team/may/chan_mcu/branches/10/addons/Makefile?view=diff&rev=396414&r1=396413&r2=396414
==============================================================================
--- team/may/chan_mcu/branches/10/addons/Makefile (original)
+++ team/may/chan_mcu/branches/10/addons/Makefile Thu Aug 8 14:02:28 2013
@@ -31,6 +31,8 @@
cdr_mysql \
chan_mobile \
chan_ooh323 \
+ chan_mcu \
+ res_xmlrpc_mcu \
format_mp3 \
res_config_mysql
@@ -65,6 +67,10 @@
$(if $(filter format_mp3,$(EMBEDDED_MODS)),modules.link,format_mp3.so): mp3/common.o mp3/dct64_i386.o mp3/decode_ntom.o mp3/layer3.o mp3/tabinit.o mp3/interface.o
chan_ooh323.o: _ASTCFLAGS+=$(H323CFLAGS)
+chan_mcu.o: _ASTCFLAGS+=-I/usr/local/xmlrpc/include
+res_xmlrpc_mcu.o: _ASTCFLAGS+=-I/usr/local/xmlrpc/include
+chan_mcu.so: LIBS+=-L/usr/local/xmlrpc/lib -lxmlrpc -lxmlrpc_client -lxmlrpc_xmlparse -lxmlrpc_xmltok -lxmlrpc_abyss -lxmlrpc_server -lxmlrpc_util
+res_xmlrpc_mcu.so: LIBS+=-L/usr/local/xmlrpc/lib -lxmlrpc -lxmlrpc_client -lxmlrpc_xmlparse -lxmlrpc_xmltok -lxmlrpc_abyss -lxmlrpc_server -lxmlrpc_util
$(if $(filter chan_ooh323,$(EMBEDDED_MODS)),modules.link,chan_ooh323.so): _ASTCFLAGS+=$(H323CFLAGS)
$(if $(filter chan_ooh323,$(EMBEDDED_MODS)),modules.link,chan_ooh323.so): $(addprefix ooh323c/src/,$(H323OBJS)) chan_ooh323.o ooh323cDriver.o
Added: team/may/chan_mcu/branches/10/addons/chan_mcu.c
URL: http://svnview.digium.com/svn/asterisk/team/may/chan_mcu/branches/10/addons/chan_mcu.c?view=auto&rev=396414
==============================================================================
--- team/may/chan_mcu/branches/10/addons/chan_mcu.c (added)
+++ team/may/chan_mcu/branches/10/addons/chan_mcu.c Thu Aug 8 14:02:28 2013
@@ -1,0 +1,2123 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ */
+
+/*! \file
+ *
+ * \brief Medooze MediaMixer channel driver
+ *
+ * \ingroup channel_drivers
+ */
+
+/*** MODULEINFO
+ <defaultenabled>no</defaultenabled>
+ <depend>res_xmlrpc_mcu</depend>
+ <support_level>extended</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <fcntl.h>
+#include <sys/signal.h>
+
+#include <xmlrpc-c/base.h>
+#include <xmlrpc-c/client.h>
+
+#include "asterisk/lock.h"
+#include "asterisk/channel.h"
+#include "asterisk/config.h"
+#include "asterisk/module.h"
+#include "asterisk/pbx.h"
+#include "asterisk/sched.h"
+#include "asterisk/io.h"
+#include "asterisk/acl.h"
+#include "asterisk/callerid.h"
+#include "asterisk/file.h"
+#include "asterisk/cli.h"
+#include "asterisk/app.h"
+#include "asterisk/rtp_engine.h"
+#include "asterisk/causes.h"
+
+#include "mcu_common.h"
+
+#define FORMAT_STRING_SIZE 512
+
+#define H264_PAYLOAD_NAME "102"
+#define VP8_PAYLOAD_NAME "103"
+#define ALAW_PAYLOAD_NAME "8"
+#define SPEEX16_PAYLOAD_NAME "111"
+
+// from MCU media mixer
+enum AudioType {PCMA=8,PCMU=0,GSM=3,SPEEX16=117,AMR=118,TELEPHONE_EVENT=100,NELLY8=130,NELLY11=131};
+enum VideoType {H263_1996=34,H263_1998=103,MPEG4=104,H264=99,SORENSON=100,VP8=107};
+
+static const char tdesc[] = "MCU Channel Driver";
+static const char type[] = "MCU";
+static const char xmlrpc_cname[] = "Asterisk XMLRPC client";
+static const char xmlrpc_cversion[] = "0.1";
+static char defaultCLID[] = "asterisk";
+static const char config[] = "chan_mcu.conf";
+
+static struct ast_sockaddr bindaddr;
+
+struct ast_module *myself;
+
+/** Asterisk RTP stuff*/
+static struct ast_sched_context *sched;
+static struct io_context *io;
+
+
+static xmlrpc_env xmlrpcenv;
+
+struct mcu_pvt {
+ ast_mutex_t lock; /* Channel private lock */
+ struct ast_channel *owner; /* owner channel */
+ struct ast_rtp_instance *rtp;
+ struct ast_rtp_instance *vrtp; /* Placeholder for now */
+ time_t lastrtptx;
+ time_t lastrtprx;
+ xmlrpc_client *xr_client;
+ ast_mutex_t xrlock;
+ ast_cond_t xrcond;
+ int xreqs;
+ int stop_rpc;
+ struct ast_format_cap *cap;
+ char *clid;
+ // char mcuId[MAXHOSTNAMELEN];
+ int confId;
+ int partId;
+ int audio_port, video_port;
+ char *a_redirip, *a_redirport;
+ char *v_redirip, *v_redirport;
+ struct mcu_call* mcu_call;
+ enum AudioType audio_codec;
+ enum VideoType video_codec;
+ int init_done;
+ pthread_t finishThread;
+//
+ xmlrpc_server_info *qxr_server;
+ char *qxr_method;
+ xmlrpc_value *qxr_parm;
+ xmlrpc_response_handler *qxr_cbfunc;
+ xmlrpc_env env;
+//
+ struct mcu_pvt* next;
+};
+
+/* Forward declarations */
+static struct ast_channel *mcu_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, void *data, int *cause);
+static int mcu_call(struct ast_channel *ast, char *dest, int timeout);
+static int mcu_hangup(struct ast_channel *ast);
+static struct ast_frame *mcu_read(struct ast_channel *ast);
+static int mcu_write(struct ast_channel *ast, struct ast_frame *f);
+static int mcu_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
+static int mcu_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
+static struct ast_frame *mcu_rtp_read(struct ast_channel *ast, struct mcu_pvt *p);
+
+static void mcu_destroy(struct mcu_pvt *pvt);
+
+static int reload_config(int reload);
+
+
+/* direct xmlrpc calls */
+void SendStartAudio(struct mcu_pvt *p);
+void SendStartVideo(struct mcu_pvt *p);
+void SendReStartSending(struct mcu_pvt *p);
+
+/* callbacks from xmlrpc lib */
+void onCreateParticipant(const char* url, const char* method, xmlrpc_value *params, void *user_data,
+ xmlrpc_env *faultP, xmlrpc_value *resultP);
+void onStartAudioReceiving(const char* url, const char* method, xmlrpc_value *params, void *user_data,
+ xmlrpc_env *faultP, xmlrpc_value *resultP);
+void onStartVideoReceiving(const char* url, const char* method, xmlrpc_value *params, void *user_data,
+ xmlrpc_env *faultP, xmlrpc_value *resultP);
+void onAddMosaicParticipant(const char* url, const char* method, xmlrpc_value *params, void *user_data,
+ xmlrpc_env *faultP, xmlrpc_value *resultP);
+void onAddSidebarParticipant(const char* url, const char* method, xmlrpc_value *params, void *user_data,
+ xmlrpc_env *faultP, xmlrpc_value *resultP);
+void onSetAudioCodec(const char* url, const char* method, xmlrpc_value *params, void *user_data,
+ xmlrpc_env *faultP, xmlrpc_value *resultP);
+void onSetVideoCodec(const char* url, const char* method, xmlrpc_value *params, void *user_data,
+ xmlrpc_env *faultP, xmlrpc_value *resultP);
+void onStartAudioSending(const char* url, const char* method, xmlrpc_value *params, void *user_data,
+ xmlrpc_env *faultP, xmlrpc_value *resultP);
+void onStartVideoSending(const char* url, const char* method, xmlrpc_value *params, void *user_data,
+ xmlrpc_env *faultP, xmlrpc_value *resultP);
+void onReStartAudioSending(const char* url, const char* method, xmlrpc_value *params, void *user_data,
+ xmlrpc_env *faultP, xmlrpc_value *resultP);
+void onDeleteParticipant(const char* url, const char* method, xmlrpc_value *params, void *user_data,
+ xmlrpc_env *faultP, xmlrpc_value *resultP);
+
+/* Channel driver declaration */
+static struct ast_channel_tech mcu_tech = {
+ .type = "MCU",
+ .description = tdesc,
+ .requester = mcu_request,
+ .call = mcu_call,
+ .hangup = mcu_hangup,
+ .read = mcu_read,
+ .write = mcu_write,
+ .write_video = mcu_write,
+ .write_text = mcu_write,
+ .indicate = mcu_indicate,
+ .fixup = mcu_fixup,
+ .bridge = ast_rtp_instance_bridge,
+ .early_bridge = ast_rtp_instance_early_bridge,
+};
+
+static enum ast_rtp_glue_result mcu_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **rtp);
+static enum ast_rtp_glue_result mcu_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp_instance **rtp);
+static void mcu_get_codec(struct ast_channel *chan, struct ast_format_cap *result);
+static int mcu_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *instance, struct ast_rtp_instance *vinstance, struct ast_rtp_instance *tinstance, const struct ast_format_cap *cap, int nat_active);
+
+static struct ast_rtp_glue mcu_rtp = {
+ .type = type,
+ .get_rtp_info = mcu_get_rtp_peer,
+ .get_vrtp_info = mcu_get_vrtp_peer,
+ .update_peer = mcu_set_rtp_peer,
+ .get_codec = mcu_get_codec,
+};
+
+
+AST_MUTEX_DEFINE_STATIC(mcu_cn_lock);
+static long int mcu_callnum = 0;
+
+static int mcuDebug = 1; /* Debug flag */
+
+static void loop_cleanup(void* dummy)
+{
+ struct mcu_pvt *pvt = (struct mcu_pvt *) dummy;
+ ast_verbose("-- loop thread cleaned\n");
+ ast_mutex_destroy(&pvt->xrlock);
+ ast_cond_destroy(&pvt->xrcond);
+ xmlrpc_client_destroy(pvt->xr_client);
+ xmlrpc_server_info_free(pvt->qxr_server);
+
+ ast_mutex_destroy(&pvt->lock);
+
+ pvt->cap = ast_format_cap_destroy(pvt->cap);
+ if (pvt->rtp) {
+ ast_rtp_instance_destroy(pvt->rtp);
+ }
+ if (pvt->vrtp) {
+ ast_rtp_instance_destroy(pvt->vrtp);
+ }
+
+ if (pvt->mcu_call) {
+ free(pvt->mcu_call);
+ }
+
+ free(pvt);
+}
+
+static void* xmlrpc_loop(void* dummy) {
+ struct mcu_pvt *pvt = (struct mcu_pvt *) dummy;
+ ast_verbose("-- loop started\n");
+
+ ast_mutex_lock(&pvt->xrlock);
+
+ while (!pvt->stop_rpc) {
+ struct timeval wait;
+ struct timespec ts;
+
+ wait = ast_tvadd(ast_tvnow(), ast_samp2tv(300, 1000));
+ ts.tv_sec = wait.tv_sec;
+ ts.tv_nsec = wait.tv_usec * 1000;
+ ast_cond_timedwait(&pvt->xrcond, &pvt->xrlock, &ts);
+
+ while (pvt->xreqs) {
+ pvt->xreqs = 0;
+ ast_verbose("--- loop thread sending %s\n", pvt->qxr_method);
+ xmlrpc_client_start_rpc(&pvt->env, pvt->xr_client, pvt->qxr_server, pvt->qxr_method, pvt->qxr_parm,
+ pvt->qxr_cbfunc, (void *)pvt);
+ if (pvt->env.fault_code) {
+ ast_log(LOG_ERROR, "xmlrpc parse fault %d:%s\n", pvt->env.fault_code, pvt->env.fault_string);
+ continue;
+ }
+ xmlrpc_client_event_loop_finish(pvt->xr_client);
+ // xmlrpc_DECREF(pvt->qxr_parm);
+
+ }
+
+ }
+
+ ast_mutex_unlock(&pvt->xrlock);
+ ast_verbose("-- loop exited\n");
+ return NULL; // never here
+}
+
+static void* loop_thread(void *dummy)
+{
+ void *ret = NULL;
+ pthread_cleanup_push(loop_cleanup, dummy);
+ ret = xmlrpc_loop(dummy);
+ pthread_cleanup_pop(1);
+ return ret;
+}
+
+
+static int mcu_write(struct ast_channel *ast, struct ast_frame *f)
+{
+ struct mcu_pvt *p = ast->tech_pvt;
+ struct ast_format tmpfmt;
+ int res = 0;
+ if (p) {
+ ast_mutex_lock(&p->lock);
+ if (!p->init_done) {
+ ast_mutex_unlock(&p->lock);
+ return res;
+ }
+ p->lastrtptx = time(NULL);
+ switch (f->frametype) {
+ case AST_FRAME_VOICE:
+ if (p->rtp) {
+ if (!p->audio_codec) {
+ if ((ast_format_cap_iscompatible(p->owner->nativeformats, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0)))) {
+ p->audio_codec = PCMA; // alaw preffered
+ } else {
+ p->audio_codec = SPEEX16;
+ }
+ SendStartAudio(p);
+ }
+ if (!p->video_codec && p->audio_port) {
+#ifdef AST_FORMAT_VP8
+ if ((ast_format_cap_iscompatible(p->owner->nativeformats, ast_format_set(&tmpfmt, AST_FORMAT_VP8, 0)))) {
+ p->video_codec = VP8;
+ } else {
+ p->video_codec = H264;
+ }
+#else
+ p->video_codec = H264;
+#endif
+ SendStartVideo(p);
+ }
+ res = ast_rtp_instance_write(p->rtp, f);
+ }
+ break;
+ case AST_FRAME_VIDEO:
+ if (p->vrtp) {
+ res = ast_rtp_instance_write(p->vrtp, f);
+ }
+ break;
+ default:
+ ast_log(LOG_WARNING, "Can't send to %s frame type of %d\n", ast->name,
+ f->frametype);
+ }
+ ast_mutex_unlock(&p->lock);
+ }
+
+ return res;
+}
+
+
+
+static struct ast_frame *mcu_read(struct ast_channel *ast)
+{
+ struct ast_frame *fr;
+ static struct ast_frame null_frame = { AST_FRAME_NULL, };
+ struct mcu_pvt *p = ast->tech_pvt;
+
+ if (!p) {
+ return &null_frame;
+ }
+ ast_mutex_lock(&p->lock);
+ if (p->rtp) {
+ fr = mcu_rtp_read(ast, p);
+ } else {
+ fr = &null_frame;
+ }
+ ast_mutex_unlock(&p->lock);
+ return fr;
+}
+
+/*! \brief Function called when we should read a frame from the channel */
+static struct ast_frame *mcu_rtp_read(struct ast_channel *ast, struct mcu_pvt *p)
+{
+ static struct ast_frame null_frame = { AST_FRAME_NULL, };
+ struct ast_frame *f = &null_frame;
+ switch (ast->fdno) {
+ case 0: // Audio
+ f = ast_rtp_instance_read(p->rtp, 0);
+ p->lastrtprx = time(NULL);
+ break;
+ case 1: // RTCP
+ f = ast_rtp_instance_read(p->rtp, 1);
+ break;
+ case 2: // Video
+ f = ast_rtp_instance_read(p->vrtp, 0);
+ p->lastrtprx = time(NULL);
+ break;
+ case 3: // RTCP Video
+ f = ast_rtp_instance_read(p->vrtp, 0);
+ break;
+ default:
+ f = &null_frame;
+ }
+
+ if (f && p->owner && (f->frametype == AST_FRAME_VOICE)) {
+ /* We already hold the channel lock */
+ if (!(ast_format_cap_iscompatible(p->owner->nativeformats, &f->subclass.format))) {
+ ast_debug(1, "Oooh, voice format changed to %s\n", ast_getformatname(&f->subclass.format));
+ ast_format_cap_set(p->owner->nativeformats, &f->subclass.format);
+ ast_set_read_format(p->owner, &p->owner->readformat);
+ ast_set_write_format(p->owner, &p->owner->writeformat);
+ }
+ }
+ return f;
+}
+
+static int configure_rtp(struct mcu_pvt *pvt) {
+
+
+ //struct ast_sockaddr tmp;
+ //ast_parse_arg("::", PARSE_ADDR, &tmp);
+
+ if (!(pvt->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr, NULL))) {
+ ast_log(LOG_ERROR, "Unable to create RTP session: %s\n", strerror(errno));
+ return 0;
+ }
+ if (!(pvt->vrtp = ast_rtp_instance_new("asterisk", sched, &bindaddr, NULL))) {
+ ast_log(LOG_ERROR, "Unable to create video RTP session: %s\n", strerror(errno));
+ return 0;
+ }
+
+ if (pvt->owner) {
+ while (pvt->owner && ast_channel_trylock(pvt->owner)) {
+ ast_debug(1,"Failed to grab lock, trying again\n");
+ DEADLOCK_AVOIDANCE(&pvt->lock);
+ }
+ if (!pvt->owner) {
+ ast_log(LOG_ERROR, "Channel has no owner\n");
+ return 0;
+ }
+ } else {
+ ast_log(LOG_ERROR, "Channel has no owner\n");
+ return 0;
+ }
+
+ ast_channel_set_fd(pvt->owner, 0, ast_rtp_instance_fd(pvt->rtp, 0));
+ ast_channel_set_fd(pvt->owner, 1, ast_rtp_instance_fd(pvt->rtp, 1));
+ ast_channel_set_fd(pvt->owner, 2, ast_rtp_instance_fd(pvt->vrtp, 0));
+ ast_channel_set_fd(pvt->owner, 3, ast_rtp_instance_fd(pvt->vrtp, 1));
+
+ ast_channel_unlock(pvt->owner);
+
+ return 1;
+}
+
+static struct mcu_pvt *mcu_alloc(char *url)
+{
+ struct mcu_pvt *pvt = NULL;
+ // struct xmlrpc_clientparms clientParms;
+
+ if (mcuDebug) {
+ ast_verbose("--- mcu alloc for %s" , url);
+ }
+
+ if (!(pvt = ast_calloc(1, sizeof(*pvt)))) {
+ ast_log(LOG_ERROR, "Couldn't allocate private mcu structure\n");
+ return NULL;
+ }
+
+ if (!(pvt->cap = ast_format_cap_alloc_nolock())) {
+ ast_free(pvt);
+ ast_log(LOG_ERROR, "Couldn't allocate private mcu structure\n");
+ return NULL;
+ }
+
+ /* initialize xmlrpc structure here */
+
+ // clientParms.transport = "curl";
+ xmlrpc_client_create(&xmlrpcenv, XMLRPC_CLIENT_NO_FLAGS, xmlrpc_cname, xmlrpc_cversion,
+ NULL, 0, &pvt->xr_client);
+ // &clientParms, XMLRPC_CPSIZE(transport), &pvt->xr_client);
+
+ if (!pvt->xr_client) {
+ ast_log(LOG_ERROR, "Couldn't allocate xmlrpc client data, fault is %d:%s\n", xmlrpcenv.fault_code, xmlrpcenv.fault_string);
+ return NULL;
+ }
+
+
+ ast_mutex_init(&pvt->lock);
+ ast_mutex_lock(&pvt->lock);
+
+ ast_mutex_init(&pvt->xrlock);
+ ast_cond_init(&pvt->xrcond, NULL);
+
+ ast_mutex_unlock(&pvt->lock);
+ return pvt;
+}
+
+static void mcu_destroy(struct mcu_pvt *pvt)
+{
+ ast_mutex_lock(&pvt->lock);
+
+ if (pvt->clid) {
+ free(pvt->clid);
+ }
+
+ if (pvt->a_redirip) {
+ free(pvt->a_redirip);
+ }
+ if (pvt->a_redirport) {
+ free(pvt->a_redirport);
+ }
+ if (pvt->v_redirip) {
+ free(pvt->v_redirip);
+ }
+ if (pvt->v_redirport) {
+ free(pvt->v_redirport);
+ }
+
+ if (pvt->owner) {
+ while(ast_channel_trylock(pvt->owner)) {
+ ast_debug(1, "Failed to grab lock, trying again\n");
+ DEADLOCK_AVOIDANCE(&pvt->lock);
+ }
+ ast_debug(1, "Detaching from %s\n", pvt->owner->name);
+ pvt->owner->tech_pvt = NULL;
+ ast_channel_unlock(pvt->owner);
+ pvt->owner = NULL;
+ ast_module_unref(myself);
+ }
+
+ /* ast_mutex_lock(&pvt->xrlock);
+ xmlrpc_client_destroy(pvt->xr_client);
+ pvt->xr_client = NULL;
+ ast_mutex_unlock(&pvt->xrlock); */
+
+ pvt->stop_rpc = 1;
+
+ ast_mutex_unlock(&pvt->lock);
+}
+static struct ast_channel* mcu_chan_new(struct mcu_pvt *p, int state, char *url, struct ast_format_cap *cap,
+ const char *linkedid)
+{
+ struct ast_channel *chan = NULL;
+ struct ast_format tmpfmt;
+
+ if (mcuDebug) {
+ ast_verbose("--- mcu_new %s\n", url);
+ }
+ ast_mutex_lock(&mcu_cn_lock);
+ chan = ast_channel_alloc(1, state, "", "", "", "", "", linkedid, 0, "MCU/%s-%ld", url, mcu_callnum);
+ mcu_callnum++;
+ ast_mutex_unlock(&mcu_cn_lock);
+ if (chan) {
+ ast_channel_lock(chan);
+ chan->tech = &mcu_tech;
+ if (cap) {
+ ast_format_cap_copy(chan->nativeformats, cap);
+ ast_best_codec(cap, &tmpfmt);
+ ast_format_copy(&chan->rawwriteformat, &tmpfmt);
+ ast_format_copy(&chan->rawwriteformat, &tmpfmt);
+ ast_set_write_format(chan, &tmpfmt);
+ ast_set_read_format(chan, &tmpfmt);
+ }
+ chan->tech_pvt = (void *)p;
+ p->owner = chan;
+ ast_module_ref(myself);
+ ast_update_use_count();
+ ast_setstate(chan, state);
+ ast_channel_unlock(chan);
+ }
+
+ return chan;
+}
+
+/*! \brief Function called when we should prepare to call the destination */
+static struct ast_channel *mcu_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, void *data, int *cause)
+{
+ struct ast_channel *chan;
+ char formats[FORMAT_STRING_SIZE];
+ struct mcu_pvt *p;
+ struct ast_format tmpfmt;
+
+
+ if (mcuDebug) {
+ ast_verbose("mcu_request data %s format %s\n", (char *)data,
+ ast_getformatname_multiple(formats,FORMAT_STRING_SIZE,cap));
+ }
+
+ if (!(ast_format_cap_has_type(cap, AST_FORMAT_TYPE_AUDIO)) ||
+ (!(ast_format_cap_iscompatible(cap, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0))) && !(ast_format_cap_iscompatible(cap, ast_format_set(&tmpfmt, AST_FORMAT_SPEEX16, 0))))) {
+ ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s' (we support alaw audio only now)\n",
+ ast_getformatname_multiple(formats,FORMAT_STRING_SIZE,cap));
+ goto failure;
+ }
+
+ // h.264 and vp8 only now
+ if (ast_format_cap_has_type(cap, AST_FORMAT_TYPE_VIDEO)) {
+#ifdef AST_FORMAT_VP8
+ if (!(ast_format_cap_iscompatible(cap, ast_format_set(&tmpfmt, AST_FORMAT_H264, 0))) &&
+ !(ast_format_cap_iscompatible(cap, ast_format_set(&tmpfmt, AST_FORMAT_VP8, 0)))) {
+#else
+ if (!(ast_format_cap_iscompatible(cap, ast_format_set(&tmpfmt, AST_FORMAT_H264, 0)))) {
+#endif
+ ast_log(LOG_NOTICE, "H.264 or VP8 video only supported\n");
+ goto failure;
+ }
+ }
+
+ if (!(p = mcu_alloc((char *)data))) {
+ ast_log(LOG_WARNING, "Can't build pvt data for %s\n", (char *)data);
+ goto failure;
+ }
+
+ ast_mutex_lock(&p->lock);
+ chan = mcu_chan_new(p, AST_STATE_DOWN, (char *)data, cap, requestor ? requestor->linkedid : NULL);
+ ast_mutex_unlock(&p->lock);
+
+ if (!chan) {
+ mcu_destroy(p);
+ goto failure;
+ }
+
+ if (!configure_rtp(p)) {
+ mcu_destroy(p);
+ goto failure;
+ }
+
+ if (mcuDebug) {
+ ast_verbose("mcu_request success\n");
+ }
+
+ return chan;
+
+failure:
+ *cause = AST_CAUSE_FAILURE;
+ return NULL;
+}
+
+/*! \brief Function called when we should actually call the destination */
+static int mcu_call(struct ast_channel *ast, char *dest, int timeout)
+{
+ struct mcu_pvt *p = ast->tech_pvt;
+
+ xmlrpc_value *confP, *nameP, *typP, *barP, *mosP;
+
+ pthread_attr_t attr;
+
+ if (!p) {
+ return -1;
+ }
+
+ if (mcuDebug) {
+ ast_verbose("--- MCU Call\n");
+ }
+
+ xmlrpc_env_init(&p->env);
+
+ ast_mutex_lock(&p->lock);
+
+ p->clid = defaultCLID;
+
+ if (ast->connected.id.name.valid && ast->connected.id.name.str && ast->connected.id.name.str[0]) {
+ p->clid = strdup(ast->connected.id.name.str);
+ } else {
+ if (ast->connected.id.number.valid && ast->connected.id.number.str && ast->connected.id.number.str[0]) {
+ p->clid = strdup(ast->connected.id.number.str);
+ }
+ }
+
+ if (dest) {
+ p->mcu_call = get_conference_by_name(dest);
+ if (p->mcu_call) {
+ p->confId = p->mcu_call->confId;
+ } else {
+ return -1;
+ }
+ }
+ if (!p->confId || !p->mcu_call->url) {
+ ast_mutex_unlock(&p->lock);
+ return -1;
+ }
+ p->qxr_server = xmlrpc_server_info_new(&p->env, p->mcu_call->url);
+
+ /* creating xmlrpc finishing thread */
+ ast_mutex_lock(&p->xrlock);
+
+ pthread_attr_init(&attr);
+ if ((errno = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED | PTHREAD_CREATE_JOINABLE))) {
+ ast_log(LOG_WARNING, "pthread_attr_setdetachstate: %s\n", strerror(errno));
+ }
+ if(ast_pthread_create_detached_background(&p->finishThread, NULL, loop_thread, p) < 0) {
+ ast_log(LOG_ERROR, "Unable to start loop thread for channel %s\n", ast->name);
+ ast_mutex_unlock(&p->lock);
+ return -1;
+ }
+
+ /* call mcu to create participaant */
+
+ if (mcuDebug) {
+ ast_verbose("xmlrpc_call: %s \"%s\" %s\n", p->mcu_call->url, "CreateParticipant", p->clid);
+ }
+
+ // xmlrpc_client_start_rpcf(&env, p->xr_client, p->mcuId, "CreateParticipant", onCreateParticipant, p,
+ // "(isiii)", p->confId, p->clid, 0,0,0);
+
+ confP = xmlrpc_int_new(&p->env, p->confId);
+ nameP = xmlrpc_string_new(&p->env, p->clid);
+ mosP = xmlrpc_int_new(&p->env, 0);
+ typP = xmlrpc_int_new(&p->env, 0);
+ barP = xmlrpc_int_new(&p->env, 0);
+ p->qxr_parm = xmlrpc_array_new(&p->env);
+ xmlrpc_array_append_item(&p->env, p->qxr_parm, confP);
+ xmlrpc_array_append_item(&p->env, p->qxr_parm, nameP);
+ xmlrpc_array_append_item(&p->env, p->qxr_parm, mosP);
+ xmlrpc_array_append_item(&p->env, p->qxr_parm, typP);
+ xmlrpc_array_append_item(&p->env, p->qxr_parm, barP);
+
+ xmlrpc_DECREF(confP);
+ xmlrpc_DECREF(nameP);
+ xmlrpc_DECREF(mosP);
+ xmlrpc_DECREF(typP);
+ xmlrpc_DECREF(barP);
+
+ p->qxr_cbfunc = onCreateParticipant;
+ p->qxr_method = "CreateParticipant";
+ p->xreqs = 1;
+
+ ast_mutex_unlock(&p->xrlock);
+ ast_cond_signal(&p->xrcond);
+
+ // xmlrpc_client_event_loop_finish(p->xr_client);
+
+ /* xmlrpc_client_call2f(&xmlrpcenv, p->xr_client, p->mcuId, "CreateParticipant", &rpcres,
+ "(isiii)", p->confId, p->clid, 0,0,0);
+
+ if (xmlrpcenv.fault_code) {
+ ast_log(LOG_ERROR, "xmlrpc fault %d:%s\n", xmlrpcenv.fault_code, xmlrpcenv.fault_string);
+ }
+
+ xmlrpc_parse_value(&xmlrpcenv, rpcres, "{s:(i),*}", "returnVal", &p->partId);
+
+ if (xmlrpcenv.fault_code) {
+ ast_log(LOG_ERROR, "xmlrpc parse fault %d:%s\n", xmlrpcenv.fault_code, xmlrpcenv.fault_string);
+ }
+
+ xmlrpc_DECREF(rpcres);
+
+ if (mcuDebug) {
+ ast_verbose("mcu_call: partId is %s:%d\n", tmpstr, p->partId);
+ } */
+
+
+ ast_mutex_unlock(&p->lock);
+
+ if (mcuDebug) {
+ ast_verbose("+++ MCU Call\n");
+ }
+
+ return 0;
+}
+
+/*! \brief Function called when we should hang the channel up */
+static int mcu_hangup(struct ast_channel *ast)
+{
+ struct mcu_pvt *p = ast->tech_pvt;
+ xmlrpc_value *confP, *partP;
+ xmlrpc_env env;
+
+ xmlrpc_env_init(&env);
+
+ if (p) {
+ ast_mutex_lock(&p->lock);
+ }
+
+ /* call mcu to delete participaant */
+
+ if (mcuDebug) {
+ ast_verbose("xmlrpc_call: %s \"%s\" %s\n", p->mcu_call->url, "DeleteParticipant", p->clid);
+ }
+
+ ast_mutex_lock(&p->xrlock);
+
+ // xmlrpc_parse_value(env, param_array, "(ii)", &confId,&partId);
+
+ confP = xmlrpc_int_new(&env, p->confId);
+ partP = xmlrpc_int_new(&env, p->partId);
+ p->qxr_parm = xmlrpc_array_new(&env);
+ xmlrpc_array_append_item(&env, p->qxr_parm, confP);
+ xmlrpc_array_append_item(&env, p->qxr_parm, partP);
+
+ xmlrpc_DECREF(confP);
+ xmlrpc_DECREF(partP);
+
+ p->qxr_cbfunc = onDeleteParticipant;
+ p->qxr_method = "DeleteParticipant";
+ p->xreqs = 1;
+
+ ast_mutex_unlock(&p->xrlock);
+ ast_cond_signal(&p->xrcond);
+ ast_mutex_unlock(&p->lock);
+
+ mcu_destroy(p);
+
+ return 0;
+}
+
+static int mcu_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
+{
+ struct mcu_pvt *p = NULL;
+ int ret = -1;
+
+ if (!newchan || !newchan->tech_pvt) {
+ if (!newchan)
+ ast_log(LOG_WARNING, "No new channel! Fixup of %s failed.\n", oldchan->name);
+ if (!newchan->tech_pvt)
+ ast_log(LOG_WARNING, "No MCU tech on new chan, Fixup of %s failed.\n", oldchan->name);
+ return -1;
+ }
+
+ p = newchan->tech_pvt;
+
+ ast_mutex_lock(&p->lock);
+
+ if (p->owner != oldchan) {
+ ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
+ } else {
+ p->owner = newchan;
+ ret = 0;
+ }
+
+ ast_mutex_unlock(&p->lock);
+ return ret;
+}
+
+
+static int mcu_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
+{
+ struct mcu_pvt *p = ast->tech_pvt;
+ int res = -1;
+
+ if (!p) {
+ return -1;
+ }
+
+ if (mcuDebug) {
+ ast_verbose("mcu_indicate %d on %s\n", condition, ast->name);
+ }
+
+ ast_mutex_lock(&p->lock);
+ switch (condition) {
+ case AST_CONTROL_SRCUPDATE:
+ case AST_CONTROL_SRCCHANGE:
+ if (p->rtp) {
+ ast_rtp_instance_update_source(p->rtp);
+ }
+ if (p->vrtp) {
+ ast_rtp_instance_update_source(p->vrtp);
+ }
+ res = 0;
+ break;
+ default:
+ ast_log(LOG_WARNING, "Don't know how to indicate %d on %s\n", condition, ast->name);
+ }
+ ast_mutex_unlock(&p->lock);
+ return res;
+}
+
+
+/*
+ RTP handling
+ */
+
+static void mcu_get_codec(struct ast_channel *chan, struct ast_format_cap *result)
+{
+ ast_format_cap_append(result, chan->nativeformats);
+}
+
+static enum ast_rtp_glue_result mcu_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **rtp)
+{
+ struct mcu_pvt *pvt = NULL;
+ enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_REMOTE;
+ struct ast_sockaddr tmp;
+
+ if (!(pvt = (struct mcu_pvt *) chan->tech_pvt) || !pvt->rtp || !pvt->audio_port) {
+ return AST_RTP_GLUE_RESULT_FORBID;
+ }
+
+ ast_mutex_lock(&pvt->lock);
+
+ *rtp = pvt->rtp ? ao2_ref(pvt->rtp, +1), pvt->rtp : NULL;
+ ast_rtp_instance_get_remote_address(*rtp, &tmp);
+ if (mcuDebug) {
+ ast_verbose("mcu_get_rtp_peer %s -> %s:%d, %d\n", chan->name, ast_sockaddr_stringify_addr(&tmp),
+ ast_sockaddr_port(&tmp), res);
+ }
+
+ ast_mutex_unlock(&pvt->lock);
+ return res;
+
+}
+
+
+static enum ast_rtp_glue_result mcu_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp_instance **rtp)
+{
+ struct mcu_pvt *pvt = NULL;
+ enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_REMOTE;
+ struct ast_sockaddr tmp;
+
+ if (!(pvt = (struct mcu_pvt *) chan->tech_pvt) || !pvt->vrtp || !pvt->video_port) {
+ return AST_RTP_GLUE_RESULT_FORBID;
+ }
+
+ ast_mutex_lock(&pvt->lock);
+
+ /* get rtp from mcu */
+
+
+ *rtp = pvt->vrtp ? ao2_ref(pvt->vrtp, +1), pvt->vrtp : NULL;
+ ast_rtp_instance_get_remote_address(*rtp, &tmp);
+ if (mcuDebug) {
+ ast_verbose("mcu_get_vrtp_peer %s -> %s:%d, %d\n", chan->name, ast_sockaddr_stringify_addr(&tmp),
+ ast_sockaddr_port(&tmp), res);
+ }
+
+ ast_mutex_unlock(&pvt->lock);
+ return res;
+}
+
+static int mcu_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *instance, struct ast_rtp_instance *vinstance, struct ast_rtp_instance *tinstance, const struct ast_format_cap *cap, int nat_active)
+{
+ struct mcu_pvt* pvt = NULL;
+ struct ast_sockaddr tmp;
+ int changed = 0;
+
+ ast_channel_lock(chan);
+ pvt = chan->tech_pvt;
+ ast_mutex_lock(&pvt->lock);
+
+ if (instance) {
+ ast_rtp_instance_get_remote_address(instance, &tmp);
+ if (pvt->a_redirip && pvt->a_redirport &&
+ !strcmp(pvt->a_redirip, ast_sockaddr_stringify_host(&tmp)) &&
+ !strcmp(pvt->a_redirport, ast_sockaddr_stringify_port(&tmp))) {
+ changed = 0;
+ } else {
+ if (pvt->a_redirip) {
+ free(pvt->a_redirip);
+ }
+ if (pvt->a_redirport) {
+ free(pvt->a_redirport);
+ }
+ pvt->a_redirip = strdup(ast_sockaddr_stringify_host(&tmp));
+ pvt->a_redirport = strdup(ast_sockaddr_stringify_port(&tmp));
+ changed = 1;
+ }
+ if (mcuDebug) {
+ ast_verbose("mcu_set_rtp_peer %s(a) -> %s:%d (%s)\n", chan->name, ast_sockaddr_stringify_addr(&tmp),
+ ast_sockaddr_port(&tmp), changed ? "changed" : "no change");
+ }
+ }
+ if (vinstance) {
+ ast_rtp_instance_get_remote_address(vinstance, &tmp);
+ if (pvt->v_redirip && pvt->v_redirport &&
+ !strcmp(pvt->v_redirip, ast_sockaddr_stringify_host(&tmp)) &&
+ !strcmp(pvt->v_redirport, ast_sockaddr_stringify_port(&tmp))) {
+ changed = 0;
+ } else {
+ if (pvt->v_redirip) {
+ free(pvt->v_redirip);
+ }
+ if (pvt->v_redirport) {
+ free(pvt->v_redirport);
+ }
+ pvt->v_redirip = strdup(ast_sockaddr_stringify_host(&tmp));
+ pvt->v_redirport = strdup(ast_sockaddr_stringify_port(&tmp));
+ changed = 1;
+ }
+ if (mcuDebug) {
+ ast_verbose("mcu_set_rtp_peer %s(v) -> %s:%d (%s)\n", chan->name, ast_sockaddr_stringify_addr(&tmp),
+ ast_sockaddr_port(&tmp), changed ? "changed" : "no change");
+ }
+ }
+ if (changed) {
+ SendReStartSending(pvt);
+ }
+ ast_mutex_unlock(&pvt->lock);
+ ast_channel_unlock(chan);
+ return 0;
+}
+
+
+/*
+ Direct XML RPC calls
+ */
+
+void SendReStartSending(struct mcu_pvt *p)
+{
+ xmlrpc_env env;
+ xmlrpc_value *confP, *partP, *mediaP, *ipP, *portP, *rtpmapP, *acP;
+
+ xmlrpc_env_init(&env);
+
+ ast_mutex_unlock(&p->lock);
+ ast_mutex_lock(&p->xrlock);
+ ast_mutex_lock(&p->lock);
+
+ if (p->a_redirip) {
+
+ if (mcuDebug) {
+ ast_verbose("reset audio to %s:%s\n", p->a_redirip, p->a_redirport);
+ }
+
+ confP = xmlrpc_int_new(&env, p->confId);
+ partP = xmlrpc_int_new(&env, p->partId);
+ mediaP = xmlrpc_int_new(&env, 0); // audio
+
+ ipP = xmlrpc_string_new(&env, p->a_redirip);
+ portP = xmlrpc_int_new(&env, atoi(p->a_redirport));
+
+ rtpmapP = xmlrpc_struct_new(&env);
+ acP = xmlrpc_int_new(&env, p->audio_codec);
+ if (p->audio_codec == PCMA) {
+ xmlrpc_struct_set_value(&env, rtpmapP, ALAW_PAYLOAD_NAME, acP);
+ } else {
+ xmlrpc_struct_set_value(&env, rtpmapP, SPEEX16_PAYLOAD_NAME, acP);
+ }
+
+ p->qxr_parm = xmlrpc_array_new(&p->env);
+ xmlrpc_array_append_item(&p->env, p->qxr_parm, confP);
+ xmlrpc_array_append_item(&p->env, p->qxr_parm, partP);
+ xmlrpc_array_append_item(&p->env, p->qxr_parm, mediaP);
+ xmlrpc_array_append_item(&p->env, p->qxr_parm, ipP);
+ xmlrpc_array_append_item(&p->env, p->qxr_parm, portP);
+ xmlrpc_array_append_item(&p->env, p->qxr_parm, rtpmapP);
+
+ xmlrpc_DECREF(confP);
+ xmlrpc_DECREF(partP);
+ xmlrpc_DECREF(mediaP);
+ xmlrpc_DECREF(ipP);
+ xmlrpc_DECREF(portP);
+ xmlrpc_DECREF(rtpmapP);
+
+ p->qxr_cbfunc = onReStartAudioSending;
+ p->qxr_method = "StartSending";
+
+ p->xreqs = 1;
+
+ ast_mutex_unlock(&p->xrlock);
+ ast_cond_signal(&p->xrcond);
+ }
+}
+
+void SendStartAudio(struct mcu_pvt *p)
+{
+ xmlrpc_env env;
+ xmlrpc_value *confP, *partP, *codecP;
+
+ xmlrpc_env_init(&env);
+
+ ast_mutex_unlock(&p->lock);
+ ast_mutex_lock(&p->xrlock);
+ ast_mutex_lock(&p->lock);
+
+ if (p->audio_codec) {
+ if (mcuDebug) {
+ ast_verbose("sending SetAudioCodec %d\n", p->audio_codec);
+ }
+
+ confP = xmlrpc_int_new(&p->env, p->confId);
+ partP = xmlrpc_int_new(&p->env, p->partId);
+ codecP = xmlrpc_int_new(&p->env, p->audio_codec);
+ p->qxr_parm = xmlrpc_array_new(&p->env);
+ xmlrpc_array_append_item(&p->env, p->qxr_parm, confP);
+ xmlrpc_array_append_item(&p->env, p->qxr_parm, partP);
+ xmlrpc_array_append_item(&p->env, p->qxr_parm, codecP);
+
+ xmlrpc_DECREF(confP);
+ xmlrpc_DECREF(partP);
+ xmlrpc_DECREF(codecP);
+
+ p->qxr_cbfunc = onSetAudioCodec;
+ p->qxr_method = "SetAudioCodec";
+ p->xreqs = 1;
+
+ ast_mutex_unlock(&p->xrlock);
+ ast_cond_signal(&p->xrcond);
+ }
+
+}
+
+void SendStartVideo(struct mcu_pvt *p)
+{
+ xmlrpc_env env;
+ xmlrpc_value *confP, *partP, *codecP, *modeP, *fpsP, *bitrateP, *qualityP, *fillLevelP, *intraPeriodP;
+
+ xmlrpc_env_init(&env);
+
+ ast_mutex_unlock(&p->lock);
+ while (p->owner && ast_mutex_trylock(&p->xrlock)) {
+ ast_debug(1, "Failed to grab lock, trying again\n");
+ CHANNEL_DEADLOCK_AVOIDANCE(p->owner);
+ }
+ ast_mutex_lock(&p->lock);
+ if (!p->owner) {
+ return;
+ }
+
+ if (p->video_codec) {
+ if (mcuDebug) {
+ ast_verbose("sending SetVideoCodec %d\n", p->video_codec);
+ }
+ confP = xmlrpc_int_new(&p->env, p->confId);
+ partP = xmlrpc_int_new(&p->env, p->partId);
+ codecP = xmlrpc_int_new(&p->env, p->video_codec);
+ modeP = xmlrpc_int_new(&p->env, p->mcu_call->mode);
+ fpsP = xmlrpc_int_new(&p->env, p->mcu_call->fps);
+ bitrateP = xmlrpc_int_new(&p->env, p->mcu_call->bitrate);
+ qualityP = xmlrpc_int_new(&p->env, 0);
+ fillLevelP = xmlrpc_int_new(&p->env, 0);
+ intraPeriodP = xmlrpc_int_new(&p->env, p->mcu_call->intraPeriod);
+
+ p->qxr_parm = xmlrpc_array_new(&p->env);
+ xmlrpc_array_append_item(&p->env, p->qxr_parm, confP);
+ xmlrpc_array_append_item(&p->env, p->qxr_parm, partP);
+ xmlrpc_array_append_item(&p->env, p->qxr_parm, codecP);
+ xmlrpc_array_append_item(&p->env, p->qxr_parm, modeP);
+ xmlrpc_array_append_item(&p->env, p->qxr_parm, fpsP);
+ xmlrpc_array_append_item(&p->env, p->qxr_parm, bitrateP);
+ xmlrpc_array_append_item(&p->env, p->qxr_parm, qualityP);
+ xmlrpc_array_append_item(&p->env, p->qxr_parm, fillLevelP);
+ xmlrpc_array_append_item(&p->env, p->qxr_parm, intraPeriodP);
+
+ xmlrpc_DECREF(confP);
+ xmlrpc_DECREF(partP);
+ xmlrpc_DECREF(codecP);
+ xmlrpc_DECREF(modeP);
+ xmlrpc_DECREF(fpsP);
+ xmlrpc_DECREF(bitrateP);
+ xmlrpc_DECREF(qualityP);
+ xmlrpc_DECREF(fillLevelP);
+ xmlrpc_DECREF(intraPeriodP);
+
+ p->qxr_cbfunc = onSetVideoCodec;
+ p->qxr_method = "SetVideoCodec";
+ p->xreqs = 1;
+
+ ast_mutex_unlock(&p->xrlock);
+ ast_cond_signal(&p->xrcond);
+ }
+
+}
+
+/*
+ Callbacks from XMLRPC lib
+ */
+
+void onCreateParticipant(const char* url, const char* method, xmlrpc_value *params, void *user_data,
+ xmlrpc_env *faultP, xmlrpc_value *resultP)
+{
+ struct ast_channel *c;
+ struct mcu_pvt *p = (struct mcu_pvt *)user_data;
+ xmlrpc_env env;
+
+ xmlrpc_value *confP, *partP, *posP;
+
+ xmlrpc_env_init(&env);
+ ast_mutex_lock(&p->lock);
+
+ if (mcuDebug) {
+ ast_verbose("onCreateParticipant\n");
+ }
+ if (!faultP->fault_occurred) {
+ xmlrpc_parse_value(&p->env, resultP, "{s:(i),*}", "returnVal", &p->partId);
+ if (p->env.fault_code) {
+ ast_log(LOG_ERROR, "xmlrpc parse fault %d:%s\n", p->env.fault_code, p->env.fault_string);
+ }
+ // xmlrpc_DECREF(resultP);
+ if (!p->partId) {
+ ast_log(LOG_ERROR, "participant ID not returned\n");
+ }
+ }
+
+ ast_verbose("+++ partId = %d\n", p->partId);
+
+ if (!p->owner) {
+ ast_log(LOG_ERROR, "No matching call found\n");
+ ast_mutex_unlock(&p->lock);
+ return;
+ }
+
+ while (p->owner && ast_channel_trylock(p->owner)) {
+ ast_debug(1, "Failed to grab lock, trying again\n");
+ DEADLOCK_AVOIDANCE(&p->lock);
+ }
+
+ if (!p->owner) {
+ ast_log(LOG_ERROR, "No matching call found\n");
+ ast_mutex_unlock(&p->lock);
+ return;
+ }
+
+ c = p->owner;
+
+ if (p->partId) {
+ ast_queue_control(c, AST_CONTROL_PROCEEDING);
+ } else {
+ ast_queue_control(c, AST_CONTROL_HANGUP);
+ ast_channel_unlock(c);
+ ast_mutex_unlock(&p->lock);
+ return;
+ }
+
+ /* Sending StartReceiving for audio */
+
+ /* ast_format_cap_iter_start(chan->nativeformats);
+ while (!ast_format_cap_iter_next(chan->nativeformats, &tmpfmt)) {
+ if (AST_FORMAT_GET_TYPE(tmpfmt.id) == AST_FORMAT_TYPE_AUDIO) {
+ continue;
+ }
+ } */
+
+ // Fix me here !!! we must get codec payload
+ // audio_codec = ast_rtp_codecs_get_payload_format();
+
+ ast_channel_unlock(c);
+
+ if (mcuDebug) {
+ ast_verbose("sending AddMosaicParticipant to mcu on %s\n", c->name);
+ }
+ xmlrpc_env_init(&env);
+ confP = xmlrpc_int_new(&env, p->confId);
+ partP = xmlrpc_int_new(&env, p->partId);
+ posP = xmlrpc_int_new(&env, 0);
+ p->qxr_parm = xmlrpc_array_new(&env);
+ xmlrpc_array_append_item(&env, p->qxr_parm, confP);
+ xmlrpc_array_append_item(&env, p->qxr_parm, posP);
+ xmlrpc_array_append_item(&env, p->qxr_parm, partP);
+
+ xmlrpc_DECREF(confP);
+ xmlrpc_DECREF(partP);
+ xmlrpc_DECREF(posP);
+
+ p->qxr_cbfunc = onAddMosaicParticipant;
+ p->qxr_method = "AddMosaicParticipant";
+ p->xreqs = 1;
+ ast_mutex_unlock(&p->lock);
+
+}
+
+void onAddMosaicParticipant(const char* url, const char* method, xmlrpc_value *params, void *user_data,
+ xmlrpc_env *faultP, xmlrpc_value *resultP)
+{
+ struct mcu_pvt *p = (struct mcu_pvt *)user_data;
+ struct ast_channel *c;
+ int rc = 0;
+ xmlrpc_env env;
+
+ xmlrpc_value *confP, *partP, *posP;
+
+ xmlrpc_env_init(&env);
+
+ ast_mutex_lock(&p->lock);
+ if (mcuDebug) {
+ ast_verbose("onAddMosaicParticipant\n");
+ }
+
+ if (!faultP->fault_occurred) {
+ xmlrpc_parse_value(&env, resultP, "{s:i,*}", "returnCode", &rc);
+ if (env.fault_code) {
+ ast_log(LOG_ERROR, "xmlrpc parse fault %d:%s\n", env.fault_code, env.fault_string);
+ }
+ // xmlrpc_DECREF(resultP);
+ }
+
+ if (!p->owner) {
+ ast_log(LOG_ERROR, "No matching call found\n");
+ ast_mutex_unlock(&p->lock);
+ return;
+ }
+
+ while (p->owner && ast_channel_trylock(p->owner)) {
+ ast_debug(1, "Failed to grab lock, trying again\n");
+ DEADLOCK_AVOIDANCE(&p->lock);
+ }
+
+ if (!p->owner) {
+ ast_log(LOG_ERROR, "No matching call found\n");
+ ast_mutex_unlock(&p->lock);
+ return;
+ }
+
+ c = p->owner;
+
+ if (rc != 1) {
+ ast_queue_control(c, AST_CONTROL_HANGUP);
+ ast_channel_unlock(c);
+ ast_mutex_unlock(&p->lock);
+ return;
+ }
+
+ ast_channel_unlock(c);
+
+
+ if (mcuDebug) {
+ ast_verbose("sending AddSideBarParticipant to mcu on %s\n", c->name);
+ }
+ xmlrpc_env_init(&env);
+ confP = xmlrpc_int_new(&env, p->confId);
+ partP = xmlrpc_int_new(&env, p->partId);
+ posP = xmlrpc_int_new(&env, 0);
+ p->qxr_parm = xmlrpc_array_new(&env);
+ xmlrpc_array_append_item(&env, p->qxr_parm, confP);
+ xmlrpc_array_append_item(&env, p->qxr_parm, posP);
+ xmlrpc_array_append_item(&env, p->qxr_parm, partP);
+
+ xmlrpc_DECREF(confP);
+ xmlrpc_DECREF(partP);
+ xmlrpc_DECREF(posP);
+
+ p->qxr_cbfunc = onAddSidebarParticipant;
+ p->qxr_method = "AddSidebarParticipant";
+ p->xreqs = 1;
+ ast_mutex_unlock(&p->lock);
+}
+
+void onAddSidebarParticipant(const char* url, const char* method, xmlrpc_value *params, void *user_data,
+ xmlrpc_env *faultP, xmlrpc_value *resultP)
+{
+ struct mcu_pvt *p = (struct mcu_pvt *)user_data;
+ struct ast_channel *c;
+ int rc = 0;
+ xmlrpc_env env;
+
+ xmlrpc_env_init(&env);
+ ast_mutex_lock(&p->lock);
+ if (mcuDebug) {
+ ast_verbose("onAddSideBarParticipant\n");
+ }
+
+ if (!faultP->fault_occurred) {
+ xmlrpc_parse_value(&env, resultP, "{s:i,*}", "returnCode", &rc);
+ if (env.fault_code) {
+ ast_log(LOG_ERROR, "xmlrpc parse fault %d:%s\n", env.fault_code, env.fault_string);
+ }
+ // xmlrpc_DECREF(resultP);
+ }
+
+ if (!p->owner) {
+ ast_log(LOG_ERROR, "No matching call found\n");
+ ast_mutex_unlock(&p->lock);
+ return;
+ }
+
+ while (p->owner && ast_channel_trylock(p->owner)) {
+ ast_debug(1, "Failed to grab lock, trying again\n");
+ DEADLOCK_AVOIDANCE(&p->lock);
+ }
+
+ if (!p->owner) {
+ ast_log(LOG_ERROR, "No matching call found\n");
+ ast_mutex_unlock(&p->lock);
+ return;
+ }
+
+ c = p->owner;
+
+ if (rc == 1) {
+ ast_queue_control(c, AST_CONTROL_PROGRESS);
+ } else {
+ ast_queue_control(c, AST_CONTROL_HANGUP);
+ ast_channel_unlock(c);
+ ast_mutex_unlock(&p->lock);
+ return;
+ }
+
+ ast_channel_unlock(c);
+
+ p->init_done = 1;
+ ast_mutex_unlock(&p->lock);
+}
+
[... 1745 lines stripped ...]
More information about the asterisk-commits
mailing list