Changeset 8498 for branches/jingle/src
- Timestamp:
- 08/15/07 11:47:29 (17 months ago)
- Files:
-
- 1 modified
-
branches/jingle/src/common/jingle.py (modified) (13 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/jingle/src/common/jingle.py
r8493 r8498 62 62 # to send error instead of ack 63 63 self.callbacks={ 64 'content-accept': [self.__contentAcceptCB, self.__ defaultCB],64 'content-accept': [self.__contentAcceptCB, self.__broadcastCB, self.__defaultCB], 65 65 'content-add': [self.__defaultCB], 66 66 'content-modify': [self.__defaultCB], 67 67 'content-remove': [self.__defaultCB], 68 'session-accept': [self.__contentAcceptCB, self.__ defaultCB],68 'session-accept': [self.__contentAcceptCB, self.__broadcastCB, self.__defaultCB], 69 69 'session-info': [self.__defaultCB], 70 'session-initiate': [self.__sessionInitiateCB, self.__ defaultCB],70 'session-initiate': [self.__sessionInitiateCB, self.__broadcastCB, self.__defaultCB], 71 71 'session-terminate': [self.__defaultCB], 72 'transport-info': [self.__ defaultCB],72 'transport-info': [self.__broadcastCB, self.__defaultCB], 73 73 'iq-result': [], 74 74 'iq-error': [], … … 76 76 77 77 # for making streams using farsight 78 import gc 79 gc.disable() 80 print self.weinitiate, "#farsight_session_factory_make" 78 81 self.p2psession = farsight.farsight_session_factory_make('rtp') 79 82 self.p2psession.connect('error', self.on_p2psession_error) … … 124 127 if error: 125 128 # it's an iq-error stanza 126 callables= 'iq-error'129 action = 'iq-error' 127 130 elif jingle: 128 131 # it's a jingle action 129 132 action = jingle.getAttr('action') 130 callables = action131 133 else: 132 134 # it's an iq-result (ack) stanza 133 callables= 'iq-result'134 135 callables = self.callbacks[ callables]135 action = 'iq-result' 136 137 callables = self.callbacks[action] 136 138 137 139 try: 138 140 for callable in callables: 139 callable(stanza=stanza, jingle=jingle, error=error )141 callable(stanza=stanza, jingle=jingle, error=error, action=action) 140 142 except xmpp.NodeProcessed: 141 143 pass 142 144 143 def __defaultCB(self, stanza, jingle, error ):145 def __defaultCB(self, stanza, jingle, error, action): 144 146 ''' Default callback for action stanzas -- simple ack 145 147 and stop processing. ''' … … 147 149 self.connection.connection.send(response) 148 150 149 def __contentAcceptCB(self, stanza, jingle, error ):151 def __contentAcceptCB(self, stanza, jingle, error, action): 150 152 ''' Called when we get content-accept stanza or equivalent one 151 153 (like session-accept).''' 152 # check which contents are accepted , call their callbacks154 # check which contents are accepted 153 155 for content in jingle.iterTags('content'): 154 156 creator = content['creator'] 155 157 name = content['name'] 156 157 158 def __sessionInitiateCB(self, stanza, jingle, error): 158 159 def __sessionInitiateCB(self, stanza, jingle, error, action): 159 160 ''' We got a jingle session request from other entity, 160 161 therefore we are the receiver... Unpack the data. ''' … … 170 171 if desc_ns==xmpp.NS_JINGLE_AUDIO and tran_ns==xmpp.NS_JINGLE_ICE_UDP: 171 172 # we've got voip content 172 self.addContent(element['name'], JingleVoiP(self , node=element), 'peer')173 self.addContent(element['name'], JingleVoiP(self), 'peer') 173 174 fail = False 174 175 … … 182 183 self.state = JingleStates.pending 183 184 185 def __broadcastCB(self, stanza, jingle, error, action): 186 ''' Broadcast the stanza contents to proper content handlers. ''' 187 for content in jingle.iterTags('content'): 188 name = content['name'] 189 creator = content['creator'] 190 cn = self.contents[(creator, name)] 191 cn.stanzaCB(stanza, content, error, action) 192 184 193 def on_p2psession_error(self, *anything): 185 print "Farsight session error!"194 print self.weinitiate, "Farsight session error!" 186 195 187 196 ''' Methods that make/send proper pieces of XML. They check if the session … … 281 290 282 291 def toXML(self): 283 return xmpp.Node('payload ',292 return xmpp.Node('payload-type', 284 293 attrs=self.attrs, 285 294 payload=(xmpp.Node('parameter', {'name': k, 'value': v}) for k,v in self.params)) 286 295 287 296 class JingleAudioSession(object): 288 __metaclass__=meta.VerboseClassType297 # __metaclass__=meta.VerboseClassType 289 298 def __init__(self, content, fromNode): 290 299 self.content = content … … 354 363 return self.__codecsList(self.responder_codecs) 355 364 356 class JingleICEUDPSession(object):357 __metaclass__=meta.VerboseClassType358 def __init__(self, content):359 self.content = content360 361 def _sessionInitiateCB(self):362 ''' Called when we initiate the session. '''363 pass364 365 def toXML(self):366 ''' ICE-UDP doesn't send much in its transport stanza... '''367 return xmpp.Node(xmpp.NS_JINGLE_ICE_UDP+' transport')368 369 365 class JingleContent(object): 370 366 ''' An abstraction of content in Jingle sessions. ''' … … 380 376 ''' Jingle VoiP sessions consist of audio content transported 381 377 over an ICE UDP protocol. ''' 382 __metaclass__=meta.VerboseClassType378 # __metaclass__=meta.VerboseClassType 383 379 def __init__(self, session, node=None): 384 380 JingleContent.__init__(self, session, node) 385 self. codecs = None381 self.got_codecs = False 386 382 387 383 #if node is None: … … 392 388 self.setupStream() 393 389 390 def stanzaCB(self, stanza, content, error, action): 391 ''' Called when something related to our content was sent by peer. ''' 392 callbacks = { 393 'content-accept': [self.__getRemoteCodecsCB], 394 'content-add': [], 395 'content-modify': [], 396 'content-remove': [], 397 'session-accept': [self.__getRemoteCodecsCB], 398 'session-info': [], 399 'session-initiate': [self.__getRemoteCodecsCB], 400 'session-terminate': [], 401 'transport-info': [self.__transportInfoCB], 402 'iq-result': [], 403 'iq-error': [], 404 }[action] 405 for callback in callbacks: 406 callback(stanza, content, error, action) 407 408 def __getRemoteCodecsCB(self, stanza, content, error, action): 409 if self.got_codecs: return 410 411 codecs = [] 412 for codec in content.getTag('description').iterTags('payload-type'): 413 c = {'id': int(codec['id']), 414 'encoding_name': codec['name'], 415 'media_type': farsight.MEDIA_TYPE_AUDIO, 416 'channels': 1, 417 'params': dict((p['name'], p['value']) for p in codec.iterTags('parameter'))} 418 if 'channels' in codec: c['channels']=codec['channels'] 419 codecs.append(c) 420 if len(codecs)==0: return 421 422 print self.session.weinitiate, "#farsight_stream_set_remote_codecs" 423 self.p2pstream.set_remote_codecs(codecs) 424 self.got_codecs=True 425 426 def __transportInfoCB(self, stanza, content, error, action): 427 ''' Got a new transport candidate. ''' 428 candidates = [] 429 for candidate in content.getTag('transport').iterTags('candidate'): 430 cand={ 431 # 'candidate_id': str(self.session.connection.connection.getAnID()), 432 'candidate_id': candidate['cid'], 433 'component': int(candidate['component']), 434 'ip': candidate['ip'], 435 'port': int(candidate['port']), 436 'proto': candidate['protocol']=='udp' and farsight.NETWORK_PROTOCOL_UDP \ 437 or farsight.NETWORK_PROTOCOL_TCP, 438 'proto_subtype':'RTP', 439 'proto_profile':'AVP', 440 'preference': float(candidate['priority'])/100000, 441 # 'type': farsight.CANDIDATE_TYPE_LOCAL, 442 'type': int(candidate['type']), 443 } 444 if 'ufrag' in candidate: cand['username']=candidate['ufrag'] 445 if 'pwd' in candidate: cand['password']=candidate['pwd'] 446 447 candidates.append(cand) 448 print self.session.weinitiate, "#add_remote_candidate" 449 self.p2pstream.add_remote_candidate(candidates) 450 394 451 def toXML(self): 395 452 ''' Return proper XML for <content/> element. ''' … … 397 454 attrs={'name': self.name, 'creator': self.creator, 'profile': 'RTP/AVP'}, 398 455 payload=[ 399 xmpp.Node(xmpp.NS_JINGLE_AUDIO+' description', payload=self. getCodecs()),456 xmpp.Node(xmpp.NS_JINGLE_AUDIO+' description', payload=self.iterCodecs()), 400 457 xmpp.Node(xmpp.NS_JINGLE_ICE_UDP+' transport') 401 458 ]) … … 408 465 409 466 def setupStream(self): 467 print self.session.weinitiate, "#farsight_session_create_stream" 410 468 self.p2pstream = self.session.p2psession.create_stream( 411 469 farsight.MEDIA_TYPE_AUDIO, farsight.STREAM_DIRECTION_BOTH) … … 417 475 self.p2pstream.connect('state-changed', self.on_p2pstream_state_changed) 418 476 self.p2pstream.connect('new-native-candidate', self.on_p2pstream_new_native_candidate) 477 478 self.p2pstream.set_remote_codecs(self.p2pstream.get_local_codecs()) 479 480 print self.session.weinitiate, "#farsight_stream_prepare_transports" 419 481 self.p2pstream.prepare_transports() 420 482 483 print self.session.weinitiate, "#farsight_stream_set_active_codec" 484 self.p2pstream.set_active_codec(8) #??? 485 486 sink = gst.element_factory_make('alsasink') 487 sink.set_property('sync', False) 488 sink.set_property('latency-time', 20000) 489 sink.set_property('buffer-time', 80000) 490 491 src = gst.element_factory_make('audiotestsrc') 492 src.set_property('blocksize', 320) 493 #src.set_property('latency-time', 20000) 494 src.set_property('is-live', True) 495 496 print self.session.weinitiate, "#farsight_stream_set_sink" 497 self.p2pstream.set_sink(sink) 498 print self.session.weinitiate, "#farsight_stream_set_source" 499 self.p2pstream.set_source(src) 500 421 501 def on_p2pstream_error(self, *whatever): pass 422 def on_p2pstream_new_active_candidate_pair(self, *whatever): pass 423 def on_p2pstream_codec_changed(self, *whatever): pass 424 def on_p2pstream_native_candidates_prepared(self, *whatever): pass 425 def on_p2pstream_state_changed(self, *whatever): pass 502 def on_p2pstream_new_active_candidate_pair(self, stream, native, remote): 503 print self.session.weinitiate, "##new_active_candidate_pair" 504 #print "New native candidate pair: %s, %s" % (native, remote) 505 def on_p2pstream_codec_changed(self, stream, codecid): 506 print self.session.weinitiate, "##codec_changed" 507 #print "Codec changed: %d" % codecid 508 def on_p2pstream_native_candidates_prepared(self, *whatever): 509 print self.session.weinitiate, "##native_candidates_prepared" 510 #print "Native candidates prepared: %r" % whatever 511 for candidate in self.p2pstream.get_native_candidate_list(): 512 self.send_candidate(candidate) 513 def on_p2pstream_state_changed(self, stream, state, dir): 514 print self.session.weinitiate, "##state_changed" 515 #print "State: %d, Dir: %d" % (state, dir) 516 if state==farsight.STREAM_STATE_CONNECTED: 517 print self.session.weinitiate, "#farsight_stream_signal_native_candidates_prepared" 518 stream.signal_native_candidates_prepared() 519 print self.session.weinitiate, "#farsight_stream_start" 520 stream.start() 426 521 def on_p2pstream_new_native_candidate(self, p2pstream, candidate_id): 522 print self.session.weinitiate, "##new_native_candidate" 523 print self.session.weinitiate, "#get_native_candidate" 427 524 candidates = p2pstream.get_native_candidate(candidate_id) 525 print self.session.weinitiate, "#!", repr(candidates) 428 526 429 527 for candidate in candidates: 430 attrs={ 431 'component': candidate['component'], 432 'foundation': '1', # hack 433 'generation': '0', 434 'ip': candidate['ip'], 435 'network': '0', 436 'port': candidate['port'], 437 'priority': int(100000*candidate['preference']), # hack 438 'protocol': candidate['proto']==farsight.NETWORK_PROTOCOL_UDP and 'udp' or 'tcp', 439 } 440 if 'username' in candidate: attrs['ufrag']=candidate['username'] 441 if 'password' in candidate: attrs['pwd']=candidate['password'] 442 c=self.__content() 443 t=c.addChild(xmpp.NS_JINGLE_ICE_UDP+' transport') 444 t.addChild('candidate', attrs=attrs) 445 self.session.sendTransportInfo(c) 446 447 def getCodecs(self): 528 self.send_candidate(candidate) 529 def send_candidate(self, candidate): 530 attrs={ 531 'cid': candidate['candidate_id'], 532 'component': candidate['component'], 533 'foundation': '1', # hack 534 'generation': '0', 535 'type': candidate['type'], 536 'ip': candidate['ip'], 537 'network': '0', 538 'port': candidate['port'], 539 'priority': int(100000*candidate['preference']), # hack 540 'protocol': candidate['proto']==farsight.NETWORK_PROTOCOL_UDP and 'udp' or 'tcp', 541 } 542 if 'username' in candidate: attrs['ufrag']=candidate['username'] 543 if 'password' in candidate: attrs['pwd']=candidate['password'] 544 c=self.__content() 545 t=c.addChild(xmpp.NS_JINGLE_ICE_UDP+' transport') 546 t.addChild('candidate', attrs=attrs) 547 self.session.sendTransportInfo(c) 548 549 def iterCodecs(self): 550 print self.session.weinitiate, "#farsight_stream_get_local_codecs" 448 551 codecs=self.p2pstream.get_local_codecs() 449 return (xmpp.Node('payload', attrs=a) for a in codecs) 552 for codec in codecs: 553 a = {'name': codec['encoding_name'], 554 'id': codec['id'], 555 'channels': 1} 556 if 'clock_rate' in codec: a['clockrate']=codec['clock_rate'] 557 if 'optional_params' in codec: 558 p = (xmpp.Node('parameter', {'name': name, 'value': value}) 559 for name, value in codec['optional_params'].iteritems()) 560 else: p = () 561 yield xmpp.Node('payload-type', a, p) 450 562 451 563 class ConnectionJingle(object):
