Example #1
0
def host_room(room, username):
    queue = Queue()
    threading.Thread(target=get_messages_thread,
                     args=(queue, username)).start()
    rtc = RTCPeerConnection(rtcConfiguration)
    channel = Channel(rtc.createDataChannel("data", negotiated=True, id=0))

    offer = run(rtc.createOffer())
    run(rtc.setLocalDescription(offer))
    res = post("/api/host/%s" % room, {
        "room": room,
        "offer": object_to_string(offer)
    }, username)
    print("Got res %s" % res)
    run(rtc.setRemoteDescription(object_from_string(res["answer"])))
    for candidate in rtc.sctp.transport.transport.iceGatherer.getLocalCandidates(
    ):
        send_message(username, res["username"], "ice",
                     fix_candidate(object_to_string(candidate)))
    time.sleep(3)
    while not queue.empty():
        for message in queue.get():
            if message["type"] == "ice":
                print("Got candidate: %s" % message["data"])
                rtc.sctp.transport.transport.addRemoteCandidate(
                    object_from_string(fix_candidate2(message["data"])))
    rtc.sctp.transport.transport.addRemoteCandidate(None)

    return channel, rtc
Example #2
0
async def run(pc):
    session = ClientSession()

    async with session.ws_connect("ws://39.102.116.49:8080") as ws:
        async for msg in ws:
            if msg.type == WSMsgType.TEXT:
                data = json.loads(msg.data)

                if data["type"] == "offerOrAnswer":
                    await pc.setRemoteDescription(
                        object_from_string(json.dumps(data["msg"])))

                    if data["msg"]["type"] == "offer":
                        pc.addTrack(FlagVideoStreamTrack())
                        await pc.setLocalDescription(await pc.createAnswer())
                        await ws.send_str(
                            json.dumps({
                                "type":
                                "offerOrAnswer",
                                "msg":
                                json.loads(
                                    object_to_string(pc.localDescription)),
                            }))
                elif data["type"] == "candidate":
                    try:
                        await pc.addIceCandidate(
                            object_from_string(json.dumps(data["msg"])))
                    except:
                        pass
Example #3
0
async def websocket_coroutine():
    session = aiohttp.ClientSession()
    async with session.ws_connect(WEBSOCKET_URI) as ws:
        print("websocket connected")
        request = json.dumps({
            "what": "call"
        })
        await ws.send_str(request)

        async for msg in ws:
            print(msg)
            if msg.type == aiohttp.WSMsgType.TEXT:
                params = json.loads(msg.data)
                print(params)
                if params["what"] == "offer":
                    print("offer received")
                    uv4l_sdp = object_from_string(params["data"])
                    await pc.setRemoteDescription(uv4l_sdp)
                    await pc.setLocalDescription(await pc.createAnswer())
                    local_sdp = object_to_string(pc.localDescription)
                    print(local_sdp)
                    print(type(local_sdp))
                    await ws.send_str(json.dumps({
                        "what": "answer",
                        "data": local_sdp
                    }))

                elif params['what'] == 'hangup':
                    print("hangup received")
                    await ws.close()
                    break
                else:
                    print(msg)
            elif msg.type == aiohttp.WSMsgType.ERROR:
                break
Example #4
0
    async def create_offer(self):
        channel = self.pc.createDataChannel("chat")
        self.channel = channel

        await self.pc.setLocalDescription(await self.pc.createOffer())

        return object_to_string(self.pc.localDescription)
    async def _set_offer(self, pc, signaling):
        await signaling.connect()
        channel = pc.createDataChannel("chat")

        self.channel = channel

        @channel.on("open")
        def on_open():
            asyncio.ensure_future(self.send(channel))

        @channel.on("message")
        def on_message(message):
            self.process_msg(message, channel)

        await pc.setLocalDescription(await pc.createOffer())
        local_description = object_to_string(pc.localDescription)

        response = {
            MSG_FIELD.TYPE: NODE_EVENTS.WEBRTC_OFFER,
            MSG_FIELD.PAYLOAD: local_description,
            MSG_FIELD.FROM: self._origin,
        }

        forward_payload = {
            MSG_FIELD.TYPE: GRID_EVENTS.FORWARD,
            MSG_FIELD.DESTINATION: self._destination,
            MSG_FIELD.CONTENT: response,
        }

        self._grid.send(json.dumps(forward_payload))
        await self.consume_signaling(pc, signaling)
Example #6
0
    async def consume_signaling(self, pc, signaling):
        while True:
            if self._msg == "":
                await asyncio.sleep(5)
                continue

            obj = object_from_string(self._msg)

            if isinstance(obj, RTCSessionDescription):
                await pc.setRemoteDescription(obj)

                if obj.type == "offer":
                    # send answer
                    await pc.setLocalDescription(await pc.createAnswer())
                    local_description = object_to_string(pc.localDescription)

                    response = {
                        MSG_FIELD.TYPE: NODE_EVENTS.WEBRTC_ANSWER,
                        MSG_FIELD.FROM: self._origin,
                        MSG_FIELD.PAYLOAD: local_description,
                    }

                    forward_payload = {
                        MSG_FIELD.TYPE: GRID_EVENTS.FORWARD,
                        MSG_FIELD.DESTINATION: self._destination,
                        MSG_FIELD.CONTENT: response,
                    }
                    self._grid.send(json.dumps(forward_payload))
            elif isinstance(obj, RTCIceCandidate):
                pc.addIceCandidate(obj)
            elif obj is BYE:
                print("Exiting")
                break
            self._msg = ""
    async def consume_signaling(self, pc, signaling):

        # Async keep-alive connection thread
        while self.available:
            sleep_time = 0
            if self._msg == "":
                await asyncio.sleep(sleep_time)
                continue

            obj = object_from_string(self._msg)

            if isinstance(obj, RTCSessionDescription):
                await pc.setRemoteDescription(obj)
                if obj.type == "offer":
                    # send answer
                    await pc.setLocalDescription(await pc.createAnswer())
                    local_description = object_to_string(pc.localDescription)

                    response = {
                        MSG_FIELD.TYPE: NODE_EVENTS.WEBRTC_ANSWER,
                        MSG_FIELD.FROM: self._origin,
                        MSG_FIELD.PAYLOAD: local_description,
                    }

                    forward_payload = {
                        MSG_FIELD.TYPE: GRID_EVENTS.FORWARD,
                        MSG_FIELD.DESTINATION: self._destination,
                        MSG_FIELD.CONTENT: response,
                    }
                    self._grid.send(json.dumps(forward_payload))
                    sleep_time = 10
            self._msg = ""
        raise Exception
Example #8
0
 async def send(self, obj):
     message = object_to_string(obj)
     print('>', message)
     await self.websocket.send(json.dumps({
         'cmd': 'send',
         'msg': message,
     }))
Example #9
0
 def receive_sync(self):
     loop = asyncio.get_event_loop()
     message = loop.run_until_complete(self.receive())
     if message and self._javascript_callable:
         message = object_to_string(message)
         print('receive:', message)
         message = json.loads(message)
         message = IPython.display.JSON(message)
     return message
Example #10
0
    async def create_answer(self, offer):
        offer = object_from_string(offer)

        await self.pc.setRemoteDescription(offer)
        await self.pc.setLocalDescription(await self.pc.createAnswer())

        @self.pc.on("datachannel")
        def on_datachannel(channel):
            self.channel = channel

        return object_to_string(self.pc.localDescription)
Example #11
0
 async def send(self, obj):
     message = object_to_string(obj)
     logger.debug("> " + message)
     if self.__is_initiator:
         await self._http.post(self.__post_url, data=message)
     else:
         await self._websocket.send(
             json.dumps({
                 "cmd": "send",
                 "msg": message
             }))
Example #12
0
 async def send(self, obj):
     message = object_to_string(obj)
     print('>', message)
     if self.__is_initiator:
         await self.client.post(self.__post_url, data=message)
     else:
         await self.websocket.send(
             json.dumps({
                 'cmd': 'send',
                 'msg': message,
             }))
Example #13
0
 def test_candidate_to_string(self):
     candidate = RTCIceCandidate(component=1,
                                 foundation='0',
                                 ip='192.168.99.7',
                                 port=33543,
                                 priority=2122252543,
                                 protocol='UDP',
                                 type='host')
     candidate.sdpMid = 'audio'
     candidate.sdpMLineIndex = 0
     self.assertEqual(object_to_string(
         candidate
     ), '{"candidate": "candidate:0 1 UDP 2122252543 192.168.99.7 33543 typ host", "id": "audio", "label": 0, "type": "candidate"}'
                      )  # noqa
Example #14
0
 def test_candidate_to_string(self):
     candidate = RTCIceCandidate(
         component=1,
         foundation="0",
         ip="192.168.99.7",
         port=33543,
         priority=2122252543,
         protocol="UDP",
         type="host",
     )
     candidate.sdpMid = "audio"
     candidate.sdpMLineIndex = 0
     self.assertEqual(
         object_to_string(candidate),
         '{"candidate": "candidate:0 1 UDP 2122252543 192.168.99.7 33543 typ host", "id": "audio", "label": 0, "type": "candidate"}',
     )
Example #15
0
    async def _set_offer(self) -> str:
        """Initialize a Real Time Communication Data Channel,
        set datachannel callbacks/tasks, and send offer payload
        message.

        :return: returns a signaling offer payload containing local description.
        :rtype: str
        """
        try:
            # Use the Peer Connection structure to
            # set the channel as a RTCDataChannel.
            self.channel = self.peer_connection.createDataChannel(
                "datachannel")

            # This method will be called by as a callback
            # function by the aioRTC lib when the when
            # the connection opens.
            @self.channel.on("open")
            async def on_open() -> None:  # type : ignore
                self.__producer_task = asyncio.ensure_future(self.producer())

            # This method is the aioRTC "consumer" task
            # and will be running as long as connection remains.
            # At this point we're just setting the method behavior
            # It'll start running after the connection opens.
            @self.channel.on("message")
            async def on_message(
                    message: Union[bin, str]) -> None:  # type: ignore
                # Forward all received messages to our own consumer method.
                await self.consumer(msg=message)

            # Set peer_connection to generate an offer message type.
            await self.peer_connection.setLocalDescription(
                await self.peer_connection.createOffer())

            # Generates the local description structure
            # and serialize it to string afterwards.
            local_description = object_to_string(
                self.peer_connection.localDescription)

            # Return the Offer local_description payload.
            return local_description
        except Exception as e:
            log = f"Got an exception in WebRTCConnection _set_offer. {e}"
            logger.error(log)
            raise e
Example #16
0
async def WebRTCSignalingService(request):
    ws = web.WebSocketResponse()
    await ws.prepare(request)

    async for msg in ws:
        print(msg)
        if msg.type == aiohttp.WSMsgType.TEXT:
            params = json.loads(msg.data)
            print(type(params))
            print(params)

            if params["what"] == "call":
                print("call received")
                # prepare media
                pc.addTrack(VideoStreamTrack)
                await pc.setLocalDescription(await pc.createOffer())
                uv4l_sdp = object_to_string(pc.localDescription)
                print(type(uv4l_sdp))
                await ws.send_str(
                    json.dumps({
                        "what": "offer",
                        "data": uv4l_sdp
                    }))

            elif params["what"] == "answer":
                print("answer received")
                local_sdp = object_from_string(params["data"])
                await pc.setRemoteDescription(local_sdp)
                print('setRemoteDescription(<local_sdp>)')
                # await pc.setRemoteDescription(local_sdp)

            elif params["what"] == "addIceCandidate":
                print("addIceCandidate received")
            elif params['what'] == 'hangup':
                print("hangup received")
                await ws.close()
            else:
                await ws.send_json(msg.data + '\n received.')
        elif msg.type == aiohttp.WSMsgType.ERROR:
            print('ws connection closed with exception %s' % ws.exception())

    print('websocket connection closed')

    return ws
Example #17
0
    async def consume_signaling(self, pc, signaling):
        """Consume signaling to go through all the webrtc connection protocol.

        Args:
            pc: Peer Connection.
            signaling: Webrtc signaling instance.
        Exception:
            ConnectionClosedException: Exception used to finish this connection
            and close this thread.
        """
        # Async keep-alive connection thread
        while self.available:
            sleep_time = 0
            if self._msg == "":
                await asyncio.sleep(sleep_time)
                continue

            obj = object_from_string(self._msg)

            if isinstance(obj, RTCSessionDescription):
                await pc.setRemoteDescription(obj)
                if obj.type == "offer":
                    # send answer
                    await pc.setLocalDescription(await pc.createAnswer())
                    local_description = object_to_string(pc.localDescription)

                    response = {
                        MSG_FIELD.TYPE: NODE_EVENTS.WEBRTC_ANSWER,
                        MSG_FIELD.FROM: self._origin,
                        MSG_FIELD.PAYLOAD: local_description,
                    }

                    forward_payload = {
                        MSG_FIELD.TYPE: GRID_EVENTS.FORWARD,
                        MSG_FIELD.DESTINATION: self._destination,
                        MSG_FIELD.CONTENT: response,
                    }
                    self._grid.send(json.dumps(forward_payload))
                    sleep_time = 10
            self._msg = ""
        raise Exception
Example #18
0
    async def _process_answer(self, payload: str) -> Union[str, None]:
        # Converts payload received by
        # the other peer in aioRTC Object
        # instance.
        try:
            msg = object_from_string(payload)

            # Check if Object instance is a
            # description of RTC Session.
            if isinstance(msg, RTCSessionDescription):

                # Use the target's network address/metadata
                # to set the remote description of this peer.
                # This will basically say to this peer how to find/connect
                # with to other peer.
                await self.peer_connection.setRemoteDescription(msg)

                # If it's an offer message type,
                # generates your own local description
                # and send it back in order to tell
                # to the other peer how to find you.
                if msg.type == "offer":
                    # Set peer_connection to generate an offer message type.
                    await self.peer_connection.setLocalDescription(
                        await self.peer_connection.createAnswer())

                    # Generates the local description structure
                    # and serialize it to string afterwards.
                    local_description = object_to_string(
                        self.peer_connection.localDescription)

                    # Returns the answer peer's local description
                    return local_description
        except Exception as e:
            log = f"Got an exception in WebRTCConnection _process_answer. {e}"
            logger.error(log)
            raise e
        return None
Example #19
0
 async def send(self, obj):
     message = object_to_string(obj)
     print('>', message)
     await self._http.post(self.__post_url, data=message)
Example #20
0
 def test_bye_to_string(self):
     self.assertEqual(object_to_string(BYE), '{"type": "bye"}')
Example #21
0
    async def _set_offer(self) -> str:
        """
        Initialize a Real-Time Communication Data Channel,
        set data channel callbacks/tasks, and send offer payload
        message.

        :return: returns a signaling offer payload containing local description.
        :rtype: str
        """
        try:
            # Use the Peer Connection structure to
            # set the channel as a RTCDataChannel.
            self.channel = self.peer_connection.createDataChannel(
                "datachannel",
            )
            # Keep send buffer busy with chunks
            self.channel.bufferedAmountLowThreshold = 4 * DC_MAX_CHUNK_SIZE

            # This method will be called by aioRTC lib as a callback
            # function when the connection opens.
            @self.channel.on("open")
            async def on_open() -> None:  # type : ignore
                self.__producer_task = asyncio.ensure_future(self.producer())

            chunked_msg = []
            chunks_pending = 0

            # This method is the aioRTC "consumer" task
            # and will be running as long as connection remains.
            # At this point we're just setting the method behavior
            # It'll start running after the connection opens.
            @self.channel.on("message")
            async def on_message(raw: bytes) -> None:
                nonlocal chunked_msg, chunks_pending

                chunk = OrderedChunk.load(raw)
                message = chunk.data

                if message == DC_CHUNK_START_SIGN:
                    chunks_pending = chunk.idx
                    chunked_msg = [b""] * chunks_pending
                elif chunks_pending:
                    if chunked_msg[chunk.idx] == b"":
                        chunks_pending -= 1
                    chunked_msg[chunk.idx] = message
                    if chunks_pending == 0:
                        await self.consumer(msg=b"".join(chunked_msg))
                else:
                    # Forward all received messages to our own consumer method.
                    await self.consumer(msg=message)

            # Set peer_connection to generate an offer message type.
            await self.peer_connection.setLocalDescription(
                await self.peer_connection.createOffer()
            )

            # Generates the local description structure
            # and serialize it to string afterwards.
            local_description = object_to_string(self.peer_connection.localDescription)

            # Return the Offer local_description payload.
            return local_description
        except Exception as e:
            traceback_and_raise(e)
Example #22
0
 async def send(self, message):
     if not self._javascript_callable or type(message) != str:
         message = object_to_string(message)
     self._webrtc_server.send_message(self._room, self.__peer_id, message)