Moved things to JingleRTPContent, start pipeline earlier
Some methods of JingleVoIPContent have been moved to JingleRTPContent, in prevision of a video content class. The pipeline now starts in setupStream, and the stream's direction is changed when the stream is ready.
This commit is contained in:
		
							parent
							
								
									32ad59aa42
								
							
						
					
					
						commit
						af44ee0840
					
				
					 1 changed files with 33 additions and 28 deletions
				
			
		| 
						 | 
					@ -13,7 +13,7 @@
 | 
				
			||||||
''' Handles the jingle signalling protocol. '''
 | 
					''' Handles the jingle signalling protocol. '''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#TODO:
 | 
					#TODO:
 | 
				
			||||||
# * things in XEP 0166, includign:
 | 
					# * things in XEP 0166, including:
 | 
				
			||||||
#   - 'senders' attribute of 'content' element
 | 
					#   - 'senders' attribute of 'content' element
 | 
				
			||||||
#   - security preconditions
 | 
					#   - security preconditions
 | 
				
			||||||
#   * actions:
 | 
					#   * actions:
 | 
				
			||||||
| 
						 | 
					@ -24,13 +24,19 @@
 | 
				
			||||||
#   * sid/content related:
 | 
					#   * sid/content related:
 | 
				
			||||||
#      - tiebreaking
 | 
					#      - tiebreaking
 | 
				
			||||||
#      - if there already is a session, use it
 | 
					#      - if there already is a session, use it
 | 
				
			||||||
 | 
					# * things in XEP 0176, including:
 | 
				
			||||||
 | 
					#      - http://xmpp.org/extensions/xep-0176.html#protocol-restarts
 | 
				
			||||||
 | 
					#      - http://xmpp.org/extensions/xep-0176.html#fallback
 | 
				
			||||||
 | 
					# * XEP 0177 (raw udp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# * UI:
 | 
					# * UI:
 | 
				
			||||||
#   - hang up button!
 | 
					#   - hang up button!
 | 
				
			||||||
#   - make state and codec informations available to the user
 | 
					#   - make state and codec informations available to the user
 | 
				
			||||||
#   * config:
 | 
					#   * config:
 | 
				
			||||||
#     - codecs
 | 
					#     - codecs
 | 
				
			||||||
#     - STUN
 | 
					#     - STUN
 | 
				
			||||||
# * figure out why it doesn't work with pidgin, and why it doesn't work well with psi
 | 
					# * DONE: figure out why it doesn't work with pidgin:
 | 
				
			||||||
 | 
					#     That's a bug in pidgin: http://xmpp.org/extensions/xep-0176.html#protocol-checks
 | 
				
			||||||
# * destroy sessions when user is unavailable, see handle_event_notify?
 | 
					# * destroy sessions when user is unavailable, see handle_event_notify?
 | 
				
			||||||
# * timeout
 | 
					# * timeout
 | 
				
			||||||
# * video
 | 
					# * video
 | 
				
			||||||
| 
						 | 
					@ -460,6 +466,7 @@ class JingleContent(object):
 | 
				
			||||||
		self.negotiated = False		# is this content already negotiated?
 | 
							self.negotiated = False		# is this content already negotiated?
 | 
				
			||||||
		self.candidates = [] # Local transport candidates
 | 
							self.candidates = [] # Local transport candidates
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							self.senders = 'both' #FIXME
 | 
				
			||||||
		self.allow_sending = True # Used for stream direction, attribute 'senders'
 | 
							self.allow_sending = True # Used for stream direction, attribute 'senders'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		self.callbacks =  {
 | 
							self.callbacks =  {
 | 
				
			||||||
| 
						 | 
					@ -581,13 +588,16 @@ class JingleContent(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class JingleRTPContent(JingleContent):
 | 
					class JingleRTPContent(JingleContent):
 | 
				
			||||||
	def __init__(self, session, node=None):
 | 
						def __init__(self, session, media, node=None):
 | 
				
			||||||
		JingleContent.__init__(self, session, node)
 | 
							JingleContent.__init__(self, session, node)
 | 
				
			||||||
 | 
							self.media = media
 | 
				
			||||||
		self.got_codecs = False
 | 
							self.got_codecs = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		self.callbacks['content-accept'] += [self.__getRemoteCodecsCB]
 | 
							self.callbacks['content-accept'] += [self.__getRemoteCodecsCB]
 | 
				
			||||||
		self.callbacks['session-accept'] += [self.__getRemoteCodecsCB]
 | 
							self.callbacks['session-accept'] += [self.__getRemoteCodecsCB]
 | 
				
			||||||
		self.callbacks['session-initiate'] += [self.__getRemoteCodecsCB]
 | 
							self.callbacks['session-initiate'] += [self.__getRemoteCodecsCB]
 | 
				
			||||||
 | 
							self.callbacks['session-terminate'] += [self.__stop]
 | 
				
			||||||
 | 
							self.callbacks['session-terminate-sent'] += [self.__stop]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def setupStream(self):
 | 
						def setupStream(self):
 | 
				
			||||||
		# pipeline and bus
 | 
							# pipeline and bus
 | 
				
			||||||
| 
						 | 
					@ -602,6 +612,10 @@ class JingleRTPContent(JingleContent):
 | 
				
			||||||
		self.pipeline.add(self.conference)
 | 
							self.pipeline.add(self.conference)
 | 
				
			||||||
		self.funnel = None
 | 
							self.funnel = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						def _fillContent(self, content):
 | 
				
			||||||
 | 
							content.addChild(xmpp.NS_JINGLE_RTP+' description', attrs={'media': self.media},
 | 
				
			||||||
 | 
							                 payload=self.iterCodecs())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _on_gst_message(self, bus, message):
 | 
						def _on_gst_message(self, bus, message):
 | 
				
			||||||
		if message.type == gst.MESSAGE_ELEMENT:
 | 
							if message.type == gst.MESSAGE_ELEMENT:
 | 
				
			||||||
			name = message.structure.get_name()
 | 
								name = message.structure.get_name()
 | 
				
			||||||
| 
						 | 
					@ -622,15 +636,18 @@ class JingleRTPContent(JingleContent):
 | 
				
			||||||
			elif name == 'farsight-component-state-changed':
 | 
								elif name == 'farsight-component-state-changed':
 | 
				
			||||||
				state = message.structure['state']
 | 
									state = message.structure['state']
 | 
				
			||||||
				print message.structure['component'], state
 | 
									print message.structure['component'], state
 | 
				
			||||||
				if state==farsight.STREAM_STATE_READY:
 | 
									if state==farsight.STREAM_STATE_CONNECTED:
 | 
				
			||||||
					self.negotiated = True
 | 
										self.negotiated = True
 | 
				
			||||||
					self.pipeline.set_state(gst.STATE_PLAYING)
 | 
										#TODO: farsight.DIRECTION_BOTH only if senders='both'
 | 
				
			||||||
 | 
										self.p2pstream.set_property('direction', farsight.DIRECTION_BOTH)
 | 
				
			||||||
					#if not self.session.weinitiate: #FIXME: one more FIXME...
 | 
										#if not self.session.weinitiate: #FIXME: one more FIXME...
 | 
				
			||||||
					#	self.session.sendContentAccept(self.__content((xmpp.Node('description', payload=self.iterCodecs()),)))
 | 
										#	self.session.sendContentAccept(self.__content((xmpp.Node('description', payload=self.iterCodecs()),)))
 | 
				
			||||||
			elif name == 'farsight-error':
 | 
								elif name == 'farsight-error':
 | 
				
			||||||
				print 'Farsight error #%d!' % message.structure['error-no']
 | 
									print 'Farsight error #%d!' % message.structure['error-no']
 | 
				
			||||||
				print 'Message: %s' % message.structure['error-msg']
 | 
									print 'Message: %s' % message.structure['error-msg']
 | 
				
			||||||
				print 'Debug: %s' % message.structure['debug-msg']
 | 
									print 'Debug: %s' % message.structure['debug-msg']
 | 
				
			||||||
 | 
								else:
 | 
				
			||||||
 | 
									print name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def __getRemoteCodecsCB(self, stanza, content, error, action):
 | 
						def __getRemoteCodecsCB(self, stanza, content, error, action):
 | 
				
			||||||
		''' Get peer codecs from what we get from peer. '''
 | 
							''' Get peer codecs from what we get from peer. '''
 | 
				
			||||||
| 
						 | 
					@ -666,24 +683,23 @@ class JingleRTPContent(JingleContent):
 | 
				
			||||||
			else:	p = ()
 | 
								else:	p = ()
 | 
				
			||||||
			yield xmpp.Node('payload-type', a, p)
 | 
								yield xmpp.Node('payload-type', a, p)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						def __stop(self, *things):
 | 
				
			||||||
 | 
							self.pipeline.set_state(gst.STATE_NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						def __del__(self):
 | 
				
			||||||
 | 
							self.__stop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class JingleVoIP(JingleRTPContent):
 | 
					class JingleVoIP(JingleRTPContent):
 | 
				
			||||||
	''' Jingle VoIP sessions consist of audio content transported
 | 
						''' Jingle VoIP sessions consist of audio content transported
 | 
				
			||||||
	over an ICE UDP protocol. '''
 | 
						over an ICE UDP protocol. '''
 | 
				
			||||||
	def __init__(self, session, node=None):
 | 
						def __init__(self, session, node=None):
 | 
				
			||||||
		JingleRTPContent.__init__(self, session, node)
 | 
							JingleRTPContent.__init__(self, session, 'audio', node)
 | 
				
			||||||
		self.got_codecs = False
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		self.callbacks['session-accept'] += [self.__startMic]
 | 
							self.got_codecs = False
 | 
				
			||||||
		self.callbacks['session-terminate'] += [self.__stop]
 | 
					 | 
				
			||||||
		self.callbacks['session-accept-sent'] += [self.__startMic]
 | 
					 | 
				
			||||||
		self.callbacks['session-terminate-sent'] += [self.__stop]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		self.setupStream()
 | 
							self.setupStream()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _fillContent(self, content):
 | 
					 | 
				
			||||||
		content.addChild(xmpp.NS_JINGLE_RTP+' description', attrs={'media': 'audio'},
 | 
					 | 
				
			||||||
		                 payload=self.iterCodecs())
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	''' Things to control the gstreamer's pipeline '''
 | 
						''' Things to control the gstreamer's pipeline '''
 | 
				
			||||||
	def setupStream(self):
 | 
						def setupStream(self):
 | 
				
			||||||
| 
						 | 
					@ -705,8 +721,7 @@ class JingleVoIP(JingleRTPContent):
 | 
				
			||||||
		                         farsight.MEDIA_TYPE_AUDIO, 16000)]
 | 
							                         farsight.MEDIA_TYPE_AUDIO, 16000)]
 | 
				
			||||||
		self.p2psession.set_codec_preferences(codecs)
 | 
							self.p2psession.set_codec_preferences(codecs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		#TODO: farsight.DIRECTION_BOTH only if senders='both'
 | 
							self.p2pstream = self.p2psession.new_stream(participant, farsight.DIRECTION_NONE,
 | 
				
			||||||
		self.p2pstream = self.p2psession.new_stream(participant, farsight.DIRECTION_BOTH,
 | 
					 | 
				
			||||||
		                                            'nice', params)
 | 
							                                            'nice', params)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# the local parts
 | 
							# the local parts
 | 
				
			||||||
| 
						 | 
					@ -724,7 +739,7 @@ class JingleVoIP(JingleRTPContent):
 | 
				
			||||||
		self.pipeline.add(self.src_mic)
 | 
							self.pipeline.add(self.src_mic)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		self.mic_volume = gst.element_factory_make('volume')
 | 
							self.mic_volume = gst.element_factory_make('volume')
 | 
				
			||||||
		self.mic_volume.set_property('volume', 0)
 | 
							self.mic_volume.set_property('volume', 1)
 | 
				
			||||||
		self.pipeline.add(self.mic_volume)
 | 
							self.pipeline.add(self.mic_volume)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# link gst elements
 | 
							# link gst elements
 | 
				
			||||||
| 
						 | 
					@ -743,17 +758,7 @@ class JingleVoIP(JingleRTPContent):
 | 
				
			||||||
		self.p2pstream.connect('src-pad-added', src_pad_added)
 | 
							self.p2pstream.connect('src-pad-added', src_pad_added)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# The following is needed for farsight to process ICE requests:
 | 
							# The following is needed for farsight to process ICE requests:
 | 
				
			||||||
		self.conference.set_state(gst.STATE_PLAYING)
 | 
							self.pipeline.set_state(gst.STATE_PLAYING)
 | 
				
			||||||
 | 
					 | 
				
			||||||
	def __startMic(self, *things):
 | 
					 | 
				
			||||||
		self.mic_volume.set_property('volume', 1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def __stop(self, *things):
 | 
					 | 
				
			||||||
		self.conference.set_state(gst.STATE_NULL)
 | 
					 | 
				
			||||||
		self.pipeline.set_state(gst.STATE_NULL)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def __del__(self):
 | 
					 | 
				
			||||||
		self.__stop()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ConnectionJingle(object):
 | 
					class ConnectionJingle(object):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue