def handle_ice_candidate(self, client, data): '''Handle ice candidate from local user. Args: client : local user data : ice candidate message from local user. Whenever the local frontend ends its ice candidate, it's expecting the ice candiate from the remote end. We will use a fake ice candidate for the remote end to trick the frontend to use an ice candidate that points to a port that our proxy is listening to intercept webrtc traffice. If the SDP for remote end has not been received yet, we postpone the reply of ice candidate because WebRTC requires SDP to be set up before receiving ice candidate message. ''' candidate = Candidate.from_string(data.candidate) if client.media_sink_ports.get(data.socketId) is None: port = int(candidate.port) client.media_sink_ports[data.socketId] = port client.ctrl_seqs[port] = 0 client.remote_cids[port] = data.socketId if client.media_source_port is None: client.media_source_port = int(candidate.port) if client.ip is None: client.ip = candidate.ip candidate = Candidate(('127.0.0.1', str(self.listen_port))) d = RTCData(candidate = str(candidate), socketId = data.socketId) msg = RTCMessage('receive_ice_candidate', d) remote_user = self.roster[data.socketId] remote_user.set_ice_candidate_msg(msg) # sdp answer has already been sent if remote_user.sdp_sent: self.client.sendMessage(str(msg))
def sdp_callback(self, interest, data): '''A callback function for incoming sdp description from remote users. Args: interest : PyCCN.UpcallInfo.Interest data : PyCCN.UpcallInfo.ContentObject Send the sdp to the frontend. If we already received the ICE candidate for the same remote user, then we also send out this ICE candidate. ''' content = data.content offer_msg = RTCMessage.from_string(content) d = RTCData(socketId = self.client.id, sdp = offer_msg.data.sdp) # this is the answer to the local user answer_msg = RTCMessage('receive_answer', offer_msg.data) self.client.sendMessage(str(answer_msg)) remote_user = self.roster[offer_msg.data.socketId] remote_user.set_sdp_sent() # we received ice candidate before sending answer if remote_user.ice_candidate_msg is not None: self.client.sendMessage(str(remote_user.ice_candidate_msg))
def process(self, client, msg): '''Process the message from the local user's front end. Args: client (PeetsServerProtocol) : local user. msg (RTCMessage) : the message from frontend. ''' rtcMsg = RTCMessage.from_string(msg) handler = self.handlers.get(rtcMsg.eventName) if handler is not None: handler(client, rtcMsg.data) else: PeetsServerFactory.__logger.error("Unknown event name: " + rtcMsg.eventName)
def handle_join(self, client, data): '''Handle join message from the frontend Args: client : local user data : join message from local user ''' PeetsServerFactory.__logger.debug('join from client %s', client.id) d = RTCData(connections = []) msg = RTCMessage('get_peers', d) client.sendMessage(str(msg)) client.local_user.nick = self.nick client.local_user.prefix = self.prefix
def peets_msg_callback(self, peets_msg): '''A callback function to process the peets message (to be used by Roster). Args: peets_msg (PeetsMessage) : The received PeetsMessage. Basically, it needs to inform the status change or text chat to the front end and als fetch sdp for the new remote user if the PeetsMessage is a Join. ''' remote_user = RemoteUser(peets_msg.user) if peets_msg.msg_type == PeetsMessage.Join or peets_msg.msg_type == PeetsMessage.Hello: if self.roster.has_key(remote_user.uid): self.__class__.__logger.debug("Redundant join message from %s", remote_user.get_sync_prefix()) exit(0) return self.roster[remote_user.uid] = remote_user self.__class__.__logger.debug("Peets join message from remote user: %s", remote_user.get_sync_prefix()) data = RTCData(socketId = remote_user.uid, username= remote_user.nick) msg = RTCMessage('new_peer_connected', data) self.client.sendMessage(str(msg)) name = remote_user.get_sdp_prefix() # ask for sdp message for the new remote user self.ccnx_socket.send_interest(name, PeetsClosure(msg_callback = self.sdp_callback)) elif peets_msg.msg_type == PeetsMessage.Leave: del self.roster[remote_user.uid] self.__class__.__logger.debug("Peets leave message from remote user: %s", remote_user.get_sync_prefix()) data = RTCData(socketId = remote_user.uid) msg = RTCMessage('remove_peer_connected', data) self.client.sendMessage(str(msg)) elif peets_msg.msg_type == PeetsMessage.Chat: data = RTCData(socketId = remote_user.uid, messages = peets_msg.extra, username = remote_user.nick) msg = RTCMessage('receive_chat_msg', data) self.client.sendMessage(str(msg))
def handle_offer(self, client, data): '''Handle the offer (sdp) from the front end Args: client : local user data : offer sdp message We store the offer for later use (we will use the same offer for all the PeerConnection this local user is going to establish) and also publish it to NDN. ''' if client.media_source_sdp is None: client.media_source_sdp = data.sdp d = RTCData(sdp = client.media_source_sdp, socketId = client.id) msg = RTCMessage('receive_offer', d) name = client.local_user.get_sdp_prefix() # publish sdp msg self.ccnx_socket.publish_content(name, str(msg)) def publish(interest): self.ccnx_socket.publish_content(name, str(msg)) self.ccnx_socket.register_prefix(name, PeetsClosure(incoming_interest_callback = publish))