From 48f90036d8b011be3a3ea327ca2619aeb97b72b1 Mon Sep 17 00:00:00 2001
From: David Baker
Date: Tue, 2 Dec 2014 12:01:30 +0000
Subject: [PATCH] Add non-working jitsi meet bridge
---
contrib/jitsimeetbridge/jitsimeetbridge.py | 260 ++
.../syweb-jitsi-conference.patch | 188 +
contrib/jitsimeetbridge/unjingle/.swp | Bin 0 -> 12288 bytes
.../unjingle/strophe.jingle.sdp.js | 712 ++++
.../unjingle/strophe.jingle.sdp.util.js | 408 +++
.../unjingle/strophe/XMLHttpRequest.js | 254 ++
.../unjingle/strophe/base64.js | 83 +
.../jitsimeetbridge/unjingle/strophe/md5.js | 279 ++
.../unjingle/strophe/strophe.js | 3256 +++++++++++++++++
contrib/jitsimeetbridge/unjingle/unjingle.js | 48 +
10 files changed, 5488 insertions(+)
create mode 100644 contrib/jitsimeetbridge/jitsimeetbridge.py
create mode 100644 contrib/jitsimeetbridge/syweb-jitsi-conference.patch
create mode 100644 contrib/jitsimeetbridge/unjingle/.swp
create mode 100644 contrib/jitsimeetbridge/unjingle/strophe.jingle.sdp.js
create mode 100644 contrib/jitsimeetbridge/unjingle/strophe.jingle.sdp.util.js
create mode 100644 contrib/jitsimeetbridge/unjingle/strophe/XMLHttpRequest.js
create mode 100644 contrib/jitsimeetbridge/unjingle/strophe/base64.js
create mode 100644 contrib/jitsimeetbridge/unjingle/strophe/md5.js
create mode 100644 contrib/jitsimeetbridge/unjingle/strophe/strophe.js
create mode 100644 contrib/jitsimeetbridge/unjingle/unjingle.js
diff --git a/contrib/jitsimeetbridge/jitsimeetbridge.py b/contrib/jitsimeetbridge/jitsimeetbridge.py
new file mode 100644
index 000000000..dbc6f6ffa
--- /dev/null
+++ b/contrib/jitsimeetbridge/jitsimeetbridge.py
@@ -0,0 +1,260 @@
+#!/usr/bin/env python
+
+"""
+This is an attempt at bridging matrix clients into a Jitis meet room via Matrix
+video call. It uses hard-coded xml strings overg XMPP BOSH. It can display one
+of the streams from the Jitsi bridge until the second lot of SDP comes down and
+we set the remote SDP at which point the stream ends. Our video never gets to
+the bridge.
+
+Requires:
+npm install jquery jsdom
+"""
+
+import gevent
+import grequests
+from BeautifulSoup import BeautifulSoup
+import json
+import urllib
+import subprocess
+import time
+
+#ACCESS_TOKEN="" #
+
+MATRIXBASE = 'https://matrix.org/_matrix/client/api/v1/'
+MYUSERNAME = '@davetest:matrix.org'
+
+HTTPBIND = 'https://meet.jit.si/http-bind'
+#HTTPBIND = 'https://jitsi.vuc.me/http-bind'
+#ROOMNAME = "matrix"
+ROOMNAME = "pibble"
+
+HOST="guest.jit.si"
+#HOST="jitsi.vuc.me"
+
+TURNSERVER="turn.guest.jit.si"
+#TURNSERVER="turn.jitsi.vuc.me"
+
+ROOMDOMAIN="meet.jit.si"
+#ROOMDOMAIN="conference.jitsi.vuc.me"
+
+class TrivialMatrixClient:
+ def __init__(self, access_token):
+ self.token = None
+ self.access_token = access_token
+
+ def getEvent(self):
+ while True:
+ url = MATRIXBASE+'events?access_token='+self.access_token+"&timeout=60000"
+ if self.token:
+ url += "&from="+self.token
+ req = grequests.get(url)
+ resps = grequests.map([req])
+ obj = json.loads(resps[0].content)
+ print "incoming from matrix",obj
+ if 'end' not in obj:
+ continue
+ self.token = obj['end']
+ if len(obj['chunk']):
+ return obj['chunk'][0]
+
+ def joinRoom(self, roomId):
+ url = MATRIXBASE+'rooms/'+roomId+'/join?access_token='+self.access_token
+ print url
+ headers={ 'Content-Type': 'application/json' }
+ req = grequests.post(url, headers=headers, data='{}')
+ resps = grequests.map([req])
+ obj = json.loads(resps[0].content)
+ print "response: ",obj
+
+ def sendEvent(self, roomId, evType, event):
+ url = MATRIXBASE+'rooms/'+roomId+'/send/'+evType+'?access_token='+self.access_token
+ print url
+ print json.dumps(event)
+ headers={ 'Content-Type': 'application/json' }
+ req = grequests.post(url, headers=headers, data=json.dumps(event))
+ resps = grequests.map([req])
+ obj = json.loads(resps[0].content)
+ print "response: ",obj
+
+
+
+xmppClients = {}
+
+
+def matrixLoop():
+ while True:
+ ev = matrixCli.getEvent()
+ print ev
+ if ev['type'] == 'm.room.member':
+ print 'membership event'
+ if ev['membership'] == 'invite' and ev['state_key'] == MYUSERNAME:
+ roomId = ev['room_id']
+ print "joining room %s" % (roomId)
+ matrixCli.joinRoom(roomId)
+ elif ev['type'] == 'm.room.message':
+ if ev['room_id'] in xmppClients:
+ print "already have a bridge for that user, ignoring"
+ continue
+ print "got message, connecting"
+ xmppClients[ev['room_id']] = TrivialXmppClient(ev['room_id'], ev['user_id'])
+ gevent.spawn(xmppClients[ev['room_id']].xmppLoop)
+ elif ev['type'] == 'm.call.invite':
+ print "Incoming call"
+ #sdp = ev['content']['offer']['sdp']
+ #print "sdp: %s" % (sdp)
+ #xmppClients[ev['room_id']] = TrivialXmppClient(ev['room_id'], ev['user_id'])
+ #gevent.spawn(xmppClients[ev['room_id']].xmppLoop)
+ elif ev['type'] == 'm.call.answer':
+ print "Call answered"
+ sdp = ev['content']['answer']['sdp']
+ if ev['room_id'] not in xmppClients:
+ print "We didn't have a call for that room"
+ continue
+ # should probably check call ID too
+ xmppCli = xmppClients[ev['room_id']]
+ xmppCli.sendAnswer(sdp)
+ elif ev['type'] == 'm.call.hangup':
+ if ev['room_id'] in xmppClients:
+ xmppClients[ev['room_id']].stop()
+ del xmppClients[ev['room_id']]
+
+class TrivialXmppClient:
+ def __init__(self, matrixRoom, userId):
+ self.rid = 0
+ self.matrixRoom = matrixRoom
+ self.userId = userId
+ self.running = True
+
+ def stop(self):
+ self.running = False
+
+ def nextRid(self):
+ self.rid += 1
+ return '%d' % (self.rid)
+
+ def sendIq(self, xml):
+ fullXml = "%s" % (self.nextRid(), self.sid, xml)
+ #print "\t>>>%s" % (fullXml)
+ return self.xmppPoke(fullXml)
+
+ def xmppPoke(self, xml):
+ headers = {'Content-Type': 'application/xml'}
+ req = grequests.post(HTTPBIND, verify=False, headers=headers, data=xml)
+ resps = grequests.map([req])
+ obj = BeautifulSoup(resps[0].content)
+ return obj
+
+ def sendAnswer(self, answer):
+ print "sdp from matrix client",answer
+ p = subprocess.Popen(['node', 'unjingle/unjingle.js', '--sdp'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ jingle, out_err = p.communicate(answer)
+ jingle = jingle % {
+ 'tojid': self.callfrom,
+ 'action': 'session-accept',
+ 'initiator': self.callfrom,
+ 'responder': self.jid,
+ 'sid': self.callsid
+ }
+ print "answer jingle from sdp",jingle
+ res = self.sendIq(jingle)
+ print "reply from answer: ",res
+
+ self.ssrcs = {}
+ jingleSoup = BeautifulSoup(jingle)
+ for cont in jingleSoup.iq.jingle.findAll('content'):
+ if cont.description:
+ self.ssrcs[cont['name']] = cont.description['ssrc']
+ print "my ssrcs:",self.ssrcs
+
+ gevent.joinall([
+ gevent.spawn(self.advertiseSsrcs)
+ ])
+
+ def advertiseSsrcs(self):
+ time.sleep(7)
+ print "SSRC spammer started"
+ while self.running:
+ ssrcMsg = "%(nick)s" % { 'tojid': "%s@%s/%s" % (ROOMNAME, ROOMDOMAIN, self.shortJid), 'nick': self.userId, 'assrc': self.ssrcs['audio'], 'vssrc': self.ssrcs['video'] }
+ res = self.sendIq(ssrcMsg)
+ print "reply from ssrc announce: ",res
+ time.sleep(10)
+
+
+
+ def xmppLoop(self):
+ self.matrixCallId = time.time()
+ res = self.xmppPoke("" % (self.nextRid(), HOST))
+
+ print res
+ self.sid = res.body['sid']
+ print "sid %s" % (self.sid)
+
+ res = self.sendIq("")
+
+ res = self.xmppPoke("