async def test_audio_wav_ended(self): track = AudioStreamTrack() recorder = MediaRecorder(self.temporary_path("test.wav")) recorder.addTrack(track) await recorder.start() await asyncio.sleep(1) track.stop() await asyncio.sleep(1) await recorder.stop()
def _run(self, robot, options): if not options.cam_ssl_cert: options.cam_ssl_cert = False if options.track == 'video': recorder = MediaRecorder(f'{options.dst_prefix}.mp4') else: recorder = MediaRecorder(f'{options.dst_prefix}.wav') # run event loop loop = asyncio.get_event_loop() loop.run_until_complete(record_webrtc(options, recorder))
async def offer(request): params = await request.json() offer = RTCSessionDescription( sdp=params['sdp'], type=params['type']) pc = RTCPeerConnection() pcs.append(pc) # prepare local media player = MediaPlayer(path=os.path.join(ROOT, 'demo-instruct.wav')) if args.write_audio: recorder = MediaRecorder(path=args.write_audio) else: recorder = MediaBlackhole() @pc.on('datachannel') def on_datachannel(channel): @channel.on('message') def on_message(message): channel.send('pong') @pc.on('track') def on_track(track): print('Track %s received' % track.kind) if track.kind == 'audio': pc.addTrack(player.audio) recorder.addTrack(track) elif track.kind == 'video': local_video = VideoTransformTrack(track, transform=params['video_transform']) pc.addTrack(local_video) @track.on('ended') def on_ended(): print('Track %s ended' % track.kind) recorder.stop() player.stop() await pc.setRemoteDescription(offer) answer = await pc.createAnswer() await pc.setLocalDescription(answer) player.start() recorder.start() return web.Response( content_type='application/json', text=json.dumps({ 'sdp': pc.localDescription.sdp, 'type': pc.localDescription.type }))
def test_audio_and_video(self): recorder = MediaRecorder(path='foo.mp4') recorder.addTrack(AudioStreamTrack()) recorder.addTrack(VideoStreamTrack()) recorder.start() run(asyncio.sleep(2)) recorder.stop()
async def test_audio_wav(self): path = self.temporary_path("test.wav") 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.assertEqual(container.streams[0].codec.name, "pcm_s16le") self.assertGreater( float(container.streams[0].duration * container.streams[0].time_base), 0)
async def run_answer(pc, signaling): done = asyncio.Event() recorder = MediaRecorder(path=OUTPUT_PATH) @pc.on('track') def on_track(track): print('Receiving video') assert track.kind == 'video' recorder.addTrack(track) recorder.start() @track.on('ended') def on_ended(): recorder.stop() done.set() # receive offer offer = await signaling.receive() await pc.setRemoteDescription(offer) # send answer await pc.setLocalDescription(await pc.createAnswer()) await signaling.send(pc.localDescription) # wait for completion await done.wait()
async def test_video_mp4_uhd(self): path = self.temporary_path("test.mp4") recorder = MediaRecorder(path) recorder.addTrack(VideoStreamTrackUhd()) 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.assertEqual(container.streams[0].codec.name, "h264") self.assertGreater( float(container.streams[0].duration * container.streams[0].time_base), 0) self.assertEqual(container.streams[0].width, 3840) self.assertEqual(container.streams[0].height, 2160)
async def offer(request): params = await request.json() offer = RTCSessionDescription(sdp=params["sdp"], type=params["type"]) pc = RTCPeerConnection() pc_id = "PeerConnection(%s)" % uuid.uuid4() pcs.add(pc) def log_info(msg, *args): logger.info(pc_id + " " + msg, *args) log_info("Created for %s", request.remote) # prepare local media player = MediaPlayer("alsa_input.pci-0000_00_1f.3.analog-stereo", format="pulse") recorder = MediaRecorder("alsa_output.pci-0000_00_1f.3.analog-stereo", format="pulse") @pc.on("datachannel") def on_datachannel(channel): @channel.on("message") def on_message(message): if isinstance(message, str) and message.startswith("ping"): channel.send("pong" + message[4:]) @pc.on("iceconnectionstatechange") async def on_iceconnectionstatechange(): log_info("ICE connection state is %s", pc.iceConnectionState) if pc.iceConnectionState == "failed": await pc.close() pcs.discard(pc) @pc.on("track") def on_track(track): log_info("Track %s received", track.kind) if track.kind == "audio": pc.addTrack(player.audio) recorder.addTrack(track) @track.on("ended") async def on_ended(): log_info("Track %s ended", track.kind) await recorder.stop() # handle offer await pc.setRemoteDescription(offer) await recorder.start() # send answer answer = await pc.createAnswer() await pc.setLocalDescription(answer) return web.Response( content_type="application/json", text=json.dumps( {"sdp": pc.localDescription.sdp, "type": pc.localDescription.type} ), )
async def create_connection(is_caller=True, desc=None): # def add_tracks(): # if player and player.audio: # print("ADD AUDIO") # pc.addTrack(player.audio) # if player and player.video: # print("ADD VIDEO") # pc.addTrack(player.video) pc = RTCPeerConnection(configuration=RTCConfiguration( iceServers=[RTCIceServer(urls=['stun:stun.l.google.com:19302'])])) player = MediaPlayer("output.wav") recorder = MediaRecorder( '/Users/pjc/Server/webrtc-connection-test/result.wav') pc.addTrack(player.audio) @pc.on("track") def on_track(track): print(f"Track received {track.kind}") if track.kind == "audio": recorder.addTrack(track) @track.on("ended") async def on_ended(): print(f"Track {track.kind} ended") await recorder.stop() @pc.on("datachannel") def on_datachannel(channel): @channel.on("message") def on_message(message): if isinstance(message, str) and message.startswith("ping"): channel.send("pong" + message[4:]) @pc.on('icecandidate') def icecandidate(item): print("icecandidate") @pc.on("iceconnectionstatechange") async def on_iceconnectionstatechange(): print(f"ICE connection state is {pc.iceConnectionState}") if pc.iceConnectionState == "failed": await pc.close() if is_caller: print("createOffer With Bind") sd = await pc.createOffer() await pc.setLocalDescription(sd) await recorder.start() else: print("Bind Offer With Create Answer") await pc.setRemoteDescription(desc) sd = await pc.createAnswer() await pc.setLocalDescription(sd) await recorder.start() return pc.localDescription, pc, recorder
async def offer(request): params = await request.json() offer = RTCSessionDescription(sdp=params['sdp'], type=params['type']) pc = RTCPeerConnection() pcs.add(pc) # prepare local media player = MediaPlayer(os.path.join(ROOT, 'demo-instruct.wav')) if args.write_audio: recorder = MediaRecorder(args.write_audio) else: recorder = MediaBlackhole() @pc.on('datachannel') def on_datachannel(channel): @channel.on('message') def on_message(message): if isinstance(message, str) and message.startswith('ping'): channel.send('pong' + message[4:]) @pc.on('iceconnectionstatechange') async def on_iceconnectionstatechange(): print('ICE connection state is %s' % pc.iceConnectionState) if pc.iceConnectionState == 'failed': await pc.close() pcs.discard(pc) @pc.on('track') def on_track(track): print('Track %s received' % track.kind) if track.kind == 'audio': pc.addTrack(player.audio) recorder.addTrack(track) elif track.kind == 'video': local_video = VideoTransformTrack( track, transform=params['video_transform']) pc.addTrack(local_video) @track.on('ended') async def on_ended(): print('Track %s ended' % track.kind) await recorder.stop() # handle offer await pc.setRemoteDescription(offer) await recorder.start() # send answer answer = await pc.createAnswer() await pc.setLocalDescription(answer) return web.Response(content_type='application/json', text=json.dumps({ 'sdp': pc.localDescription.sdp, 'type': pc.localDescription.type }))
async def offer(request): params = await request.json() offer = RTCSessionDescription(sdp=params['sdp'], type=params['type']) pc = RTCPeerConnection() pcs.add(pc) # prepare local media player = MediaPlayer(os.path.join(ROOT, 'demo-instruct.wav')) if args.write_audio: recorder = MediaRecorder(args.write_audio) else: recorder = MediaBlackhole() @pc.on('datachannel') async def on_datachannel(channel): closed = asyncio.Event() queue = asyncio.Queue() print("Channel opened") @channel.on('close') def on_close(): print("Channel closed") closed.set() @channel.on('message') async def on_message(message): await queue.put(message) #channel.send(message) print(message) await cloud_browser(channel, closed, queue) @pc.on('iceconnectionstatechange') async def on_iceconnectionstatechange(): print('ICE connection state is %s' % pc.iceConnectionState) if pc.iceConnectionState == 'failed': await pc.close() pcs.discard(pc) # handle offer await pc.setRemoteDescription(offer) await recorder.start() # send answer answer = await pc.createAnswer() await pc.setLocalDescription(answer) return web.Response(content_type='application/json', text=json.dumps({ 'sdp': pc.localDescription.sdp, 'type': pc.localDescription.type }))
def test_audio_and_video(self): recorder = MediaRecorder(self.temporary_path('test.mp4')) recorder.addTrack(AudioStreamTrack()) recorder.addTrack(VideoStreamTrack()) run(recorder.start()) run(asyncio.sleep(2)) run(recorder.stop())
async def offer(request): params = await request.json() offer = RTCSessionDescription(sdp=params["sdp"], type=params["type"]) pc = RTCPeerConnection() # pc_id = "PeerConnection(%s)" % uuid.uuid4() pcs.add(pc) # def log_info(msg, *args): # logger.info(pc_id + " " + msg, *args) # # log_info("Created for %s", request.remote) # prepare local media if args.write_audio: recorder = MediaRecorder(args.write_audio) else: recorder = MediaBlackhole() @pc.on("track") def on_track(track): # log_info("Track %s received", track.kind) local_video = VideoTransformTrack(track, powidth=params["powidth"], poheight=params["poheight"], powidth2=params["powidth2"], poheight2=params["poheight2"]) pc.addTrack(local_video) @track.on("ended") async def on_ended(): # log_info("Track %s ended", track.kind) await recorder.stop() # handle offer await pc.setRemoteDescription(offer) await recorder.start() # send answer answer = await pc.createAnswer() await pc.setLocalDescription(answer) return web.Response( content_type="application/json", text=json.dumps({ "sdp": pc.localDescription.sdp, "type": pc.localDescription.type }), )
async def offer(request): params = await request.json() offer = RTCSessionDescription( sdp=params['sdp'], type=params['type']) pc = RTCPeerConnection() pcs.add(pc) # prepare local media player = MediaPlayer('hw:1', format='alsa', options={'channels': '1'}) recorder = MediaRecorder('plughw:0,0', format='alsa') @pc.on('iceconnectionstatechange') async def on_iceconnectionstatechange(): print('ICE connection state is %s' % pc.iceConnectionState) if pc.iceConnectionState == 'failed': await pc.close() pcs.discard(pc) @pc.on('track') def on_track(track): print('Track %s received' % track.kind) pc.addTrack(player.audio) recorder.addTrack(track) @track.on('ended') async def on_ended(): print('Track %s ended' % track.kind) await recorder.stop() # handle offer await pc.setRemoteDescription(offer) await recorder.start() # send answer answer = await pc.createAnswer() await pc.setLocalDescription(answer) return web.Response( content_type='application/json', text=json.dumps({ 'sdp': pc.localDescription.sdp, 'type': pc.localDescription.type }))
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_mp3(self): path = self.temporary_path("test.mp3") 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.assertIn(container.streams[0].codec.name, ("mp3", "mp3float")) self.assertGreater( float(container.streams[0].duration * container.streams[0].time_base), 0 )
def start_peer(room=None, signaling_folder=None, play_from=None, record_to=None, frame_transformer=None, verbose=False, ice_servers=None, multiprocess=False): if verbose: logging.basicConfig(level=logging.DEBUG) else: logging.basicConfig(level=logging.INFO) if ice_servers: logger.debug('Using ICE servers:', ice_servers) servers = [RTCIceServer(*server) if type(server) == tuple else RTCIceServer(server) for server in ice_servers] pc = RTCPeerConnection( configuration=RTCConfiguration(servers)) else: pc = RTCPeerConnection() # room = str(room) if signaling_folder: signaling = ColabSignaling(signaling_folder=signaling_folder, room=room) else: signaling = ColabApprtcSignaling(room=room) # create media source if play_from: player = MediaPlayer(play_from) else: player = None # create media sink if record_to: recorder = MediaRecorder(record_to) else: recorder = MediaBlackhole() if multiprocess: p = Process(target=run_process, args=(pc, player, recorder, signaling, frame_transformer)) p.start() return signaling.room, p else: run_process(pc, player, recorder, signaling, frame_transformer) return signaling.room, None
def test_video_png(self): path = self.temporary_path("test-%3d.png") recorder = MediaRecorder(path) 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), 1) self.assertEqual(container.streams[0].codec.name, "png") self.assertGreater( float(container.streams[0].duration * container.streams[0].time_base), 0 ) self.assertEqual(container.streams[0].width, 640) self.assertEqual(container.streams[0].height, 480)
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)
async def accept(self, port, segment_time, server=None, turn=None): ice_servers = [RTCIceServer('stun:stun.l.google.com:19302')] if turn: ice_servers.append(turn) config = RTCConfiguration(ice_servers) self.pc = RTCPeerConnection(config) if server: self.signaling = WebSocketClient(server, port) else: self.signaling = WebSocketServer(port) recorder_options = { "segment_time": segment_time, "reset_timestamps": "1", "strftime": "1", } self.recorder = MediaRecorder('video/%Y-%m-%d_%H-%M-%S.mkv', format="segment", options=recorder_options) async def send_answer(): logger.debug(f"Ice Gathering State: {self.pc.iceGatheringState}") # отправка происходит если были собраны все IceCandidate if self.pc.iceGatheringState == 'complete': logger.debug("Answer sent") await self.signaling.send_data({ "sdp": self.pc.localDescription.sdp, "type": self.pc.localDescription.type }) else: # если IceCandidate не собраны, то ожидается их сбор self.pc.once("icegatheringstatechange", send_answer) @self.signaling.on_message async def on_message(message): logger.debug(f"{message.get('type')} received") if message.get("type") == "offer": offer = RTCSessionDescription(sdp=message["sdp"], type=message["type"]) await self.pc.setRemoteDescription(offer) answer = await self.pc.createAnswer() await self.pc.setLocalDescription(answer) await send_answer() @self.pc.on("connectionstatechange") async def on_connectionstatechange(): if self.pc.connectionState == "failed": await self.pc.close() elif self.pc.connectionState == "connected": await self.recorder.start() elif self.pc.connectionState == "closed": await self.recorder.stop() logger.info("Recorder closed") logger.info(f"Connection state: {self.pc.connectionState}") @self.pc.on("track") async def on_track(track): if track.kind == "audio": self.recorder.addTrack(track) elif track.kind == "video": self.__video = track self.recorder.addTrack( FixedPtsTrack(MediaRelay().subscribe(track))) logger.info(f"Track {track.kind} added") @track.on("ended") async def on_ended(): await self.recorder.stop() logger.info(f"Track {track.kind} ended")
def test_video_png(self): recorder = MediaRecorder(self.temporary_path('test-%3d.png')) recorder.addTrack(VideoStreamTrack()) run(recorder.start()) run(asyncio.sleep(2)) run(recorder.stop())
def out_recorder_factory() -> MediaRecorder: return MediaRecorder("output.flv", format="flv")
def test_video_jpg(self): recorder = MediaRecorder(path='foo-%3d.jpg') recorder.addTrack(VideoStreamTrack()) recorder.start() run(asyncio.sleep(2)) recorder.stop()
def test_audio_wav(self): recorder = MediaRecorder(self.temporary_path('test.wav')) recorder.addTrack(AudioStreamTrack()) run(recorder.start()) run(asyncio.sleep(2)) run(recorder.stop())
def in_recorder_factory() -> MediaRecorder: return MediaRecorder( "input.flv", format="flv" ) # HLS does not work. See https://github.com/aiortc/aiortc/issues/331
async def offer(request): params = await request.json() offer = RTCSessionDescription(sdp=params["sdp"], type=params["type"]) pc = RTCPeerConnection() pc_id = "PeerConnection(%s)" % uuid.uuid4() pcs.add(pc) def log_info(msg, *args): logger.info(pc_id + " " + msg, *args) log_info("Created for %s", request.remote) # prepare local media player = MediaPlayer(os.path.join(ROOT, "demo-instruct.wav")) if args.write_audio: recorder = MediaRecorder(args.write_audio) else: recorder = MediaBlackhole() @pc.on("datachannel") def on_datachannel(channel): @channel.on("message") def on_message(message): if isinstance(message, str) and message.startswith("ping"): channel.send("pong" + message[4:]) @pc.on("iceconnectionstatechange") async def on_iceconnectionstatechange(): log_info("ICE connection state is %s", pc.iceConnectionState) if pc.iceConnectionState == "failed": await pc.close() pcs.discard(pc) @pc.on("track") def on_track(track): log_info("Track %s received", track.kind) if track.kind == "audio": pc.addTrack(player.audio) recorder.addTrack(track) elif track.kind == "video": local_video = VideoTransformTrack( track, transform=params["video_transform"]) pc.addTrack(local_video) @track.on("ended") async def on_ended(): log_info("Track %s ended", track.kind) await recorder.stop() # handle offer await pc.setRemoteDescription(offer) await recorder.start() # send answer answer = await pc.createAnswer() await pc.setLocalDescription(answer) return web.Response( content_type="application/json", text=json.dumps({ "sdp": pc.localDescription.sdp, "type": pc.localDescription.type }), )
parser.add_argument('role', choices=['offer', 'answer']) parser.add_argument('--record-to', help='Write received media to a file.'), parser.add_argument('--verbose', '-v', action='count') add_signaling_arguments(parser) args = parser.parse_args() if args.verbose: logging.basicConfig(level=logging.DEBUG) # create signaling and peer connection signaling = create_signaling(args) pc = RTCPeerConnection() # create media sink if args.record_to: recorder = MediaRecorder(args.record_to) else: recorder = MediaBlackhole() # run event loop loop = asyncio.get_event_loop() try: loop.run_until_complete(run( pc=pc, recorder=recorder, role=args.role, signaling=signaling)) except KeyboardInterrupt: pass finally: # cleanup
def test_audio_wav(self): recorder = MediaRecorder(path='foo.wav') recorder.addTrack(AudioStreamTrack()) recorder.start() run(asyncio.sleep(2)) recorder.stop()
parser.add_argument("--play-from", help="Read the media from a file and sent it.") parser.add_argument("--record-to", help="Write received media to a file.") args = parser.parse_args() if not args.room: args.room = secrets.token_urlsafe(8).lower() peerId = secrets.token_urlsafe(8).lower() uri = f'wss://v3demo.mediasoup.org:4443/?roomId={args.room}&peerId={peerId}' if args.play_from: player = MediaPlayer(args.play_from) else: player = None # create media sink if args.record_to: recorder = MediaRecorder(args.record_to) else: recorder = MediaBlackhole() # run event loop loop = asyncio.get_event_loop() try: demo = Demo(uri=uri, player=player, recorder=recorder) loop.run_until_complete(demo.run()) except KeyboardInterrupt: pass finally: loop.run_until_complete(demo.close())
async def join_room(room, play_from, record_to): # fetch room parameters async with aiohttp.ClientSession() as session: async with session.post('https://appr.tc/join/' + room) as response: # we cannot use response.json() due to: # https://github.com/webrtc/apprtc/issues/562 data = json.loads(await response.text()) assert data['result'] == 'SUCCESS' params = data['params'] # create peer conection pc = RTCPeerConnection() # setup media source if play_from: player = MediaPlayer(play_from) else: player = None 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(VideoImageTrack()) # setup media sink if record_to: recorder = MediaRecorder(record_to) else: recorder = MediaBlackhole() @pc.on('track') def on_track(track): print('Track %s received' % track.kind) recorder.addTrack(track) def on_ended(): print('Track %s ended' % track.kind) # connect to websocket and join signaling = Signaling() await signaling.connect(params) await signaling.send({ 'clientid': params['client_id'], 'cmd': 'register', 'roomid': params['room_id'], }) if params['is_initiator'] == 'true': # send offer await pc.setLocalDescription(await pc.createOffer()) await signaling.send_message(description_to_dict(pc.localDescription)) print('Please point a browser at %s' % params['room_link']) # receive 60s of media try: await asyncio.wait_for(consume_signaling( signaling, pc, player, recorder, params), timeout=60) except asyncio.TimeoutError: pass # shutdown print('Shutting down') await signaling.send_message({'type': 'bye'}) await pc.close()