Changeset 8461

Show
Ignore:
Timestamp:
08/07/07 01:19:57 (17 months ago)
Author:
liori
Message:

Jingle: UI entry point and lots of small changes.

Location:
branches/jingle
Files:
1 added
5 modified

Legend:

Unmodified
Added
Removed
  • branches/jingle/data/glade/chat_control_popup_menu.glade

    r8314 r8461  
    6767 
    6868  <child> 
     69    <widget class="GtkMenuItem" id="start_voip_menuitem"> 
     70      <property name="visible">True</property> 
     71      <property name="label" translatable="yes">Start _Voice chat</property> 
     72      <property name="use_underline">True</property> 
     73      <signal name="activate" handler="_on_start_voip_menuitem_activate" last_modification_time="Tue, 03 Jan 2006 04:26:46 GMT"/> 
     74    </widget> 
     75  </child> 
     76 
     77  <child> 
    6978    <widget class="GtkImageMenuItem" id="add_to_roster_menuitem"> 
    7079      <property name="visible">True</property> 
  • branches/jingle/src/chat_control.py

    r8454 r8461  
    11921192                        widget.get_active()) 
    11931193 
     1194        def _on_start_voip_menuitem_activate(self, *things): 
     1195                print 'Start VoiP' 
     1196                gajim.connections[self.account].startVoiP(self.contact.jid) 
     1197 
    11941198        def _update_gpg(self): 
    11951199                tb = self.xml.get_widget('gpg_togglebutton') 
     
    15341538                history_menuitem = xml.get_widget('history_menuitem') 
    15351539                toggle_gpg_menuitem = xml.get_widget('toggle_gpg_menuitem') 
     1540                start_voip_menuitem = xml.get_widget('start_voip_menuitem') 
    15361541                add_to_roster_menuitem = xml.get_widget('add_to_roster_menuitem') 
    15371542                send_file_menuitem = xml.get_widget('send_file_menuitem') 
     
    15841589                        self._on_toggle_gpg_menuitem_activate) 
    15851590                self.handlers[id] = toggle_gpg_menuitem  
     1591                id = start_voip_menuitem.connect('activate', 
     1592                        self._on_start_voip_menuitem_activate) 
     1593                self.handlers[id] = start_voip_menuitem 
    15861594                id = information_menuitem.connect('activate',  
    15871595                        self._on_contact_information_menuitem_activate) 
  • branches/jingle/src/common/connection_handlers.py

    r8453 r8461  
    3939from common.pubsub import ConnectionPubSub 
    4040from common.caps import ConnectionCaps 
     41from common.jingle import ConnectionJingle 
    4142 
    4243STATUS_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd', 
     
    11751176                        self.dispatch('VCARD', vcard) 
    11761177 
    1177 class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, ConnectionCommands, ConnectionPubSub, ConnectionCaps): 
     1178class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, ConnectionCommands, ConnectionPubSub, ConnectionCaps, ConnectionJingle): 
    11781179        def __init__(self): 
    11791180                ConnectionVcard.__init__(self) 
     
    11811182                ConnectionCommands.__init__(self) 
    11821183                ConnectionPubSub.__init__(self) 
     1184                ConnectionJingle.__init__(self) 
    11831185                self.gmail_url=None 
    11841186                # List of IDs we are waiting answers for {id: (type_of_request, data), } 
     
    21002102                        common.xmpp.NS_SEARCH) 
    21012103                con.RegisterHandler('iq', self._PubSubCB, 'result') 
     2104                con.RegisterHandler('iq', self._JingleCB, 'result') 
     2105                con.RegisterHandler('iq', self._JingleCB, 'error') 
     2106                con.RegisterHandler('iq', self._JingleCB, 'set', 
     2107                        common.xmpp.NS_JINGLE) 
    21022108                con.RegisterHandler('iq', self._ErrorCB, 'error') 
    21032109                con.RegisterHandler('iq', self._IqCB) 
  • branches/jingle/src/common/jingle.py

    r8456 r8461  
    1313''' Handles the jingle signalling protocol. ''' 
    1414 
     15import gajim 
    1516import xmpp 
     17 
     18import meta 
    1619 
    1720class JingleStates(object): 
     
    2124        active=2 
    2225 
    23 class WrongState(exception): pass 
    24 class NoCommonCodec(exception): pass 
     26class Exception(object): pass 
     27class WrongState(Exception): pass 
     28class NoCommonCodec(Exception): pass 
    2529 
    2630class JingleSession(object): 
    2731        ''' This represents one jingle session. ''' 
     32        __metaclass__=meta.VerboseClassType 
    2833        def __init__(self, con, weinitiate, jid): 
    2934                ''' con -- connection object, 
     
    3338                self.connection=con     # connection to use 
    3439                # our full jid 
    35                 self.ourjid=gajim.get_full_jid_from_account(self.connection.name) 
    36                 self.jid=jid            # jid we connect to 
     40                self.ourjid=gajim.get_jid_from_account(self.connection.name)+'/'+con.server_resource 
     41                self.peerjid=jid        # jid we connect to 
    3742                # jid we use as the initiator 
    38                 self.initiator=weinitiate and self.ourjid or self.jid 
     43                self.initiator=weinitiate and self.ourjid or self.peerjid 
    3944                # jid we use as the responder 
    40                 self.responder=weinitiate and self.jid or self.ourjid 
     45                self.responder=weinitiate and self.peerjid or self.ourjid 
    4146                # are we an initiator? 
    4247                self.weinitiate=weinitiate 
    4348                # what state is session in? (one from JingleStates) 
    4449                self.state=JingleStates.ended 
    45                 self.sid=con.getAnID()  # sessionid 
     50                self.sid=con.connection.getAnID()       # sessionid 
    4651 
    4752                # callbacks to call on proper contents 
    4853                # use .prepend() to add new callbacks 
    4954                self.callbacks=dict((key, [self.__defaultCB]) for key in 
    50                         ('content-accept', 'content-add', 'content-modify', 
     55                        ('content-add', 'content-modify', 
    5156                         'content-remove', 'session-accept', 'session-info', 
    5257                         'session-initiate', 'session-terminate', 
     
    5560                self.callbacks['iq-error']=[] 
    5661 
     62                self.callbacks['content-accept']=[self.__contentAcceptCB, self.__defaultCB] 
     63 
    5764        ''' Middle-level functions to manage contents. Handle local content 
    5865        cache and send change notifications. ''' 
    59         def addContent(self, name, description, transport, profile=None): 
     66        def addContent(self, name, content, initiator='we'): 
    6067                ''' Add new content to session. If the session is active, 
    6168                this will send proper stanza to update session.  
    62                 The protocol prohibits changing that when pending.''' 
     69                The protocol prohibits changing that when pending. 
     70                Initiator must be one of ('we', 'peer', 'initiator', 'responder')''' 
    6371                if self.state==JingleStates.pending: 
    6472                        raise WrongState 
    6573 
    66                 content={'creator': 'initiator', 
    67                         'name': name, 
    68                         'description': description, 
    69                         'transport': transport} 
    70                 if profile is not None: 
    71                         content['profile']=profile 
    72                 self.contents[('initiator', name)]=content 
     74                if (initiator=='we' and self.weinitiate) or (initiator=='peer' and not self.weinitiate): 
     75                        initiator='initiator' 
     76                elif (initiator=='peer' and self.weinitiate) or (initiator=='we' and not self.weinitiate): 
     77                        initiator='responder' 
     78                content.creator = initiator 
     79                content.name = name 
     80                self.contents[(initiator,name)]=content 
    7381 
    7482                if self.state==JingleStates.active: 
    7583                        pass # TODO: send proper stanza, shouldn't be needed now 
     84 
     85        def removeContent(self, creator, name): 
     86                ''' We do not need this now ''' 
     87                pass 
     88 
     89        def modifyContent(self, creator, name, *someother): 
     90                ''' We do not need this now ''' 
     91                pass 
    7692 
    7793        ''' Middle-level function to do stanza exchange. ''' 
     
    93109                        # it's an iq-error stanza 
    94110                        callables = 'iq-error' 
    95                 else if jingle: 
     111                elif jingle: 
    96112                        # it's a jingle action 
    97113                        action = jingle.getAttr('action') 
     
    116132                raise xmpp.NodeProcessed 
    117133 
     134        def __contentAcceptCB(self, stanza, jingle, error): 
     135                ''' Called when we get content-accept stanza or equivalent one 
     136                (like session-accept).''' 
     137                # check which contents are accepted, call their callbacks 
     138                for content in jingle.iterTags('content'): 
     139                        creator = content['creator'] 
     140                        name = content['name'] 
     141                         
     142 
    118143        ''' Methods that make/send proper pieces of XML. They check if the session 
    119144        is in appropriate state. ''' 
    120         def makeJingle(self, action): 
     145        def __makeJingle(self, action): 
    121146                stanza = xmpp.Iq(typ='set', to=xmpp.JID(self.jid)) 
    122                 jingle = stanza.addChild('jingle', attrs= 
     147                jingle = stanza.addChild('jingle', attrs={ 
    123148                        'xmlns': 'http://www.xmpp.org/extensions/xep-0166.html#ns', 
    124149                        'action': action, 
     
    128153                return stanza, jingle 
    129154 
    130         def appendContent(self, jingle, content, full=True): 
     155        def __appendContent(self, jingle, content, full=True): 
    131156                ''' Append <content/> element to <jingle/> element, 
    132157                with (full=True) or without (full=False) <content/> 
    133158                children. ''' 
    134                 c=jingle.addChild('content', attrs={ 
    135                         'creator': content['creator'], 
    136                         'name': content['name']}) 
    137                 if 'profile' in content: 
    138                         c['profile']=content['profile'] 
    139159                if full: 
    140                         c.addChild(node=content['description']) 
    141                         c.addChild(node=content['transport']) 
     160                        jingle.addChild(node=content.toXML()) 
     161                else: 
     162                        jingle.addChild('content', 
     163                                attrs={'name': content.name, 'creator': content.creator}) 
    142164                return c 
    143165 
    144         def appendContents(self, jingle, full=True): 
     166        def __appendContents(self, jingle, full=True): 
    145167                ''' Append all <content/> elements to <jingle/>.''' 
    146168                # TODO: integrate with __appendContent? 
     
    151173        def __sessionInitiate(self): 
    152174                assert self.state==JingleStates.ended 
     175                stanza, jingle = self.__makeJingle('session-initiate') 
     176                self.__appendContents(jingle) 
     177                self.connection.send(jingle) 
    153178 
    154179        def __sessionAccept(self): 
     
    198223                for element in jingle.iterTags('content'): 
    199224                        content={'creator': 'initiator', 
    200                                 'name': element['name'] 
     225                                'name': element['name'], 
    201226                                'description': element.getTag('description'), 
    202227                                'transport': element.getTag('transport')} 
     
    208233 
    209234class JingleAudioSession(object): 
     235        __metaclass__=meta.VerboseClassType 
    210236        class Codec(object): 
    211237                ''' This class keeps description of a single codec. ''' 
     
    233259                                payload=(xmpp.Node('parameter', {'name': k, 'value': v}) for k,v in self.params)) 
    234260 
    235         def __init__(self, con, weinitiate, jid): 
    236                 JingleSession.__init__(self, con, weinitiate, jid) 
    237                 if weinitiate: 
    238                         pass #add voice content 
    239                 self.callbacks['session-initiate'].prepend( 
     261        def __init__(self, content): 
     262                self.content = content 
    240263 
    241264                self.initiator_codecs=[] 
    242265                self.responder_codecs=[] 
     266 
     267        def sessionInitiateCB(self, stanza, ourcontent): 
     268                pass 
    243269 
    244270        ''' "Negotiation" of codecs... simply presenting what *we* can do, nothing more... ''' 
     
    283309                        payload=(codec.toXML() for codec in codecs)) 
    284310 
     311        def toXML(self): 
     312                if not self.initiator_codecs: 
     313                        # we are the initiator, so just send our codecs 
     314                        self.initiator_codecs = self.getOurCodecs() 
     315                        return self.__codecsList(self.initiator_codecs) 
     316                else: 
     317                        # we are the responder, we SHOULD adjust our codec list 
     318                        self.responder_codecs = self.getOurCodecs(self.initiator_codecs) 
     319                        return self.__codecsList(self.responder_codecs) 
     320 
    285321class JingleICEUDPSession(object): 
    286         def __init__(self, con, weinitiate, jid): 
     322        __metaclass__=meta.VerboseClassType 
     323        def __init__(self, content): 
     324                self.content = content 
     325 
     326        def _sessionInitiateCB(self): 
     327                ''' Called when we initiate the session. ''' 
    287328                pass 
    288329 
    289 class JingleVoiP(JingleSession): 
     330        def toXML(self): 
     331                ''' ICE-UDP doesn't send much in its transport stanza... ''' 
     332                return xmpp.Node('transport', xmlns=xmpp.JINGLE_ICE_UDP) 
     333 
     334class JingleVoiP(object): 
    290335        ''' Jingle VoiP sessions consist of audio content transported 
    291336        over an ICE UDP protocol. ''' 
    292         def __init__(*data): 
    293                 JingleAudioSession.__init__(*data) 
    294                 JingleICEUDPSession.__init__(*data) 
     337        __metaclass__=meta.VerboseClassType 
     338        def __init__(self): 
     339                self.audio = JingleAudioSession(self) 
     340                self.transport = JingleICEUDPSession(self) 
     341 
     342        def toXML(self): 
     343                ''' Return proper XML for <content/> element. ''' 
     344                return xmpp.Node('content', 
     345                        attrs={'name': self.name, 'creator': self.creator, 'profile': 'RTP/AVP'}, 
     346                        childs=[self.audio.toXML(), self.transport.toXML()]) 
     347 
     348        def _sessionInitiateCB(self): 
     349                ''' Called when we initiate the session. ''' 
     350                self.transport._sessionInitiateCB() 
    295351 
    296352class ConnectionJingle(object): 
     
    308364                jingle - a JingleSession object. 
    309365                ''' 
    310                 self.__sessions[(jingle.jid, jingle.sid)]=jingle 
     366                self.__sessions[(jingle.peerjid, jingle.sid)]=jingle 
    311367 
    312368        def deleteJingle(self, jingle): 
    313369                ''' Remove a jingle session from a jingle stanza dispatcher ''' 
    314                 del self.__session[(jingle.jid, jingle.sid)] 
    315  
    316         def _jingleCB(self, con, stanza): 
     370                del self.__session[(jingle.peerjid, jingle.sid)] 
     371 
     372        def _JingleCB(self, con, stanza): 
    317373                ''' The jingle stanza dispatcher. 
    318374                Route jingle stanza to proper JingleSession object, 
     
    331387 
    332388                jingle = stanza.getTag('jingle') 
     389                if not jingle: return 
    333390                sid = jingle.getAttr('sid') 
    334391 
     
    342399                return self.__sessions[(jid, sid)].stanzaCB(stanza) 
    343400 
    344         def addJingleIqCallback(jid, id, jingle): 
     401        def addJingleIqCallback(self, jid, id, jingle): 
    345402                self.__iq_responses[(jid, id)]=jingle 
     403 
     404        def startVoiP(self, jid): 
     405                jingle = JingleSession(self, weinitiate=True, jid=jid) 
     406                self.addJingle(jingle) 
     407                jingle.addContent('voice', JingleVoiP()) 
     408                jingle.startSession() 
  • branches/jingle/src/common/xmpp/protocol.py

    r8410 r8461  
    5656NS_INVISIBLE    ='presence-invisible'                                   # Jabberd2 
    5757NS_IQ           ='iq'                                                   # Jabberd2 
     58NS_JINGLE       ='http://www.xmpp.org/extensions/xep-0166.html#ns'      # XEP-0166 
     59NS_JINGLE_AUDIO ='http://www.xmpp.org/extensions/xep-0167.html#ns'      # XEP-0167 
     60NS_JINGLE_RAW_UDP='http://www.xmpp.org/extensions/xep-0177.html#ns'     # XEP-0177 
     61NS_JINGLE_ICE_UDP='http://www.xmpp.org/extensions/xep-0176.html#ns-udp' # XEP-0176 
    5862NS_LAST         ='jabber:iq:last' 
    5963NS_MESSAGE      ='message'                                              # Jabberd2