support for content-{add,reject,accept}, new helpers, and other few things
This commit is contained in:
		
							parent
							
								
									a051d1ec95
								
							
						
					
					
						commit
						77541f3e7f
					
				
					 4 changed files with 196 additions and 81 deletions
				
			
		| 
						 | 
					@ -1579,14 +1579,17 @@ class ChatControl(ChatControlBase, ChatCommands):
 | 
				
			||||||
		elif state == 'connecting':
 | 
							elif state == 'connecting':
 | 
				
			||||||
			self.audio_state = self.JINGLE_STATE_CONNECTING
 | 
								self.audio_state = self.JINGLE_STATE_CONNECTING
 | 
				
			||||||
			self.audio_sid = sid
 | 
								self.audio_sid = sid
 | 
				
			||||||
 | 
								self._audio_button.set_active(True)
 | 
				
			||||||
		elif state == 'connection_received':
 | 
							elif state == 'connection_received':
 | 
				
			||||||
			self.audio_state = self.JINGLE_STATE_CONNECTION_RECEIVED
 | 
								self.audio_state = self.JINGLE_STATE_CONNECTION_RECEIVED
 | 
				
			||||||
			self.audio_sid = sid
 | 
								self.audio_sid = sid
 | 
				
			||||||
 | 
								self._audio_button.set_active(True)
 | 
				
			||||||
		elif state == 'connected':
 | 
							elif state == 'connected':
 | 
				
			||||||
			self.audio_state = self.JINGLE_STATE_CONNECTED
 | 
								self.audio_state = self.JINGLE_STATE_CONNECTED
 | 
				
			||||||
		elif state == 'stop':
 | 
							elif state == 'stop':
 | 
				
			||||||
			self.audio_state = self.JINGLE_STATE_AVAILABLE
 | 
								self.audio_state = self.JINGLE_STATE_AVAILABLE
 | 
				
			||||||
			self.audio_sid = None
 | 
								self.audio_sid = None
 | 
				
			||||||
 | 
								self._audio_button.set_active(False)
 | 
				
			||||||
		elif state == 'error':
 | 
							elif state == 'error':
 | 
				
			||||||
			self.audio_state = self.JINGLE_STATE_ERROR
 | 
								self.audio_state = self.JINGLE_STATE_ERROR
 | 
				
			||||||
		self.update_audio()
 | 
							self.update_audio()
 | 
				
			||||||
| 
						 | 
					@ -1605,15 +1608,18 @@ class ChatControl(ChatControlBase, ChatCommands):
 | 
				
			||||||
			self.video_sid = None
 | 
								self.video_sid = None
 | 
				
			||||||
		elif state == 'connecting':
 | 
							elif state == 'connecting':
 | 
				
			||||||
			self.video_state = self.JINGLE_STATE_CONNECTING
 | 
								self.video_state = self.JINGLE_STATE_CONNECTING
 | 
				
			||||||
 | 
								self._video_button.set_active(True)
 | 
				
			||||||
			self.video_sid = sid
 | 
								self.video_sid = sid
 | 
				
			||||||
		elif state == 'connection_received':
 | 
							elif state == 'connection_received':
 | 
				
			||||||
			self.video_state = self.JINGLE_STATE_CONNECTION_RECEIVED
 | 
								self.video_state = self.JINGLE_STATE_CONNECTION_RECEIVED
 | 
				
			||||||
 | 
								self._video_button.set_active(True)
 | 
				
			||||||
			self.video_sid = sid
 | 
								self.video_sid = sid
 | 
				
			||||||
		elif state == 'connected':
 | 
							elif state == 'connected':
 | 
				
			||||||
			self.video_state = self.JINGLE_STATE_CONNECTED
 | 
								self.video_state = self.JINGLE_STATE_CONNECTED
 | 
				
			||||||
		elif state == 'stop':
 | 
							elif state == 'stop':
 | 
				
			||||||
			self.video_state = self.JINGLE_STATE_AVAILABLE
 | 
								self.video_state = self.JINGLE_STATE_AVAILABLE
 | 
				
			||||||
			self.video_sid = None
 | 
								self.video_sid = None
 | 
				
			||||||
 | 
								self._video_button.set_active(False)
 | 
				
			||||||
		elif state == 'error':
 | 
							elif state == 'error':
 | 
				
			||||||
			self.video_state = self.JINGLE_STATE_ERROR
 | 
								self.video_state = self.JINGLE_STATE_ERROR
 | 
				
			||||||
		self.update_video()
 | 
							self.update_video()
 | 
				
			||||||
| 
						 | 
					@ -1825,10 +1831,11 @@ class ChatControl(ChatControlBase, ChatCommands):
 | 
				
			||||||
			self.set_audio_state('connecting', sid)
 | 
								self.set_audio_state('connecting', sid)
 | 
				
			||||||
		else:
 | 
							else:
 | 
				
			||||||
			session = gajim.connections[self.account].get_jingle_session(
 | 
								session = gajim.connections[self.account].get_jingle_session(
 | 
				
			||||||
				self.contact.get_full_jid(), self.audio_sid)
 | 
									self.contact.get_full_jid(), self.video_sid)
 | 
				
			||||||
			if session:
 | 
								if session:
 | 
				
			||||||
				# TODO: end only audio
 | 
									content = session.get_content('audio')
 | 
				
			||||||
				session.end_session()
 | 
									if content:
 | 
				
			||||||
 | 
										session.remove_content(content.creator, content.name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def on_video_button_toggled(self, widget):
 | 
						def on_video_button_toggled(self, widget):
 | 
				
			||||||
		if widget.get_active():
 | 
							if widget.get_active():
 | 
				
			||||||
| 
						 | 
					@ -1839,8 +1846,9 @@ class ChatControl(ChatControlBase, ChatCommands):
 | 
				
			||||||
			session = gajim.connections[self.account].get_jingle_session(
 | 
								session = gajim.connections[self.account].get_jingle_session(
 | 
				
			||||||
				self.contact.get_full_jid(), self.video_sid)
 | 
									self.contact.get_full_jid(), self.video_sid)
 | 
				
			||||||
			if session:
 | 
								if session:
 | 
				
			||||||
				# TODO: end only video
 | 
									content = session.get_content('video')
 | 
				
			||||||
				session.end_session()
 | 
									if content:
 | 
				
			||||||
 | 
										session.remove_content(content.creator, content.name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _toggle_gpg(self):
 | 
						def _toggle_gpg(self):
 | 
				
			||||||
		if not self.gpg_is_active and not self.contact.keyID:
 | 
							if not self.gpg_is_active and not self.contact.keyID:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,7 +17,10 @@
 | 
				
			||||||
#   - 'senders' attribute of 'content' element
 | 
					#   - 'senders' attribute of 'content' element
 | 
				
			||||||
#   - security preconditions
 | 
					#   - security preconditions
 | 
				
			||||||
#   * actions:
 | 
					#   * actions:
 | 
				
			||||||
#     - content-accept, content-reject, content-add, content-modify
 | 
					#     - content-accept: see content-add
 | 
				
			||||||
 | 
					#     - content-reject: sending it ; receiving is ok
 | 
				
			||||||
 | 
					#     - content-add: handling ; sending is ok
 | 
				
			||||||
 | 
					#     - content-modify: both
 | 
				
			||||||
#     - description-info, session-info
 | 
					#     - description-info, session-info
 | 
				
			||||||
#     - security-info
 | 
					#     - security-info
 | 
				
			||||||
#     - transport-accept, transport-reject
 | 
					#     - transport-accept, transport-reject
 | 
				
			||||||
| 
						 | 
					@ -88,7 +91,7 @@ class JingleSession(object):
 | 
				
			||||||
		# our full jid
 | 
							# our full jid
 | 
				
			||||||
		self.ourjid = gajim.get_jid_from_account(self.connection.name) + '/' + \
 | 
							self.ourjid = gajim.get_jid_from_account(self.connection.name) + '/' + \
 | 
				
			||||||
			con.server_resource
 | 
								con.server_resource
 | 
				
			||||||
		self.peerjid = jid # jid we connect to
 | 
							self.peerjid = str(jid) # jid we connect to
 | 
				
			||||||
		# jid we use as the initiator
 | 
							# jid we use as the initiator
 | 
				
			||||||
		self.initiator = weinitiate and self.ourjid or self.peerjid
 | 
							self.initiator = weinitiate and self.ourjid or self.peerjid
 | 
				
			||||||
		# jid we use as the responder
 | 
							# jid we use as the responder
 | 
				
			||||||
| 
						 | 
					@ -107,10 +110,12 @@ class JingleSession(object):
 | 
				
			||||||
		# use .prepend() to add new callbacks, especially when you're going
 | 
							# use .prepend() to add new callbacks, especially when you're going
 | 
				
			||||||
		# to send error instead of ack
 | 
							# to send error instead of ack
 | 
				
			||||||
		self.callbacks = {
 | 
							self.callbacks = {
 | 
				
			||||||
			'content-accept':	[self.__contentAcceptCB, self.__defaultCB],
 | 
								'content-accept':	[self.__contentAcceptCB, self.__broadcastCB,
 | 
				
			||||||
			'content-add':		[self.__defaultCB], #TODO
 | 
									self.__defaultCB],
 | 
				
			||||||
 | 
								'content-add':		[self.__contentAddCB, self.__broadcastCB,
 | 
				
			||||||
 | 
									self.__defaultCB], #TODO
 | 
				
			||||||
			'content-modify':	[self.__defaultCB], #TODO
 | 
								'content-modify':	[self.__defaultCB], #TODO
 | 
				
			||||||
			'content-reject':	[self.__defaultCB], #TODO
 | 
								'content-reject':	[self.__defaultCB, self.__contentRemoveCB], #TODO
 | 
				
			||||||
			'content-remove':	[self.__defaultCB, self.__contentRemoveCB],
 | 
								'content-remove':	[self.__defaultCB, self.__contentRemoveCB],
 | 
				
			||||||
			'description-info':	[self.__defaultCB], #TODO
 | 
								'description-info':	[self.__defaultCB], #TODO
 | 
				
			||||||
			'security-info':	[self.__defaultCB], #TODO
 | 
								'security-info':	[self.__defaultCB], #TODO
 | 
				
			||||||
| 
						 | 
					@ -133,7 +138,6 @@ class JingleSession(object):
 | 
				
			||||||
	def approve_session(self):
 | 
						def approve_session(self):
 | 
				
			||||||
		''' Called when user accepts session in UI (when we aren't the initiator).
 | 
							''' Called when user accepts session in UI (when we aren't the initiator).
 | 
				
			||||||
		'''
 | 
							'''
 | 
				
			||||||
		self.accepted = True
 | 
					 | 
				
			||||||
		self.accept_session()
 | 
							self.accept_session()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def decline_session(self):
 | 
						def decline_session(self):
 | 
				
			||||||
| 
						 | 
					@ -154,10 +158,23 @@ class JingleSession(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	''' Middle-level functions to manage contents. Handle local content
 | 
						''' Middle-level functions to manage contents. Handle local content
 | 
				
			||||||
	cache and send change notifications. '''
 | 
						cache and send change notifications. '''
 | 
				
			||||||
 | 
						def get_content(self, media=None):
 | 
				
			||||||
 | 
							if media == 'audio':
 | 
				
			||||||
 | 
								cls = JingleVoIP
 | 
				
			||||||
 | 
							elif media == 'video':
 | 
				
			||||||
 | 
								cls = JingleVideo
 | 
				
			||||||
 | 
							#elif media == None:
 | 
				
			||||||
 | 
							#	cls = JingleContent
 | 
				
			||||||
 | 
							else:
 | 
				
			||||||
 | 
								return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for content in self.contents.values():
 | 
				
			||||||
 | 
								if isinstance(content, cls):
 | 
				
			||||||
 | 
									return content
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def add_content(self, name, content, creator='we'):
 | 
						def add_content(self, name, content, creator='we'):
 | 
				
			||||||
		''' Add new content to session. If the session is active,
 | 
							''' Add new content to session. If the session is active,
 | 
				
			||||||
		this will send proper stanza to update session. 
 | 
							this will send proper stanza to update session. 
 | 
				
			||||||
		The protocol prohibits changing that when pending.
 | 
					 | 
				
			||||||
		Creator must be one of ('we', 'peer', 'initiator', 'responder')'''
 | 
							Creator must be one of ('we', 'peer', 'initiator', 'responder')'''
 | 
				
			||||||
		assert creator in ('we', 'peer', 'initiator', 'responder')
 | 
							assert creator in ('we', 'peer', 'initiator', 'responder')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -171,34 +188,53 @@ class JingleSession(object):
 | 
				
			||||||
		content.name = name
 | 
							content.name = name
 | 
				
			||||||
		self.contents[(creator, name)] = content
 | 
							self.contents[(creator, name)] = content
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if self.state == JingleStates.active:
 | 
					 | 
				
			||||||
			pass # TODO: send proper stanza, shouldn't be needed now
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def remove_content(self, creator, name):
 | 
						def remove_content(self, creator, name):
 | 
				
			||||||
		''' We do not need this now '''
 | 
							''' We do not need this now '''
 | 
				
			||||||
		pass
 | 
							#TODO:
 | 
				
			||||||
 | 
							if (creator, name) in self.contents:
 | 
				
			||||||
 | 
								content = self.contents[(creator, name)]
 | 
				
			||||||
 | 
								if len(self.contents) > 1:
 | 
				
			||||||
 | 
									self.__content_remove(content)
 | 
				
			||||||
 | 
								self.contents[(creator, name)].destroy()
 | 
				
			||||||
 | 
							if len(self.contents) == 0:
 | 
				
			||||||
 | 
								self.end_session()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def modify_content(self, creator, name, *someother):
 | 
						def modify_content(self, creator, name, *someother):
 | 
				
			||||||
		''' We do not need this now '''
 | 
							''' We do not need this now '''
 | 
				
			||||||
		pass
 | 
							pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def accept_session(self):
 | 
						def on_session_state_changed(self, content=None):
 | 
				
			||||||
		''' Check if all contents and user agreed to start session. '''
 | 
							if self.state == JingleStates.active and self.accepted:
 | 
				
			||||||
		if not self.weinitiate and self.accepted and \
 | 
								if not content:
 | 
				
			||||||
		self.state == JingleStates.pending and self.is_ready():
 | 
									return
 | 
				
			||||||
 | 
								if (content.creator == 'initiator') == self.weinitiate:
 | 
				
			||||||
 | 
									# We initiated this content. It's a pending content-add.
 | 
				
			||||||
 | 
									self.__content_add(content)
 | 
				
			||||||
 | 
								else:
 | 
				
			||||||
 | 
									# The other side created this content, we accept it.
 | 
				
			||||||
 | 
									self.__content_accept(content)
 | 
				
			||||||
 | 
							elif self.is_ready():
 | 
				
			||||||
 | 
								if not self.weinitiate and self.state == JingleStates.pending:
 | 
				
			||||||
				self.__session_accept()
 | 
									self.__session_accept()
 | 
				
			||||||
 | 
								elif self.weinitiate and self.state == JingleStates.ended:
 | 
				
			||||||
 | 
									self.__session_initiate()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def is_ready(self):
 | 
						def is_ready(self):
 | 
				
			||||||
		''' Returns True when all codecs and candidates are ready
 | 
							''' Returns True when all codecs and candidates are ready
 | 
				
			||||||
		(for all contents). '''
 | 
							(for all contents). '''
 | 
				
			||||||
		return all((content.is_ready() for content in self.contents.itervalues()))
 | 
							return (all((content.is_ready() for content in self.contents.itervalues()))
 | 
				
			||||||
 | 
								and self.accepted)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	''' Middle-level function to do stanza exchange. '''
 | 
						''' Middle-level function to do stanza exchange. '''
 | 
				
			||||||
 | 
						def accept_session(self):
 | 
				
			||||||
 | 
							''' Mark the session as accepted. '''
 | 
				
			||||||
 | 
							self.accepted = True
 | 
				
			||||||
 | 
							self.on_session_state_changed()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def start_session(self):
 | 
						def start_session(self):
 | 
				
			||||||
		''' Start session. '''
 | 
							''' Mark the session as ready to be started. '''
 | 
				
			||||||
		#FIXME: Start only once
 | 
							self.accepted = True
 | 
				
			||||||
		if self.weinitiate and self.state == JingleStates.ended and self.is_ready():
 | 
							self.on_session_state_changed()
 | 
				
			||||||
			self.__session_initiate()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def send_session_info(self):
 | 
						def send_session_info(self):
 | 
				
			||||||
		pass
 | 
							pass
 | 
				
			||||||
| 
						 | 
					@ -309,10 +345,10 @@ class JingleSession(object):
 | 
				
			||||||
			creator = content['creator']
 | 
								creator = content['creator']
 | 
				
			||||||
			name = content['name']
 | 
								name = content['name']
 | 
				
			||||||
			if (creator, name) in self.contents:
 | 
								if (creator, name) in self.contents:
 | 
				
			||||||
				del self.contents[(creator, name)]
 | 
									self.contents[(creator, name)].destroy()
 | 
				
			||||||
		if len(self.contents) == 0:
 | 
							if len(self.contents) == 0:
 | 
				
			||||||
			reason = xmpp.Node('reason')
 | 
								reason = xmpp.Node('reason')
 | 
				
			||||||
			reason.setTag('success') #FIXME: Is it the good one?
 | 
								reason.setTag('success')
 | 
				
			||||||
			self._session_terminate(reason)
 | 
								self._session_terminate(reason)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def __sessionAcceptCB(self, stanza, jingle, error, action):
 | 
						def __sessionAcceptCB(self, stanza, jingle, error, action):
 | 
				
			||||||
| 
						 | 
					@ -328,6 +364,27 @@ class JingleSession(object):
 | 
				
			||||||
			creator = content['creator']
 | 
								creator = content['creator']
 | 
				
			||||||
			name = content['name']#TODO...
 | 
								name = content['name']#TODO...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						def __contentAddCB(self, stanza, jingle, error, action):
 | 
				
			||||||
 | 
							#TODO: Needs to be rewritten
 | 
				
			||||||
 | 
							if self.state == JingleStates.ended:
 | 
				
			||||||
 | 
								raise OutOfOrder
 | 
				
			||||||
 | 
							for element in jingle.iterTags('content'):
 | 
				
			||||||
 | 
								# checking what kind of session this will be
 | 
				
			||||||
 | 
								desc_ns = element.getTag('description').getNamespace()
 | 
				
			||||||
 | 
								media = element.getTag('description')['media']
 | 
				
			||||||
 | 
								tran_ns = element.getTag('transport').getNamespace()
 | 
				
			||||||
 | 
								if desc_ns == xmpp.NS_JINGLE_RTP and media in ('audio', 'video') \
 | 
				
			||||||
 | 
								and tran_ns == xmpp.NS_JINGLE_ICE_UDP:
 | 
				
			||||||
 | 
									if media == 'audio':
 | 
				
			||||||
 | 
										self.add_content(element['name'], JingleVoIP(self), 'peer')
 | 
				
			||||||
 | 
									else:
 | 
				
			||||||
 | 
										self.add_content(element['name'], JingleVideo(self), 'peer')
 | 
				
			||||||
 | 
								else:
 | 
				
			||||||
 | 
									content = JingleContent()
 | 
				
			||||||
 | 
									self.add_content(element['name'], content, 'peer')
 | 
				
			||||||
 | 
									self.__content_reject(content)
 | 
				
			||||||
 | 
									self.contents[(content.creator, content.name)].destroy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def __sessionInitiateCB(self, stanza, jingle, error, action):
 | 
						def __sessionInitiateCB(self, stanza, jingle, error, action):
 | 
				
			||||||
		''' We got a jingle session request from other entity,
 | 
							''' We got a jingle session request from other entity,
 | 
				
			||||||
		therefore we are the receiver... Unpack the data,
 | 
							therefore we are the receiver... Unpack the data,
 | 
				
			||||||
| 
						 | 
					@ -511,20 +568,40 @@ class JingleSession(object):
 | 
				
			||||||
			text = '%s (%s)' % (reason, text)
 | 
								text = '%s (%s)' % (reason, text)
 | 
				
			||||||
		else:
 | 
							else:
 | 
				
			||||||
			text = reason
 | 
								text = reason
 | 
				
			||||||
		self.connection.dispatch('JINGLE_DISCONNECTED', (self.peerjid, self.sid, text))
 | 
					 | 
				
			||||||
		self.connection.delete_jingle(self)
 | 
							self.connection.delete_jingle(self)
 | 
				
			||||||
 | 
							self.connection.dispatch('JINGLE_DISCONNECTED', (self.peerjid, self.sid, text))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def __content_add(self):
 | 
						def __content_add(self, content):
 | 
				
			||||||
		assert self.state == JingleStates.active
 | 
							#TODO: test
 | 
				
			||||||
 | 
					 | 
				
			||||||
	def __content_accept(self):
 | 
					 | 
				
			||||||
		assert self.state != JingleStates.ended
 | 
							assert self.state != JingleStates.ended
 | 
				
			||||||
 | 
							stanza, jingle = self.__make_jingle('content-add')
 | 
				
			||||||
 | 
							self.__append_content(jingle, content)
 | 
				
			||||||
 | 
							self.__broadcastCB(stanza, jingle, None, 'content-add-sent')
 | 
				
			||||||
 | 
							self.connection.connection.send(stanza)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						def __content_accept(self, content):
 | 
				
			||||||
 | 
							#TODO: test
 | 
				
			||||||
 | 
							assert self.state != JingleStates.ended
 | 
				
			||||||
 | 
							stanza, jingle = self.__make_jingle('content-accept')
 | 
				
			||||||
 | 
							self.__append_content(jingle, content)
 | 
				
			||||||
 | 
							self.__broadcastCB(stanza, jingle, None, 'content-accept-sent')
 | 
				
			||||||
 | 
							self.connection.connection.send(stanza)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						def __content_reject(self, content):
 | 
				
			||||||
 | 
							assert self.state != JingleStates.ended
 | 
				
			||||||
 | 
							stanza, jingle = self.__make_jingle('content-reject')
 | 
				
			||||||
 | 
							self.__append_content(jingle, content)
 | 
				
			||||||
 | 
							self.connection.connection.send(stanza)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def __content_modify(self):
 | 
						def __content_modify(self):
 | 
				
			||||||
		assert self.state != JingleStates.ended
 | 
							assert self.state != JingleStates.ended
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def __content_remove(self):
 | 
						def __content_remove(self, content):
 | 
				
			||||||
		assert self.state != JingleStates.ended
 | 
							assert self.state != JingleStates.ended
 | 
				
			||||||
 | 
							stanza, jingle = self.__make_jingle('content-remove')
 | 
				
			||||||
 | 
							self.__append_content(jingle, content)
 | 
				
			||||||
 | 
							self.connection.connection.send(stanza)
 | 
				
			||||||
 | 
							#TODO: dispatch something?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def content_negociated(self, media):
 | 
						def content_negociated(self, media):
 | 
				
			||||||
		self.connection.dispatch('JINGLE_CONNECTED', (self.peerjid, self.sid,
 | 
							self.connection.dispatch('JINGLE_CONNECTED', (self.peerjid, self.sid,
 | 
				
			||||||
| 
						 | 
					@ -554,8 +631,8 @@ class JingleContent(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		self.callbacks = {
 | 
							self.callbacks = {
 | 
				
			||||||
			# these are called when *we* get stanzas
 | 
								# these are called when *we* get stanzas
 | 
				
			||||||
			'content-accept': [],
 | 
								'content-accept': [self.__transportInfoCB],
 | 
				
			||||||
			'content-add': [],
 | 
								'content-add': [self.__transportInfoCB],
 | 
				
			||||||
			'content-modify': [],
 | 
								'content-modify': [],
 | 
				
			||||||
			'content-remove': [],
 | 
								'content-remove': [],
 | 
				
			||||||
			'session-accept': [self.__transportInfoCB],
 | 
								'session-accept': [self.__transportInfoCB],
 | 
				
			||||||
| 
						 | 
					@ -566,6 +643,8 @@ class JingleContent(object):
 | 
				
			||||||
			'iq-result': [],
 | 
								'iq-result': [],
 | 
				
			||||||
			'iq-error': [],
 | 
								'iq-error': [],
 | 
				
			||||||
			# these are called when *we* sent these stanzas
 | 
								# these are called when *we* sent these stanzas
 | 
				
			||||||
 | 
								'content-accept-sent': [self.__fillJingleStanza],
 | 
				
			||||||
 | 
								'content-add-sent': [self.__fillJingleStanza],
 | 
				
			||||||
			'session-initiate-sent': [self.__fillJingleStanza],
 | 
								'session-initiate-sent': [self.__fillJingleStanza],
 | 
				
			||||||
			'session-accept-sent': [self.__fillJingleStanza],
 | 
								'session-accept-sent': [self.__fillJingleStanza],
 | 
				
			||||||
			'session-terminate-sent': [],
 | 
								'session-terminate-sent': [],
 | 
				
			||||||
| 
						 | 
					@ -676,6 +755,11 @@ class JingleContent(object):
 | 
				
			||||||
		content.addChild(xmpp.NS_JINGLE_ICE_UDP + ' transport', attrs=attrs,
 | 
							content.addChild(xmpp.NS_JINGLE_ICE_UDP + ' transport', attrs=attrs,
 | 
				
			||||||
			payload=self.iter_candidates())
 | 
								payload=self.iter_candidates())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						def destroy(self):
 | 
				
			||||||
 | 
							self.callbacks = None
 | 
				
			||||||
 | 
							del self.session.contents[(self.creator, self.name)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class JingleRTPContent(JingleContent):
 | 
					class JingleRTPContent(JingleContent):
 | 
				
			||||||
	def __init__(self, session, media, node=None):
 | 
						def __init__(self, session, media, node=None):
 | 
				
			||||||
		JingleContent.__init__(self, session, node)
 | 
							JingleContent.__init__(self, session, node)
 | 
				
			||||||
| 
						 | 
					@ -687,6 +771,7 @@ class JingleRTPContent(JingleContent):
 | 
				
			||||||
		self.candidates_ready = False # True when local candidates are prepared
 | 
							self.candidates_ready = False # True when local candidates are prepared
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		self.callbacks['content-accept'] += [self.__getRemoteCodecsCB]
 | 
							self.callbacks['content-accept'] += [self.__getRemoteCodecsCB]
 | 
				
			||||||
 | 
							self.callbacks['content-add'] += [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'] += [self.__stop]
 | 
				
			||||||
| 
						 | 
					@ -718,21 +803,32 @@ class JingleRTPContent(JingleContent):
 | 
				
			||||||
		content.addChild(xmpp.NS_JINGLE_RTP + ' description',
 | 
							content.addChild(xmpp.NS_JINGLE_RTP + ' description',
 | 
				
			||||||
			attrs={'media': self.media}, payload=self.iter_codecs())
 | 
								attrs={'media': self.media}, payload=self.iter_codecs())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						def _setup_funnel(self):
 | 
				
			||||||
 | 
							self.funnel = gst.element_factory_make('fsfunnel')
 | 
				
			||||||
 | 
							self.pipeline.add(self.funnel)
 | 
				
			||||||
 | 
							self.funnel.set_state(gst.STATE_PLAYING)
 | 
				
			||||||
 | 
							self.sink.set_state(gst.STATE_PLAYING)
 | 
				
			||||||
 | 
							self.funnel.link(self.sink)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						def _on_src_pad_added(self, stream, pad, codec):
 | 
				
			||||||
 | 
							if not self.funnel:
 | 
				
			||||||
 | 
								self._setup_funnel()
 | 
				
			||||||
 | 
							pad.link(self.funnel.get_pad('sink%d'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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()
 | 
				
			||||||
			#print name
 | 
					 | 
				
			||||||
			if name == 'farsight-new-active-candidate-pair':
 | 
								if name == 'farsight-new-active-candidate-pair':
 | 
				
			||||||
				pass
 | 
									pass
 | 
				
			||||||
			elif name == 'farsight-recv-codecs-changed':
 | 
								elif name == 'farsight-recv-codecs-changed':
 | 
				
			||||||
				pass
 | 
									pass
 | 
				
			||||||
			elif name == 'farsight-codecs-changed':
 | 
								elif name == 'farsight-codecs-changed':
 | 
				
			||||||
				self.session.accept_session()
 | 
									if self.is_ready():
 | 
				
			||||||
				self.session.start_session()
 | 
										self.session.on_session_state_changed(self)
 | 
				
			||||||
			elif name == 'farsight-local-candidates-prepared':
 | 
								elif name == 'farsight-local-candidates-prepared':
 | 
				
			||||||
				self.candidates_ready = True
 | 
									self.candidates_ready = True
 | 
				
			||||||
				self.session.accept_session()
 | 
									if self.is_ready():
 | 
				
			||||||
				self.session.start_session()
 | 
										self.session.on_session_state_changed(self)
 | 
				
			||||||
			elif name == 'farsight-new-local-candidate':
 | 
								elif name == 'farsight-new-local-candidate':
 | 
				
			||||||
				candidate = message.structure['candidate']
 | 
									candidate = message.structure['candidate']
 | 
				
			||||||
				self.candidates.append(candidate)
 | 
									self.candidates.append(candidate)
 | 
				
			||||||
| 
						 | 
					@ -751,9 +847,6 @@ class JingleRTPContent(JingleContent):
 | 
				
			||||||
					#TODO: farsight.DIRECTION_BOTH only if senders='both'
 | 
										#TODO: farsight.DIRECTION_BOTH only if senders='both'
 | 
				
			||||||
					self.p2pstream.set_property('direction', farsight.DIRECTION_BOTH)
 | 
										self.p2pstream.set_property('direction', farsight.DIRECTION_BOTH)
 | 
				
			||||||
					self.session.content_negociated(self.media)
 | 
										self.session.content_negociated(self.media)
 | 
				
			||||||
					#if not self.session.weinitiate: #FIXME: one more FIXME...
 | 
					 | 
				
			||||||
					#	self.session.send_content_accept(self.__content((xmpp.Node(
 | 
					 | 
				
			||||||
					#		'description', payload=self.iter_codecs()),)))
 | 
					 | 
				
			||||||
			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']
 | 
				
			||||||
| 
						 | 
					@ -805,6 +898,11 @@ class JingleRTPContent(JingleContent):
 | 
				
			||||||
	def __del__(self):
 | 
						def __del__(self):
 | 
				
			||||||
		self.__stop()
 | 
							self.__stop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						def destroy(self):
 | 
				
			||||||
 | 
							JingleContent.destroy(self)
 | 
				
			||||||
 | 
							self.p2pstream.disconnect_by_func(self._on_src_pad_added)
 | 
				
			||||||
 | 
							self.pipeline.get_bus().disconnect_by_func(self._on_gst_message)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class JingleVoIP(JingleRTPContent):
 | 
					class JingleVoIP(JingleRTPContent):
 | 
				
			||||||
	''' Jingle VoIP sessions consist of audio content transported
 | 
						''' Jingle VoIP sessions consist of audio content transported
 | 
				
			||||||
| 
						 | 
					@ -830,8 +928,8 @@ class JingleVoIP(JingleRTPContent):
 | 
				
			||||||
		# the local parts
 | 
							# the local parts
 | 
				
			||||||
		# TODO: use gconfaudiosink?
 | 
							# TODO: use gconfaudiosink?
 | 
				
			||||||
		# sink = get_first_gst_element(['alsasink', 'osssink', 'autoaudiosink'])
 | 
							# sink = get_first_gst_element(['alsasink', 'osssink', 'autoaudiosink'])
 | 
				
			||||||
		sink = gst.element_factory_make('alsasink')
 | 
							self.sink = gst.element_factory_make('alsasink')
 | 
				
			||||||
		sink.set_property('sync', False)
 | 
							self.sink.set_property('sync', False)
 | 
				
			||||||
		#sink.set_property('latency-time', 20000)
 | 
							#sink.set_property('latency-time', 20000)
 | 
				
			||||||
		#sink.set_property('buffer-time', 80000)
 | 
							#sink.set_property('buffer-time', 80000)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -843,21 +941,12 @@ class JingleVoIP(JingleRTPContent):
 | 
				
			||||||
		self.mic_volume.set_property('volume', 1)
 | 
							self.mic_volume.set_property('volume', 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# link gst elements
 | 
							# link gst elements
 | 
				
			||||||
		self.pipeline.add(sink, src_mic, self.mic_volume)
 | 
							self.pipeline.add(self.sink, src_mic, self.mic_volume)
 | 
				
			||||||
		src_mic.link(self.mic_volume)
 | 
							src_mic.link(self.mic_volume)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		def src_pad_added (stream, pad, codec):
 | 
					 | 
				
			||||||
			if not self.funnel:
 | 
					 | 
				
			||||||
				self.funnel = gst.element_factory_make('fsfunnel')
 | 
					 | 
				
			||||||
				self.pipeline.add(self.funnel)
 | 
					 | 
				
			||||||
				self.funnel.set_state (gst.STATE_PLAYING)
 | 
					 | 
				
			||||||
				sink.set_state (gst.STATE_PLAYING)
 | 
					 | 
				
			||||||
				self.funnel.link(sink)
 | 
					 | 
				
			||||||
			pad.link(self.funnel.get_pad('sink%d'))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		self.mic_volume.get_pad('src').link(self.p2psession.get_property(
 | 
							self.mic_volume.get_pad('src').link(self.p2psession.get_property(
 | 
				
			||||||
			'sink-pad'))
 | 
								'sink-pad'))
 | 
				
			||||||
		self.p2pstream.connect('src-pad-added', src_pad_added)
 | 
							self.p2pstream.connect('src-pad-added', self._on_src_pad_added)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# The following is needed for farsight to process ICE requests:
 | 
							# The following is needed for farsight to process ICE requests:
 | 
				
			||||||
		self.pipeline.set_state(gst.STATE_PLAYING)
 | 
							self.pipeline.set_state(gst.STATE_PLAYING)
 | 
				
			||||||
| 
						 | 
					@ -875,7 +964,7 @@ class JingleVideo(JingleRTPContent):
 | 
				
			||||||
		# sometimes it'll freeze...
 | 
							# sometimes it'll freeze...
 | 
				
			||||||
		JingleRTPContent.setup_stream(self)
 | 
							JingleRTPContent.setup_stream(self)
 | 
				
			||||||
		# the local parts
 | 
							# the local parts
 | 
				
			||||||
		src_vid = gst.element_factory_make('v4l2src')
 | 
							src_vid = gst.element_factory_make('videotestsrc')
 | 
				
			||||||
		videoscale = gst.element_factory_make('videoscale')
 | 
							videoscale = gst.element_factory_make('videoscale')
 | 
				
			||||||
		caps = gst.element_factory_make('capsfilter')
 | 
							caps = gst.element_factory_make('capsfilter')
 | 
				
			||||||
		caps.set_property('caps', gst.caps_from_string('video/x-raw-yuv, width=320, height=240'))
 | 
							caps.set_property('caps', gst.caps_from_string('video/x-raw-yuv, width=320, height=240'))
 | 
				
			||||||
| 
						 | 
					@ -884,19 +973,11 @@ class JingleVideo(JingleRTPContent):
 | 
				
			||||||
		self.pipeline.add(src_vid, videoscale, caps, colorspace)
 | 
							self.pipeline.add(src_vid, videoscale, caps, colorspace)
 | 
				
			||||||
		gst.element_link_many(src_vid, videoscale, caps, colorspace)
 | 
							gst.element_link_many(src_vid, videoscale, caps, colorspace)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		def src_pad_added (stream, pad, codec):
 | 
							self.sink = gst.element_factory_make('xvimagesink')
 | 
				
			||||||
			if not self.funnel:
 | 
							self.pipeline.add(self.sink)
 | 
				
			||||||
				self.funnel = gst.element_factory_make('fsfunnel')
 | 
					 | 
				
			||||||
				self.pipeline.add(self.funnel)
 | 
					 | 
				
			||||||
				videosink = gst.element_factory_make('xvimagesink')
 | 
					 | 
				
			||||||
				self.pipeline.add(videosink)
 | 
					 | 
				
			||||||
				self.funnel.set_state (gst.STATE_PLAYING)
 | 
					 | 
				
			||||||
				videosink.set_state(gst.STATE_PLAYING)
 | 
					 | 
				
			||||||
				self.funnel.link(videosink)
 | 
					 | 
				
			||||||
			pad.link(self.funnel.get_pad('sink%d'))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		colorspace.get_pad('src').link(self.p2psession.get_property('sink-pad'))
 | 
							colorspace.get_pad('src').link(self.p2psession.get_property('sink-pad'))
 | 
				
			||||||
		self.p2pstream.connect('src-pad-added', src_pad_added)
 | 
							self.p2pstream.connect('src-pad-added', self._on_src_pad_added)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# The following is needed for farsight to process ICE requests:
 | 
							# The following is needed for farsight to process ICE requests:
 | 
				
			||||||
		self.pipeline.set_state(gst.STATE_PLAYING)
 | 
							self.pipeline.set_state(gst.STATE_PLAYING)
 | 
				
			||||||
| 
						 | 
					@ -953,6 +1034,8 @@ class ConnectionJingle(object):
 | 
				
			||||||
		raise xmpp.NodeProcessed
 | 
							raise xmpp.NodeProcessed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def startVoIP(self, jid):
 | 
						def startVoIP(self, jid):
 | 
				
			||||||
 | 
							if self.get_jingle_session(jid, media='audio'):
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
		jingle = self.get_jingle_session(jid, media='video')
 | 
							jingle = self.get_jingle_session(jid, media='video')
 | 
				
			||||||
		if jingle:
 | 
							if jingle:
 | 
				
			||||||
			jingle.add_content('voice', JingleVoIP(jingle))
 | 
								jingle.add_content('voice', JingleVoIP(jingle))
 | 
				
			||||||
| 
						 | 
					@ -964,6 +1047,8 @@ class ConnectionJingle(object):
 | 
				
			||||||
		return jingle.sid
 | 
							return jingle.sid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def startVideoIP(self, jid):
 | 
						def startVideoIP(self, jid):
 | 
				
			||||||
 | 
							if self.get_jingle_session(jid, media='video'):
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
		jingle = self.get_jingle_session(jid, media='audio')
 | 
							jingle = self.get_jingle_session(jid, media='audio')
 | 
				
			||||||
		if jingle:
 | 
							if jingle:
 | 
				
			||||||
			jingle.add_content('video', JingleVideo(jingle))
 | 
								jingle.add_content('video', JingleVideo(jingle))
 | 
				
			||||||
| 
						 | 
					@ -981,14 +1066,10 @@ class ConnectionJingle(object):
 | 
				
			||||||
			else:
 | 
								else:
 | 
				
			||||||
				return None
 | 
									return None
 | 
				
			||||||
		elif media:
 | 
							elif media:
 | 
				
			||||||
			if media == 'audio':
 | 
								if media not in ('audio', 'video'):
 | 
				
			||||||
				cls = JingleVoIP
 | 
					 | 
				
			||||||
			elif media == 'video':
 | 
					 | 
				
			||||||
				cls = JingleVideo
 | 
					 | 
				
			||||||
			else:
 | 
					 | 
				
			||||||
				return None
 | 
									return None
 | 
				
			||||||
			for session in self.__sessions.values():
 | 
								for session in self.__sessions.values():
 | 
				
			||||||
				for content in session.contents.values():
 | 
									if session.peerjid == jid and session.get_content(media):
 | 
				
			||||||
					if isinstance(content, cls):
 | 
					 | 
				
			||||||
					return session
 | 
										return session
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return None
 | 
							return None
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,6 +32,7 @@
 | 
				
			||||||
import gtk
 | 
					import gtk
 | 
				
			||||||
import gobject
 | 
					import gobject
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
 | 
					from weakref import WeakValueDictionary
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import gtkgui_helpers
 | 
					import gtkgui_helpers
 | 
				
			||||||
import vcard
 | 
					import vcard
 | 
				
			||||||
| 
						 | 
					@ -4442,11 +4443,15 @@ class GPGInfoWindow:
 | 
				
			||||||
		self.window.destroy()
 | 
							self.window.destroy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class VoIPCallReceivedDialog(object):
 | 
					class VoIPCallReceivedDialog(object):
 | 
				
			||||||
 | 
						instances = WeakValueDictionary()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def __init__(self, account, contact_jid, sid):
 | 
						def __init__(self, account, contact_jid, sid):
 | 
				
			||||||
		self.account = account
 | 
							self.account = account
 | 
				
			||||||
		self.fjid = contact_jid
 | 
							self.fjid = contact_jid
 | 
				
			||||||
		self.sid = sid
 | 
							self.sid = sid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							self.instances[(contact_jid, sid)] = self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		xml = gtkgui_helpers.get_glade('voip_call_received_dialog.glade')
 | 
							xml = gtkgui_helpers.get_glade('voip_call_received_dialog.glade')
 | 
				
			||||||
		xml.signal_autoconnect(self)
 | 
							xml.signal_autoconnect(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4461,9 +4466,17 @@ class VoIPCallReceivedDialog(object):
 | 
				
			||||||
		dialog = xml.get_widget('voip_call_received_messagedialog')
 | 
							dialog = xml.get_widget('voip_call_received_messagedialog')
 | 
				
			||||||
		dialog.set_property('secondary-text',
 | 
							dialog.set_property('secondary-text',
 | 
				
			||||||
			dialog.get_property('secondary-text') % {'contact': contact_text})
 | 
								dialog.get_property('secondary-text') % {'contact': contact_text})
 | 
				
			||||||
 | 
							self._dialog = dialog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		dialog.show_all()
 | 
							dialog.show_all()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@classmethod
 | 
				
			||||||
 | 
						def get_dialog(cls, jid, sid):
 | 
				
			||||||
 | 
							if (jid, sid) in cls.instances:
 | 
				
			||||||
 | 
								return cls.instances[(jid, sid)]
 | 
				
			||||||
 | 
							else:
 | 
				
			||||||
 | 
								return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def on_voip_call_received_messagedialog_close(self, dialog):
 | 
						def on_voip_call_received_messagedialog_close(self, dialog):
 | 
				
			||||||
		return self.on_voip_call_received_messagedialog_response(dialog,
 | 
							return self.on_voip_call_received_messagedialog_response(dialog,
 | 
				
			||||||
			gtk.RESPONSE_NO)
 | 
								gtk.RESPONSE_NO)
 | 
				
			||||||
| 
						 | 
					@ -4487,7 +4500,10 @@ class VoIPCallReceivedDialog(object):
 | 
				
			||||||
				if not contact:
 | 
									if not contact:
 | 
				
			||||||
					return
 | 
										return
 | 
				
			||||||
				ctrl = gajim.interface.new_chat(contact, self.account)
 | 
									ctrl = gajim.interface.new_chat(contact, self.account)
 | 
				
			||||||
 | 
								if session.get_content('audio'):
 | 
				
			||||||
				ctrl.set_audio_state('connecting', self.sid)
 | 
									ctrl.set_audio_state('connecting', self.sid)
 | 
				
			||||||
 | 
								if session.get_content('video'):
 | 
				
			||||||
 | 
									ctrl.set_video_state('connecting', self.sid)
 | 
				
			||||||
		else: # response==gtk.RESPONSE_NO
 | 
							else: # response==gtk.RESPONSE_NO
 | 
				
			||||||
			session.decline_session()
 | 
								session.decline_session()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										12
									
								
								src/gajim.py
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								src/gajim.py
									
										
									
									
									
								
							| 
						 | 
					@ -2119,7 +2119,10 @@ class Interface:
 | 
				
			||||||
		if not ctrl:
 | 
							if not ctrl:
 | 
				
			||||||
			ctrl = self.msg_win_mgr.get_control(jid, account)
 | 
								ctrl = self.msg_win_mgr.get_control(jid, account)
 | 
				
			||||||
		if ctrl:
 | 
							if ctrl:
 | 
				
			||||||
 | 
								if 'audio' in content_types:
 | 
				
			||||||
				ctrl.set_audio_state('connection_received', sid)
 | 
									ctrl.set_audio_state('connection_received', sid)
 | 
				
			||||||
 | 
								if 'video' in content_types:
 | 
				
			||||||
 | 
									ctrl.set_video_state('connection_received', sid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if helpers.allow_popup_window(account):
 | 
							if helpers.allow_popup_window(account):
 | 
				
			||||||
			dialogs.VoIPCallReceivedDialog(account, peerjid, sid)
 | 
								dialogs.VoIPCallReceivedDialog(account, peerjid, sid)
 | 
				
			||||||
| 
						 | 
					@ -2141,14 +2144,17 @@ class Interface:
 | 
				
			||||||
	def handle_event_jingle_connected(self, account, data):
 | 
						def handle_event_jingle_connected(self, account, data):
 | 
				
			||||||
		# ('JINGLE_CONNECTED', account, (peerjid, sid, media))
 | 
							# ('JINGLE_CONNECTED', account, (peerjid, sid, media))
 | 
				
			||||||
		peerjid, sid, media = data
 | 
							peerjid, sid, media = data
 | 
				
			||||||
		if media == 'audio':
 | 
							if media in ('audio', 'video'):
 | 
				
			||||||
			jid = gajim.get_jid_without_resource(peerjid)
 | 
								jid = gajim.get_jid_without_resource(peerjid)
 | 
				
			||||||
			resource = gajim.get_resource_from_jid(peerjid)
 | 
								resource = gajim.get_resource_from_jid(peerjid)
 | 
				
			||||||
			ctrl = self.msg_win_mgr.get_control(peerjid, account)
 | 
								ctrl = self.msg_win_mgr.get_control(peerjid, account)
 | 
				
			||||||
			if not ctrl:
 | 
								if not ctrl:
 | 
				
			||||||
				ctrl = self.msg_win_mgr.get_control(jid, account)
 | 
									ctrl = self.msg_win_mgr.get_control(jid, account)
 | 
				
			||||||
			if ctrl:
 | 
								if ctrl:
 | 
				
			||||||
 | 
									if media == 'audio':
 | 
				
			||||||
					ctrl.set_audio_state('connected', sid)
 | 
										ctrl.set_audio_state('connected', sid)
 | 
				
			||||||
 | 
									else:
 | 
				
			||||||
 | 
										ctrl.set_video_state('connected', sid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def handle_event_jingle_disconnected(self, account, data):
 | 
						def handle_event_jingle_disconnected(self, account, data):
 | 
				
			||||||
		# ('JINGLE_DISCONNECTED', account, (peerjid, sid, reason))
 | 
							# ('JINGLE_DISCONNECTED', account, (peerjid, sid, reason))
 | 
				
			||||||
| 
						 | 
					@ -2160,6 +2166,10 @@ class Interface:
 | 
				
			||||||
			ctrl = self.msg_win_mgr.get_control(jid, account)
 | 
								ctrl = self.msg_win_mgr.get_control(jid, account)
 | 
				
			||||||
		if ctrl:
 | 
							if ctrl:
 | 
				
			||||||
			ctrl.set_audio_state('stop', sid=sid, reason=reason)
 | 
								ctrl.set_audio_state('stop', sid=sid, reason=reason)
 | 
				
			||||||
 | 
								ctrl.set_video_state('stop', sid=sid, reason=reason)
 | 
				
			||||||
 | 
							dialog = dialogs.VoIPCallReceivedDialog.get_dialog(peerjid, sid)
 | 
				
			||||||
 | 
							if dialog:
 | 
				
			||||||
 | 
								dialog._dialog.destroy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def handle_event_jingle_error(self, account, data):
 | 
						def handle_event_jingle_error(self, account, data):
 | 
				
			||||||
		# ('JINGLE_ERROR', account, (peerjid, sid, reason))
 | 
							# ('JINGLE_ERROR', account, (peerjid, sid, reason))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue