def test_audio_stop_source(self): source = AudioStreamTrack() relay = MediaRelay() proxy1 = relay.subscribe(source) proxy2 = relay.subscribe(source) # read some frames samples_per_frame = 160 for pts in range(0, 2 * samples_per_frame, samples_per_frame): frame1, frame2 = run(asyncio.gather(proxy1.recv(), proxy2.recv())) self.assertEqual(frame1.format.name, "s16") self.assertEqual(frame1.layout.name, "mono") self.assertEqual(frame1.pts, pts) self.assertEqual(frame1.samples, samples_per_frame) self.assertEqual(frame2.format.name, "s16") self.assertEqual(frame2.layout.name, "mono") self.assertEqual(frame2.pts, pts) self.assertEqual(frame2.samples, samples_per_frame) # stop source track source.stop() # continue reading run(asyncio.gather(proxy1.recv(), proxy2.recv())) for i in range(2): exc1, exc2 = run( asyncio.gather(proxy1.recv(), proxy2.recv(), return_exceptions=True) ) self.assertTrue(isinstance(exc1, MediaStreamError)) self.assertTrue(isinstance(exc2, MediaStreamError))
def test_track_ended(self): track = AudioStreamTrack() sender = RTCRtpSender(track, self.local_transport) run(sender.send(RTCRtpParameters(codecs=[PCMU_CODEC]))) track.stop() run(asyncio.sleep(0.5))
def test_track_ended(self): track = AudioStreamTrack() sender = RTCRtpSender(track, self.local_transport) run(sender.send(RTCRtpParameters(codecs=[PCMU_CODEC]))) # stop track and wait for RTP loop to exit track.stop() run(asyncio.sleep(0.1))
async def test_track_ended(self): async with dummy_dtls_transport_pair() as (local_transport, _): track = AudioStreamTrack() sender = RTCRtpSender(track, local_transport) await sender.send(RTCRtpParameters(codecs=[PCMU_CODEC])) # stop track and wait for RTP loop to exit track.stop() await asyncio.sleep(0.1)
def test_track_ended(self): transport, _ = dummy_dtls_transport_pair() track = AudioStreamTrack() sender = RTCRtpSender(track, transport) run(sender.send(RTCRtpParameters(codecs=[PCMU_CODEC]))) track.stop() run(asyncio.sleep(0.5)) run(transport.stop())
def test_audio_wav_ended(self): track = AudioStreamTrack() recorder = MediaRecorder(self.temporary_path("test.wav")) recorder.addTrack(track) run(recorder.start()) run(asyncio.sleep(1)) track.stop() run(asyncio.sleep(1)) run(recorder.stop())
def test_audio_ended(self): track = AudioStreamTrack() recorder = MediaBlackhole() recorder.addTrack(track) run(recorder.start()) run(asyncio.sleep(1)) track.stop() run(asyncio.sleep(1)) run(recorder.stop())
async def test_audio_slow_consumer(self): source = AudioStreamTrack() relay = MediaRelay() proxy1 = relay.subscribe(source, buffered=False) proxy2 = relay.subscribe(source, buffered=False) # read some frames samples_per_frame = 160 for pts in range(0, 2 * samples_per_frame, samples_per_frame): frame1, frame2 = await asyncio.gather(proxy1.recv(), proxy2.recv()) self.assertEqual(frame1.format.name, "s16") self.assertEqual(frame1.layout.name, "mono") self.assertEqual(frame1.pts, pts) self.assertEqual(frame1.samples, samples_per_frame) self.assertEqual(frame2.format.name, "s16") self.assertEqual(frame2.layout.name, "mono") self.assertEqual(frame2.pts, pts) self.assertEqual(frame2.samples, samples_per_frame) # skip some frames timestamp = 5 * samples_per_frame await asyncio.sleep(source._start + (timestamp / 8000) - time.time()) frame1, frame2 = await asyncio.gather(proxy1.recv(), proxy2.recv()) self.assertEqual(frame1.format.name, "s16") self.assertEqual(frame1.layout.name, "mono") self.assertEqual(frame1.pts, 5 * samples_per_frame) self.assertEqual(frame1.samples, samples_per_frame) self.assertEqual(frame2.format.name, "s16") self.assertEqual(frame2.layout.name, "mono") self.assertEqual(frame2.pts, 5 * samples_per_frame) self.assertEqual(frame2.samples, samples_per_frame) # stop a consumer proxy1.stop() # continue reading for i in range(2): exc1, frame2 = await asyncio.gather(proxy1.recv(), proxy2.recv(), return_exceptions=True) self.assertTrue(isinstance(exc1, MediaStreamError)) self.assertTrue(isinstance(frame2, av.AudioFrame)) # stop source track source.stop()
def test_audio_and_video(self): recorder = MediaBlackhole() recorder.addTrack(AudioStreamTrack()) recorder.addTrack(VideoStreamTrack()) run(recorder.start()) run(asyncio.sleep(2)) run(recorder.stop())
def test_addTrack_video(self): pc = RTCPeerConnection() # add video track video_track = VideoStreamTrack() video_sender = pc.addTrack(video_track) self.assertIsNotNone(video_sender) self.assertEqual(video_sender.track, video_track) self.assertEqual(pc.getSenders(), [video_sender]) # try to add same track again with self.assertRaises(InvalidAccessError) as cm: pc.addTrack(video_track) self.assertEqual(str(cm.exception), 'Track already has a sender') # try adding another video track with self.assertRaises(InternalError) as cm: pc.addTrack(VideoStreamTrack()) self.assertEqual(str(cm.exception), 'Only a single video track is supported for now') # add audio track audio_track = AudioStreamTrack() audio_sender = pc.addTrack(audio_track) self.assertIsNotNone(audio_sender) self.assertEqual(audio_sender.track, audio_track) self.assertEqual(pc.getSenders(), [video_sender, audio_sender])
def __init__(self, uri, player=None, recorder=MediaBlackhole()): self._uri = uri self._player = player self._recorder = recorder # Save answers temporarily self._answers = {} self._websocket = None self._device = None self._tracks = [] if player and player.audio: audioTrack = player.audio else: audioTrack = AudioStreamTrack() if player and player.video: videoTrack = player.video else: videoTrack = VideoStreamTrack() self._videoTrack = videoTrack self._audioTrack = audioTrack self._tracks.append(videoTrack) self._tracks.append(audioTrack) self._sendTransport: Optional[Transport] = None self._recvTransport: Optional[Transport] = None self._producers = [] self._consumers = [] self._tasks = [] self._closed = False
def test_stop(self): sender = RTCRtpSender(AudioStreamTrack(), self.local_transport) self.assertEqual(sender.kind, 'audio') run(sender.send(RTCRtpParameters(codecs=[PCMU_CODEC]))) # clean shutdown run(sender.stop())
def test_setRemoteDescription_unexpected_offer(self): pc = RTCPeerConnection() pc.addTrack(AudioStreamTrack()) offer = run(pc.createOffer()) run(pc.setLocalDescription(offer)) with self.assertRaises(InvalidStateError) as cm: run(pc.setRemoteDescription(RTCSessionDescription(sdp='', type='offer'))) self.assertEqual(str(cm.exception), 'Cannot handle offer in signaling state "have-local-offer"')
async def test_stop(self): async with dummy_dtls_transport_pair() as (local_transport, _): sender = RTCRtpSender(AudioStreamTrack(), local_transport) self.assertEqual(sender.kind, "audio") await sender.send(RTCRtpParameters(codecs=[PCMU_CODEC])) # clean shutdown await sender.stop()
def test_connection_error(self): """ Close the underlying transport before the sender. """ sender = RTCRtpSender(AudioStreamTrack(), self.local_transport) self.assertEqual(sender.kind, 'audio') run(sender.send(RTCRtpParameters(codecs=[PCMU_CODEC]))) run(self.local_transport.stop())
async def test_connection_error(self): """ Close the underlying transport before the sender. """ async with dummy_dtls_transport_pair() as (local_transport, _): sender = RTCRtpSender(AudioStreamTrack(), local_transport) self.assertEqual(sender.kind, "audio") await sender.send(RTCRtpParameters(codecs=[PCMU_CODEC])) await local_transport.stop()
def test_connection_error(self): transport, _ = dummy_transport_pair() encoder = PcmuEncoder() sender = RTCRtpSender(kind='audio') sender._track = AudioStreamTrack() run( asyncio.gather( sender._run(transport=transport, encoder=encoder, payload_type=0), transport.close()))
def test_connection_error(self): """ Close the underlying transport before the sender. """ transport, _ = dummy_dtls_transport_pair() sender = RTCRtpSender(AudioStreamTrack(), transport) self.assertEqual(sender.kind, 'audio') self.assertEqual(sender.transport, transport) run(asyncio.gather(sender._run(codec=PCMU_CODEC), transport.close()))
def test_stop(self): transport, _ = dummy_dtls_transport_pair() sender = RTCRtpSender(AudioStreamTrack(), transport) self.assertEqual(sender.kind, 'audio') self.assertEqual(sender.transport, transport) run(sender.send(RTCRtpParameters(codecs=[PCMU_CODEC]))) # clean shutdown run(sender.stop())
def test_addTrack_audio(self): pc = RTCPeerConnection() # add audio track track = AudioStreamTrack() sender = pc.addTrack(track) self.assertIsNotNone(sender) self.assertEqual(sender.track, track) self.assertEqual(pc.getSenders(), [sender]) self.assertEqual(len(pc.getTransceivers()), 1) # try to add same track again with self.assertRaises(InvalidAccessError) as cm: pc.addTrack(track) self.assertEqual(str(cm.exception), 'Track already has a sender') # try adding another audio track with self.assertRaises(InternalError) as cm: pc.addTrack(AudioStreamTrack()) self.assertEqual(str(cm.exception), 'Only a single audio track is supported for now')
def test_connection_error(self): """ Close the underlying transport before the sender. """ transport, _ = dummy_dtls_transport_pair() sender = RTCRtpSender(AudioStreamTrack(), transport) self.assertEqual(sender.kind, 'audio') self.assertEqual(sender.transport, transport) run(sender.send(RTCRtpParameters(codecs=[PCMU_CODEC]))) run(transport.stop())
def test_audio_wav(self): path = self.temporary_path("test.wav") recorder = MediaRecorder(path) recorder.addTrack(AudioStreamTrack()) run(recorder.start()) run(asyncio.sleep(2)) run(recorder.stop()) # check output media container = av.open(path, "r") self.assertEqual(len(container.streams), 1) self.assertEqual(container.streams[0].codec.name, "pcm_s16le") self.assertGreater( float(container.streams[0].duration * container.streams[0].time_base), 0 )
async def test_audio_mp3(self): path = self.temporary_path("test.mp3") recorder = MediaRecorder(path) recorder.addTrack(AudioStreamTrack()) await recorder.start() await asyncio.sleep(2) await recorder.stop() # check output media container = av.open(path, "r") self.assertEqual(len(container.streams), 1) self.assertIn(container.streams[0].codec.name, ("mp3", "mp3float")) self.assertGreater( float(container.streams[0].duration * container.streams[0].time_base), 0)
def test_audio_and_video(self): path = self.temporary_path("test.mp4") recorder = MediaRecorder(path) recorder.addTrack(AudioStreamTrack()) recorder.addTrack(VideoStreamTrack()) run(recorder.start()) run(asyncio.sleep(2)) run(recorder.stop()) # check output media container = av.open(path, "r") self.assertEqual(len(container.streams), 2) self.assertEqual(container.streams[0].codec.name, "aac") self.assertGreater( float(container.streams[0].duration * container.streams[0].time_base), 0 ) self.assertEqual(container.streams[1].codec.name, "h264") self.assertEqual(container.streams[1].width, 640) self.assertEqual(container.streams[1].height, 480) self.assertGreater( float(container.streams[1].duration * container.streams[1].time_base), 0 )
from pymediasoup.rtp_parameters import RtpCapabilities, RtpParameters from pymediasoup.sctp_parameters import SctpCapabilities, SctpStreamParameters from pymediasoup.transport import Transport from pymediasoup.models.transport import DtlsParameters from pymediasoup.producer import Producer from pymediasoup.data_producer import DataProducer from pymediasoup.data_consumer import DataConsumer from pymediasoup.errors import UnsupportedError from pymediasoup.consumer import Consumer from .fake_parameters import generateRouterRtpCapabilities, generateTransportRemoteParameters, generateConsumerRemoteParameters, generateDataProducerRemoteParameters, generateDataConsumerRemoteParameters from .fake_handler import FakeHandler logging.basicConfig(level=logging.DEBUG) audioTrack = AudioStreamTrack() videoTrack = VideoStreamTrack() TRACKS = [videoTrack, audioTrack] class TestMethods(unittest.IsolatedAsyncioTestCase): def test_create_device(self): device = Device(handlerFactory=AiortcHandler.createFactory( tracks=TRACKS)) self.assertEqual(device.loaded, False) async def test_device_load(self): device = Device(handlerFactory=AiortcHandler.createFactory( tracks=TRACKS)) await device.load(generateRouterRtpCapabilities()) self.assertEqual(device.handlerName, 'aiortc')
async def test_audio(self): recorder = MediaBlackhole() recorder.addTrack(AudioStreamTrack()) await recorder.start() await asyncio.sleep(1) await recorder.stop()
def test_addTrack_closed(self): pc = RTCPeerConnection() run(pc.close()) with self.assertRaises(InvalidStateError) as cm: pc.addTrack(AudioStreamTrack()) self.assertEqual(str(cm.exception), 'RTCPeerConnection is closed')
def test_connect_audio_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(AudioStreamTrack()) offer = run(pc1.createOffer()) self.assertEqual(offer.type, 'offer') self.assertTrue('m=audio ' 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=audio ' 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(AudioStreamTrack()) answer = run(pc2.createAnswer()) self.assertEqual(answer.type, 'answer') self.assertTrue('m=audio ' 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=audio ' 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'])
def test_stop_before_send(self): transport, _ = dummy_dtls_transport_pair() sender = RTCRtpSender(AudioStreamTrack(), transport) run(sender.stop())
def test_stop_before_send(self): sender = RTCRtpSender(AudioStreamTrack(), self.local_transport) run(sender.stop())