From 080f70d91ce65d1c93574f5a12fdcb98a69c1cea Mon Sep 17 00:00:00 2001 From: Filipi Fuchter Date: Tue, 29 Apr 2025 10:32:42 -0300 Subject: [PATCH 1/3] Allowing to define the username and credential for the ice servers. --- .../transports/network/webrtc_connection.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/pipecat/transports/network/webrtc_connection.py b/src/pipecat/transports/network/webrtc_connection.py index 81ece3af7..d21b57cad 100644 --- a/src/pipecat/transports/network/webrtc_connection.py +++ b/src/pipecat/transports/network/webrtc_connection.py @@ -7,7 +7,7 @@ import asyncio import json import time -from typing import Any, Literal, Optional, Union +from typing import Any, List, Literal, Optional, Union from av.frame import Frame from loguru import logger @@ -87,13 +87,21 @@ class SmallWebRTCTrack: return getattr(self._track, name) +# Alias so we don't need to expose RTCIceServer +IceServer = RTCIceServer + + class SmallWebRTCConnection(BaseObject): - def __init__(self, ice_servers=None): + def __init__(self, ice_servers: Optional[Union[List[str], List[IceServer]]] = None): super().__init__() - if ice_servers: - self.ice_servers = [RTCIceServer(urls=server) for server in ice_servers] + if not ice_servers: + self.ice_servers: List[IceServer] = [] + elif all(isinstance(s, IceServer) for s in ice_servers): + self.ice_servers = ice_servers + elif all(isinstance(s, str) for s in ice_servers): + self.ice_servers = [IceServer(urls=s) for s in ice_servers] else: - self.ice_servers = [] + raise TypeError("ice_servers must be either List[str] or List[RTCIceServer]") self._connect_invoked = False self._track_map = {} self._track_getters = { From d1ab1d38b79e2e2409b4cf133b573a74144ad7a2 Mon Sep 17 00:00:00 2001 From: Filipi Fuchter Date: Tue, 29 Apr 2025 10:33:19 -0300 Subject: [PATCH 2/3] Fixing the examples to use the new IceServer structure. --- examples/foundational/run.py | 8 ++++++-- examples/p2p-webrtc/daily-interop-bridge/server.py | 8 ++++++-- examples/p2p-webrtc/video-transform/server/server.py | 8 ++++++-- examples/p2p-webrtc/voice-agent/server.py | 11 +++++++++-- 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/examples/foundational/run.py b/examples/foundational/run.py index fc8b631b4..e7012c9e9 100644 --- a/examples/foundational/run.py +++ b/examples/foundational/run.py @@ -20,7 +20,7 @@ from fastapi.responses import RedirectResponse from loguru import logger from pipecat_ai_small_webrtc_prebuilt.frontend import SmallWebRTCPrebuiltUI -from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection +from pipecat.transports.network.webrtc_connection import IceServer, SmallWebRTCConnection # Load environment variables load_dotenv(override=True) @@ -30,7 +30,11 @@ app = FastAPI() # Store connections by pc_id pcs_map: Dict[str, SmallWebRTCConnection] = {} -ice_servers = ["stun:stun.l.google.com:19302"] +ice_servers = [ + IceServer( + urls="stun:stun.l.google.com:19302", + ) +] # Mount the frontend at / app.mount("/client", SmallWebRTCPrebuiltUI) diff --git a/examples/p2p-webrtc/daily-interop-bridge/server.py b/examples/p2p-webrtc/daily-interop-bridge/server.py index d65bd3013..0025b3490 100644 --- a/examples/p2p-webrtc/daily-interop-bridge/server.py +++ b/examples/p2p-webrtc/daily-interop-bridge/server.py @@ -18,7 +18,7 @@ from fastapi.responses import RedirectResponse from loguru import logger from pipecat_ai_small_webrtc_prebuilt.frontend import SmallWebRTCPrebuiltUI -from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection +from pipecat.transports.network.webrtc_connection import IceServer, SmallWebRTCConnection # Load environment variables load_dotenv(override=True) @@ -28,7 +28,11 @@ app = FastAPI() # Store connections by pc_id pcs_map: Dict[str, SmallWebRTCConnection] = {} -ice_servers = ["stun:stun.l.google.com:19302"] +ice_servers = [ + IceServer( + urls="stun:stun.l.google.com:19302", + ) +] # Mount the frontend at / app.mount("/prebuilt", SmallWebRTCPrebuiltUI) diff --git a/examples/p2p-webrtc/video-transform/server/server.py b/examples/p2p-webrtc/video-transform/server/server.py index d65bd3013..0025b3490 100644 --- a/examples/p2p-webrtc/video-transform/server/server.py +++ b/examples/p2p-webrtc/video-transform/server/server.py @@ -18,7 +18,7 @@ from fastapi.responses import RedirectResponse from loguru import logger from pipecat_ai_small_webrtc_prebuilt.frontend import SmallWebRTCPrebuiltUI -from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection +from pipecat.transports.network.webrtc_connection import IceServer, SmallWebRTCConnection # Load environment variables load_dotenv(override=True) @@ -28,7 +28,11 @@ app = FastAPI() # Store connections by pc_id pcs_map: Dict[str, SmallWebRTCConnection] = {} -ice_servers = ["stun:stun.l.google.com:19302"] +ice_servers = [ + IceServer( + urls="stun:stun.l.google.com:19302", + ) +] # Mount the frontend at / app.mount("/prebuilt", SmallWebRTCPrebuiltUI) diff --git a/examples/p2p-webrtc/voice-agent/server.py b/examples/p2p-webrtc/voice-agent/server.py index 3706455a5..b2ee0b4cd 100644 --- a/examples/p2p-webrtc/voice-agent/server.py +++ b/examples/p2p-webrtc/voice-agent/server.py @@ -17,7 +17,7 @@ from fastapi import BackgroundTasks, FastAPI from fastapi.responses import FileResponse from loguru import logger -from pipecat.transports.network.webrtc_connection import SmallWebRTCConnection +from pipecat.transports.network.webrtc_connection import IceServer, SmallWebRTCConnection # Load environment variables load_dotenv(override=True) @@ -28,6 +28,13 @@ app = FastAPI() pcs_map: Dict[str, SmallWebRTCConnection] = {} +ice_servers = [ + IceServer( + urls="stun:stun.l.google.com:19302", + ) +] + + @app.post("/api/offer") async def offer(request: dict, background_tasks: BackgroundTasks): pc_id = request.get("pc_id") @@ -37,7 +44,7 @@ async def offer(request: dict, background_tasks: BackgroundTasks): logger.info(f"Reusing existing connection for pc_id: {pc_id}") await pipecat_connection.renegotiate(sdp=request["sdp"], type=request["type"]) else: - pipecat_connection = SmallWebRTCConnection() + pipecat_connection = SmallWebRTCConnection(ice_servers) await pipecat_connection.initialize(sdp=request["sdp"], type=request["type"]) @pipecat_connection.event_handler("closed") From 9352396d7ee7edaaf3fa404897f391b6d985833a Mon Sep 17 00:00:00 2001 From: Filipi Fuchter Date: Tue, 29 Apr 2025 10:40:09 -0300 Subject: [PATCH 3/3] Mentioning the new feature in the changelog. --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f6af9e3f..845a1319b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Updated `SmallWebRTCConnection` to support `ice_servers` with credentials. + - Added `VADUserStartedSpeakingFrame` and `VADUserStoppedSpeakingFrame`, indicating when the VAD detected the user to start and stop speaking. These events are helpful when using smart turn detection, as the user's stop time