[Python] Reproduzir áudio em tempo real com aiortc com Python

Discussão em 'Python' iniciado por Stack, Setembro 11, 2024.

  1. Stack

    Stack Membro Participativo

    Escrevi um código em python utilizando a biblioteca aiortc, o código recebe no on_track o áudio envio pelo navegador e reproduzir o áudio diretamente no python.

    No código atual, o áudio fica com ruído.

    import argparse
    import asyncio
    import logging
    from aiohttp import web
    from aiortc import MediaStreamTrack, RTCPeerConnection, RTCSessionDescription
    from aiortc.contrib.media import MediaRecorder
    import os
    import aiohttp_cors
    import uuid
    import json
    import pyaudio # Biblioteca para reprodução de áudio em tempo real com PyAudio
    from av import AudioFrame

    ROOT = os.path.dirname(__file__)
    logger = logging.getLogger("pc")
    pcs = set()

    # Inicializa o PyAudio
    audio = pyaudio.PyAudio()

    # Configuração do PyAudio
    # Parâmetros do stream de áudio
    FORMAT = pyaudio.paInt16
    CHANNELS = 1
    RATE = 44100
    CHUNK = 1024

    # Função para abrir o stream de áudio
    def open_stream():
    return audio.open(
    format=FORMAT,
    channels=CHANNELS,
    rate=RATE,
    output=True,
    frames_per_buffer=CHUNK
    )


    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)

    recorder = MediaRecorder('temp.wav')

    def log_info(msg, *args):
    logger.info(pc_id + " " + msg, *args)

    log_info("Created for %s", request.remote)

    @pc.on("datachannel")
    def on_datachannel(channel):
    @channel.on("message")
    def on_message(message):
    if (message.startswith('command:')):
    command = message[8:]
    log_info("Command received: %s", command)

    if (command == "move_forward"):
    log_info("Move Forward")

    if isinstance(message, str) and message.startswith("ping"):
    channel.send("pong" + message[4:])

    @pc.on("connectionstatechange")
    async def on_connectionstatechange():
    log_info("Connection state is %s", pc.connectionState)
    if pc.connectionState == "failed":
    await pc.close()
    pcs.discard(pc)

    @pc.on("track")
    async def on_track(track):
    log_info("Track %s received", track.kind)

    if (track.kind == "audio"):
    log_info("Audio received")
    # Cria o stream de áudio
    # Cria o stream de áudio
    stream = open_stream()

    @track.on("ended")
    async def on_ended():
    log_info("Track %s ended", track.kind)
    stream.stop_stream()
    stream.close()

    async def play_audio():
    while True:
    try:
    # Recebe um frame de áudio
    frame = await track.recv()

    # Obtenha os dados brutos do frame
    samples = frame.to_ndarray() # Ajuste o formato conforme necessário

    # Envia os dados para o stream de áudio
    stream.write(samples.tobytes())
    except Exception as e:
    log_info(f"Exception in play_audio: {e}")
    break

    asyncio.create_task(play_audio())

    # 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 on_shutdown(app):
    # close peer connections
    coros = [pc.close() for pc in pcs]
    await asyncio.gather(*coros)
    pcs.clear()

    if __name__ == "__main__":

    parser = argparse.ArgumentParser(
    description="WebRTC audio / video / data-channels demo"
    )
    parser.add_argument(
    "--host", default="0.0.0.0", help="Host for HTTP server (default: 0.0.0.0)"
    )
    parser.add_argument(
    "--port", type=int, default=8080, help="Port for HTTP server (default: 8080)"
    )
    parser.add_argument("--verbose", "-v", action="count")
    args = parser.parse_args()

    if args.verbose:
    logging.basicConfig(level=logging.DEBUG)
    else:
    logging.basicConfig(level=logging.INFO)

    app = web.Application()
    cors = aiohttp_cors.setup(app)
    app.on_shutdown.append(on_shutdown)

    resource = cors.add(app.router.add_resource("/offer"))
    route = cors.add(
    resource.add_route("POST", offer), {
    "*": aiohttp_cors.ResourceOptions(
    allow_credentials=True,
    expose_headers=("X-Custom-Server-Header",),
    allow_headers=("X-Requested-With", "Content-Type"),
    max_age=3600,
    )
    })

    #app.router.add_post("/offer", offer)
    web.run_app(
    app, access_log=None, host=args.host, port=args.port
    )

    Continue reading...

Compartilhe esta Página