diff --git a/changelog/4048.changed.md b/changelog/4048.changed.md new file mode 100644 index 000000000..edef83283 --- /dev/null +++ b/changelog/4048.changed.md @@ -0,0 +1 @@ +- Added `enable_dialout` parameter to `configure()` in `pipecat.runner.daily` to support dial-out rooms. Also narrowed misleading `Optional` type hints and deduplicated token expiry calculation. diff --git a/src/pipecat/runner/daily.py b/src/pipecat/runner/daily.py index cfb754dfd..b9bcb6e3d 100644 --- a/src/pipecat/runner/daily.py +++ b/src/pipecat/runner/daily.py @@ -79,16 +79,17 @@ async def configure( aiohttp_session: aiohttp.ClientSession, *, api_key: Optional[str] = None, - room_exp_duration: Optional[float] = 2.0, - token_exp_duration: Optional[float] = 2.0, + room_exp_duration: float = 2.0, + token_exp_duration: float = 2.0, sip_caller_phone: Optional[str] = None, - sip_enable_video: Optional[bool] = False, - sip_num_endpoints: Optional[int] = 1, + sip_enable_video: bool = False, + sip_num_endpoints: int = 1, + enable_dialout: bool = False, sip_codecs: Optional[Dict[str, List[str]]] = None, sip_provider: Optional[str] = None, room_geo: Optional[str] = None, room_properties: Optional[DailyRoomProperties] = None, - token_properties: Optional["DailyMeetingTokenProperties"] = None, + token_properties: Optional[DailyMeetingTokenProperties] = None, ) -> DailyRoomConfig: """Configure Daily room URL and token with optional SIP capabilities. @@ -105,6 +106,8 @@ async def configure( When provided, enables SIP functionality and returns SipRoomConfig. sip_enable_video: Whether video is enabled for SIP. sip_num_endpoints: Number of allowed SIP endpoints. + enable_dialout: Whether to enable outbound dialing (PSTN or SIP) on the room. + Requires dial-out entitlement on your Daily account. sip_codecs: Codecs to support for audio and video. If None, uses Daily defaults. Example: {"audio": ["OPUS"], "video": ["H264"]} sip_provider: SIP provider name (e.g., "daily"). Only used when @@ -159,6 +162,7 @@ async def configure( sip_caller_phone is not None, sip_enable_video is not False, sip_num_endpoints != 1, + enable_dialout is not False, sip_codecs is not None, sip_provider is not None, room_geo is not None, @@ -184,6 +188,8 @@ async def configure( aiohttp_session=aiohttp_session, ) + token_expiry_seconds: float = token_exp_duration * 60 * 60 + # Check for existing room URL (only in standard mode) existing_room_url = os.getenv("DAILY_ROOM_URL") if existing_room_url and not sip_enabled: @@ -192,11 +198,12 @@ async def configure( room_url = existing_room_url # Create token and return standard format - expiry_time: float = token_exp_duration * 60 * 60 token_params = None if token_properties: token_params = DailyMeetingTokenParams(properties=token_properties) - token = await daily_rest_helper.get_token(room_url, expiry_time, params=token_params) + token = await daily_rest_helper.get_token( + room_url, token_expiry_seconds, params=token_params + ) return DailyRoomConfig(room_url=room_url, token=token) # Create a new room @@ -229,7 +236,7 @@ async def configure( provider=sip_provider, ) room_properties.sip = sip_params - room_properties.enable_dialout = True # Enable outbound calls if needed + room_properties.enable_dialout = enable_dialout room_properties.start_video_off = not sip_enable_video # Voice-only by default # Create room parameters @@ -241,7 +248,6 @@ async def configure( logger.info(f"Created Daily room: {room_url}") # Create meeting token - token_expiry_seconds = token_exp_duration * 60 * 60 token_params = None if token_properties: token_params = DailyMeetingTokenParams(properties=token_properties)