예제 #1
0
 def test_video(self):
     recorder = MediaBlackhole()
     recorder.addTrack(VideoStreamTrack())
     run(recorder.start())
     run(asyncio.sleep(2))
     run(recorder.stop())
예제 #2
0
async def run(pc, player, session, bitrate=512000, record=False):
    @pc.on('track')
    def on_track(track):
        logger.info(f'Track {track.kind} received')

        @track.on('ended')
        def on_ended():
            print(f'Track {track.kind} ended')

    @pc.on('iceconnectionstatechange')
    def on_ice_state_change():
        # logger.info(f'ICE state changed to {pc.iceConnectionState}')
        pass

    # create session
    await session.create()

    # configure media
    media = {'audio': True, 'video': True}
    if player and player.audio:
        pc.addTrack(player.audio)
    else:
        pc.addTrack(AudioStreamTrack())
    if player and player.video:
        pc.addTrack(player.video)
    else:
        pc.addTrack(VideoStreamTrack())

    # attach to echotest plugin
    plugin = await session.attach('janus.plugin.echotest')

    # create data-channel
    channel = pc.createDataChannel('JanusDataChannel')
    logger.info(f'DataChannel ({channel.label}) created')
    dc_probe_message = 'echo-ping'
    dc_open = False
    dc_probe_received = False

    @channel.on('open')
    def on_open():
        nonlocal dc_open
        dc_open = True
        logger.info(f'DataChannel ({channel.label}) open')
        logger.info(
            f'DataChannel ({channel.label}) sending: {dc_probe_message}')
        channel.send(dc_probe_message)

    @channel.on('close')
    def on_close():
        nonlocal dc_open
        dc_open = False
        logger.info(f'DataChannel ({channel.label}) closed')

    @channel.on('message')
    def on_message(message):
        logger.info(f'DataChannel ({channel.label}) received: {message}')
        if dc_probe_message in message:
            nonlocal dc_probe_received
            dc_probe_received = True

    # send offer
    await pc.setLocalDescription(await pc.createOffer())
    request = {'record': record, 'bitrate': bitrate}
    request.update(media)
    response = await plugin.sendMessage({
        'body': request,
        'jsep': {
            'sdp': pc.localDescription.sdp,
            'trickle': False,
            'type': pc.localDescription.type,
        },
    })
    assert response['plugindata']['data']['result'] == 'ok'

    # apply answer
    answer = RTCSessionDescription(sdp=response['jsep']['sdp'],
                                   type=response['jsep']['type'])
    await pc.setRemoteDescription(answer)

    logger.info('Running for a while...')
    await asyncio.sleep(5)

    # Check WebSocket status
    assert session._websocket.connection.open

    # Get RTC stats and check the status
    rtcstats = await pc.getStats()
    rtp = {'audio': {'in': 0, 'out': 0}, 'video': {'in': 0, 'out': 0}}
    dtls_state = None
    for stat in rtcstats.values():
        if stat.type == 'inbound-rtp':
            rtp[stat.kind]['in'] = stat.packetsReceived
        elif stat.type == 'outbound-rtp':
            rtp[stat.kind]['out'] = stat.packetsSent
        elif stat.type == 'transport':
            dtls_state = stat.dtlsState
    # ICE succeded
    assert pc.iceConnectionState == 'completed'
    # DTLS succeded
    assert dtls_state == 'connected'
    # Janus echoed the sent packets
    assert rtp['audio']['out'] >= rtp['audio']['in'] > 0
    assert rtp['video']['out'] >= rtp['video']['in'] > 0
    # DataChannels worked
    assert dc_open
    assert dc_probe_received

    logger.info('Ending the test now')
예제 #3
0
    def test_connect_video_bidirectional(self):
        pc1 = RTCPeerConnection()
        pc1_states = track_states(pc1)

        pc2 = RTCPeerConnection()
        pc2_states = track_states(pc2)

        self.assertEqual(pc1.iceConnectionState, 'new')
        self.assertEqual(pc1.iceGatheringState, 'new')
        self.assertIsNone(pc1.localDescription)
        self.assertIsNone(pc1.remoteDescription)

        self.assertEqual(pc2.iceConnectionState, 'new')
        self.assertEqual(pc2.iceGatheringState, 'new')
        self.assertIsNone(pc2.localDescription)
        self.assertIsNone(pc2.remoteDescription)

        # create offer
        pc1.addTrack(VideoStreamTrack())
        offer = run(pc1.createOffer())
        self.assertEqual(offer.type, 'offer')
        self.assertTrue('m=video ' in offer.sdp)
        self.assertFalse('a=candidate:' in offer.sdp)

        run(pc1.setLocalDescription(offer))
        self.assertEqual(pc1.iceConnectionState, 'new')
        self.assertEqual(pc1.iceGatheringState, 'complete')
        self.assertTrue('m=video ' in pc1.localDescription.sdp)
        self.assertTrue('a=candidate:' in pc1.localDescription.sdp)
        self.assertTrue('a=sendrecv' in pc1.localDescription.sdp)
        self.assertTrue('a=fingerprint:sha-256' in pc1.localDescription.sdp)
        self.assertTrue('a=setup:actpass' in pc1.localDescription.sdp)

        # handle offer
        run(pc2.setRemoteDescription(pc1.localDescription))
        self.assertEqual(pc2.remoteDescription, pc1.localDescription)
        self.assertEqual(len(pc2.getReceivers()), 1)

        # create answer
        pc2.addTrack(VideoStreamTrack())
        answer = run(pc2.createAnswer())
        self.assertEqual(answer.type, 'answer')
        self.assertTrue('m=video ' in answer.sdp)
        self.assertFalse('a=candidate:' in answer.sdp)

        run(pc2.setLocalDescription(answer))
        self.assertEqual(pc2.iceConnectionState, 'checking')
        self.assertEqual(pc2.iceGatheringState, 'complete')
        self.assertTrue('m=video ' in pc2.localDescription.sdp)
        self.assertTrue('a=candidate:' in pc2.localDescription.sdp)
        self.assertTrue('a=sendrecv' in pc1.localDescription.sdp)
        self.assertTrue('a=fingerprint:sha-256' in pc2.localDescription.sdp)
        self.assertTrue('a=setup:active' in pc2.localDescription.sdp)

        # handle answer
        run(pc1.setRemoteDescription(pc2.localDescription))
        self.assertEqual(pc1.remoteDescription, pc2.localDescription)
        self.assertEqual(pc1.iceConnectionState, 'checking')

        # check outcome
        run(asyncio.sleep(1))
        self.assertEqual(pc1.iceConnectionState, 'completed')
        self.assertEqual(pc2.iceConnectionState, 'completed')

        # close
        run(pc1.close())
        run(pc2.close())
        self.assertEqual(pc1.iceConnectionState, 'closed')
        self.assertEqual(pc2.iceConnectionState, 'closed')

        # check state changes
        self.assertEqual(pc1_states['iceConnectionState'],
                         ['new', 'checking', 'completed', 'closed'])
        self.assertEqual(pc1_states['iceGatheringState'],
                         ['new', 'gathering', 'complete'])
        self.assertEqual(pc1_states['signalingState'],
                         ['stable', 'have-local-offer', 'stable', 'closed'])

        self.assertEqual(pc2_states['iceConnectionState'],
                         ['new', 'checking', 'completed', 'closed'])
        self.assertEqual(pc2_states['iceGatheringState'],
                         ['new', 'gathering', 'complete'])
        self.assertEqual(pc2_states['signalingState'],
                         ['stable', 'have-remote-offer', 'stable', 'closed'])
예제 #4
0
    def test_connect_audio_and_video_and_data_channel(self):
        pc1 = RTCPeerConnection()
        pc1_states = track_states(pc1)

        pc2 = RTCPeerConnection()
        pc2_states = track_states(pc2)

        self.assertEqual(pc1.iceConnectionState, 'new')
        self.assertEqual(pc1.iceGatheringState, 'new')
        self.assertIsNone(pc1.localDescription)
        self.assertIsNone(pc1.remoteDescription)

        self.assertEqual(pc2.iceConnectionState, 'new')
        self.assertEqual(pc2.iceGatheringState, 'new')
        self.assertIsNone(pc2.localDescription)
        self.assertIsNone(pc2.remoteDescription)

        # create offer
        pc1.addTrack(AudioStreamTrack())
        pc1.addTrack(VideoStreamTrack())
        pc1.createDataChannel('chat', protocol='bob')
        offer = run(pc1.createOffer())
        self.assertEqual(offer.type, 'offer')
        self.assertTrue('m=audio ' in offer.sdp)
        self.assertTrue('m=video ' in offer.sdp)
        self.assertTrue('m=application ' in offer.sdp)

        run(pc1.setLocalDescription(offer))
        self.assertEqual(pc1.iceConnectionState, 'new')
        self.assertEqual(pc1.iceGatheringState, 'complete')

        # handle offer
        run(pc2.setRemoteDescription(pc1.localDescription))
        self.assertEqual(pc2.remoteDescription, pc1.localDescription)
        self.assertEqual(len(pc2.getSenders()), 2)
        self.assertEqual(len(pc2.getReceivers()), 2)

        # create answer
        pc2.addTrack(AudioStreamTrack())
        pc2.addTrack(VideoStreamTrack())
        answer = run(pc2.createAnswer())
        self.assertEqual(answer.type, 'answer')
        self.assertTrue('m=audio ' in answer.sdp)
        self.assertTrue('m=video ' in answer.sdp)
        self.assertTrue('m=application ' in answer.sdp)

        run(pc2.setLocalDescription(answer))
        self.assertEqual(pc2.iceConnectionState, 'checking')
        self.assertEqual(pc2.iceGatheringState, 'complete')
        self.assertTrue('m=audio ' in pc2.localDescription.sdp)
        self.assertTrue('m=video ' in pc2.localDescription.sdp)
        self.assertTrue('m=application ' in pc2.localDescription.sdp)

        # handle answer
        run(pc1.setRemoteDescription(pc2.localDescription))
        self.assertEqual(pc1.remoteDescription, pc2.localDescription)
        self.assertEqual(pc1.iceConnectionState, 'checking')

        # check outcome
        run(asyncio.sleep(1))
        self.assertEqual(pc1.iceConnectionState, 'completed')
        self.assertEqual(pc2.iceConnectionState, 'completed')

        # check a single transport is used
        self.assertBundled(pc1)
        self.assertBundled(pc2)

        # close
        run(pc1.close())
        run(pc2.close())
        self.assertEqual(pc1.iceConnectionState, 'closed')
        self.assertEqual(pc2.iceConnectionState, 'closed')

        # check state changes
        self.assertEqual(pc1_states['iceConnectionState'],
                         ['new', 'checking', 'completed', 'closed'])
        self.assertEqual(pc1_states['iceGatheringState'], [
            'new', 'gathering', 'new', 'gathering', 'new', 'gathering',
            'complete'
        ])
        self.assertEqual(pc1_states['signalingState'],
                         ['stable', 'have-local-offer', 'stable', 'closed'])

        self.assertEqual(pc2_states['iceConnectionState'],
                         ['new', 'checking', 'completed', 'closed'])
        self.assertEqual(pc2_states['iceGatheringState'],
                         ['new', 'gathering', 'complete'])
        self.assertEqual(pc2_states['signalingState'],
                         ['stable', 'have-remote-offer', 'stable', 'closed'])