[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