[Telepathy-commits] [mingle/master] Add a JingleConference abstraction so multiple jingle sessions can share one fs2.Conference
Sjoerd Simons
sjoerd at luon.net
Mon Nov 3 08:23:32 PST 2008
---
jingle.py | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 118 insertions(+), 21 deletions(-)
diff --git a/jingle.py b/jingle.py
index 8513258..bdfdb85 100644
--- a/jingle.py
+++ b/jingle.py
@@ -5,10 +5,8 @@ import sys
import fs2
import farsight
-from twisted.internet import defer, reactor
+from twisted.internet import defer
from twisted.words.protocols.jabber.client import IQ
-from twisted.words.xish import domish
-from util import elem_find_child, elem_find_children
from twisted.words.xish import domish, xpath
from twisted.words.protocols.jabber.jid import JID
@@ -46,13 +44,13 @@ class JingleBaseDescription:
self.add_payloads(description)
def add_payloads(self, parent):
- for c in self.codecs:
- pt = parent.addElement('payload-type')
- pt['id'] = str(c.id)
- pt['name'] = c.encoding_name
- pt['rate'] = str(c.clock_rate)
- if c.channels > 0:
- pt['channels'] = str(c.channels)
+ for c in self.codecs:
+ pt = parent.addElement('payload-type')
+ pt['id'] = str(c.id)
+ pt['name'] = c.encoding_name
+ pt['rate'] = str(c.clock_rate)
+ if c.channels > 0:
+ pt['channels'] = str(c.channels)
def initiate(self, stream):
self.fsstream = stream
@@ -451,7 +449,8 @@ class JingleContent:
# FIXME handle the case where we can't find a description or transport
# class
- self.fssession = self.session.fsconference.create_session(self.type)
+ self.fssession = self.session.conference.get_session(
+ self.name, self.type)
stream = self.transport.got_initiate(self.fssession,
participant, content)
@@ -494,7 +493,9 @@ class JingleContent:
return
# We got transport and descriptions going, now fire the session
- self.fssession = self.session.fsconference.create_session(self.type)
+ self.fssession = self.session.conference.get_session(
+ self.name, self.type)
+
dtransport = self.transport.prepare(self.fssession,
self.remote_participant)
ddescription = self.description.prepare(self.fssession)
@@ -517,10 +518,13 @@ class JingleContent:
self.description.initiate(self.transport.fsstream)
class JingleBaseSession:
- def __init__(self, client):
+ def __init__(self, client, conference = None):
self.client = client
self.contents = {}
- self.fsconference = fs2.Conference()
+ if conference == None:
+ conference = JingleConference()
+ self.conference = conference
+
self.remote_jid = None
self.initiating = False
self.initiator = None
@@ -591,17 +595,17 @@ class JingleBaseSession:
iq.send()
- def handle_session_initiate(self, iq):
+ def handle_session_initiate(self, iq, contact):
mtypes = { "audio": farsight.MEDIA_TYPE_AUDIO,
"video": farsight.MEDIA_TYPE_VIDEO }
jingle = xpath.queryForNodes(
'/iq/jingle[@xmlns="%s"]' % self.namespace, iq)[0]
- self.remote_jid = JID(iq['from'])
+
+ self.remote_jid = contact.jid
self.initiator = JID(jingle['initiator'])
self.sid = jingle['sid']
- self.remote_participant = \
- self.fsconference.create_participant(jingle['initiator'])
+ self.remote_participant = self.conference.get_participant(contact)
contents = xpath.queryForNodes(
'/iq/jingle[@xmlns="%s"]/content' % self.namespace, iq)
@@ -673,14 +677,14 @@ class JingleBaseSession:
# Start initiating a new jingle to contact X
self.initiating = True
self.remote_jid = contact.jid
- self.remote_participant = self.fsconference.create_participant(
- self.remote_jid.full())
+ self.remote_participant = self.conference.get_participant(contact)
assert self.contents == {}
video = JingleContent(self, "video", farsight.MEDIA_TYPE_VIDEO)
audio = JingleContent(self, "audio", farsight.MEDIA_TYPE_AUDIO)
self.contents = {video.name: video, audio.name: audio}
+ #self.contents = {audio.name: audio}
deferreds = []
for c in self.contents.copy().itervalues():
@@ -704,6 +708,95 @@ class JingleSession(JingleBaseSession):
JingleBaseSession.__init__(self, client)
self.namespace = ns.JINGLE
+class JingleStream:
+ def __init__(self, fsstream, namespace):
+ self.fsstream = fsstream
+ self.namespace = namespace
+
+class JingleConference(fs2.Conference):
+ def __init__(self):
+ fs2.Conference.__init__(self)
+ self.participants = {}
+ self.sessions = {}
+ self.streams = {}
+ self.stream_deferreds = {}
+
+ def get_participant(self, contact):
+ if not self.participants.has_key(contact):
+ self.participants[contact] = \
+ self.create_participant(contact.jid.full())
+ return self.participants[contact]
+
+ def get_session(self, name, type):
+ if not self.sessions.has_key(name):
+ session = self.create_session(type)
+ self.sessions[name] = session
+ self.streams[session] = {}
+ self.stream_deferreds[session] = {}
+ else:
+ session = self.sessions[name]
+
+ assert type == session.type
+
+ return session
+
+ def create_stream(self, session, participant, namespace):
+ transmitters = {
+ ns.GOOGLE_TRANSPORT_P2P: ("nice", { 'compatibility-mode': 1 }),
+ ns.JINGLE_TRANSPORT_RAW_UDP: ("rawudp", {} )
+ }
+
+ if not namespace in get_available_transports():
+ return None
+
+ if not transmitters.has_key(namespace):
+ return None
+
+ (transmitter, transmitter_params) = transmitters[namespace]
+
+ fsstream = session.add_participant(participant, transmitter,
+ transmitter_params)
+
+ stream = JingleStream(fsstream, namespace)
+ self.streams[session][participant] = stream
+
+ return stream;
+
+ def got_capabilities(self, caps, session, participant):
+ transport_namespaces = [ ns.JINGLE_TRANSPORT_ICE,
+ ns.JINGLE_TMP_TRANSPORT_ICE,
+ ns.GOOGLE_TRANSPORT_P2P,
+ ns.JINGLE_TRANSPORT_RAW_UDP,
+ ns.JINGLE_TMP_TRANSPORT_RAW_UDP
+ ]
+ for tns in transport_namespaces:
+ if tns in caps:
+ stream = self.create_stream(session, participant, tns)
+ if stream != None:
+ d = self.stream_deferreds[session].pop(participant)
+ d.callback(stream.fsstream)
+ break
+
+ def get_stream(self, session, contact, namespace = None):
+
+ participant = self.get_participant(contact)
+
+ if not self.streams[session].has_key(participant):
+ if not self.stream_deferreds[session].has_key(participant):
+ d = defer.Deferred()
+ self.stream_deferreds[session][participant] = d
+ contact.get_capabilities().addCallback(
+ self.got_capabilities, session, participant)
+ return d
+ else:
+
+ return self.stream_deferreds[session][participant]
+ else:
+ stream = self.streams[session][participant]
+ if namespace != None:
+ assert namespace == stream.namespace
+ return defer.succeed(stream.fsstream)
+
def get_session_for_ns(client, namespace):
ns2type = { ns.OLD_JINGLE: JingleOldSession,
@@ -736,7 +829,11 @@ def jingle_iq_received(client, iq):
return None
session = get_session_for_ns(client, jingle.uri)
- return session.handle_session_initiate(iq)
+ contact = client.get_contact(JID(iq['from']))
+ if contact != None:
+ print "Ignoring call from unknown contact"
+
+ return session.handle_session_initiate(iq, contact)
def enable_incoming_calls(client):
--
1.5.6.5
More information about the Telepathy-commits
mailing list