limited-planet-15554
09/23/2025, 8:21 AMtall-airline-16756
09/23/2025, 8:21 AMtall-airline-16756
09/23/2025, 8:22 AMsip.callStatus 속성을 살펴보시면 도움이 될 거예요. 이 속성은 실시간으로 통화 상태를 알려주는데, 주요 값들은 다음과 같습니다:
• dialing: 통화가 시작된 상태입니다
• ringing: 대상자의 전화가 울리고 있는 상태입니다
• active: 대상자가 전화를 수락한 상태입니다
• hangup: 통화가 종료된 상태로, 거부나 실패도 포함됩니다
예를 들어, `sip.callStatus`가 *active*로 바뀌면 대상자가 전화를 받으신 거고, *hangup*으로 바뀌면 거부하거나 실패한 경우라고 이해하시면 돼요.
또한, SIP 상태 코드를 통해서도 좀 더 구체적인 상황을 알 수 있답니다. 예를 들어:
• 200 OK: 통화가 성공적으로 연결된 경우
• 486 Busy Here: 대상자가 통화를 거절한 경우
• 480 Temporarily Unavailable: 대상자가 일시적으로 연결할 수 없는 상황
그리고 한 가지 팁을 드리자면, `CreateSIPParticipantRequest`에서 `wait_until_answered=True`로 설정하시면 통화가 수락되거나 실패할 때까지 기다릴 수 있어서 통화 상태를 더 쉽게 파악하실 수 있어요.
Sources: Making outbound calls | LiveKit Docs | Making calls using SIP | LiveKit Docs | Agents telephony integration | LiveKit Docs | livekit-protocol/src/livekit.rs | pkg/sip/outbound.golimited-planet-15554
09/23/2025, 8:23 AMtall-airline-16756
09/23/2025, 8:24 AMlimited-planet-15554
09/23/2025, 8:27 AMtall-airline-16756
09/23/2025, 8:27 AMwait_until_answered=True 설정 시, 대상자가 전화를 받았는지 여부를 API 응답과 예외 처리를 통해 확인할 수 있어요. 함께 차근차근 살펴볼게요.
1. 성공적인 연결: API 호출이 오류 없이 완료되면 대상자가 전화를 수락한 거랍니다. 이때 SIPParticipantInfo 객체가 반환돼요.
2. 거부 또는 실패: 만약 API 호출 중에 TwirpError 예외가 발생한다면, 예외의 `metadata`에서 `sip_status_code`와 `sip_status`를 확인해서 거부나 실패 이유를 알 수 있어요. 예를 들어, `486 Busy Here`는 대상자가 통화를 거부했다는 의미예요.
아래는 Python 예제 코드인데요, 참고하시면 도움이 될 거예요:
try:
await livekit_api.sip.create_sip_participant(request)
print("call picked up successfully")
except api.TwirpError as e:
print(f"error creating SIP participant: {e.message}, "
f"SIP status: {e.metadata.get('sip_status_code')} {e.metadata.get('sip_status')}")
이렇게 하시면 대상자가 전화를 받았는지, 거부했는지 확실히 확인하실 수 있으니 안심하세요. 궁금한 점 있으면 언제든 말씀해 주세요!
Sources: Make outbound calls | LiveKit Docs | agent.py | Agents telephony integration | LiveKit Docslimited-planet-15554
09/23/2025, 8:30 AMtall-airline-16756
09/23/2025, 8:31 AM@function_tool
async def detected_answering_machine(self):
await self.session.generate_reply(
instructions="Leave a voicemail message letting the user know you'll call back later."
)
await asyncio.sleep(0.5)
await hangup_call()
이 코드는 음성사서함 메시지를 감지한 뒤에 친절하게 메시지를 남기고 전화를 종료하는 역할을 합니다.
2. 침묵 감지
침묵 감지를 통해 응답이 없을 때를 처리할 수 있어요. 일정 시간 동안 음성이 감지되지 않으면 전화를 종료하도록 설정하는 방법입니다.
SILENCE_THRESHOLD = 5 # seconds
async def monitor_interaction():
while True:
if time.time() - user_last_spoke_time > SILENCE_THRESHOLD:
<http://logger.info|logger.info>("silent for too long! disconnecting")
try:
await ctx.room.disconnect()
except Exception as e:
logger.exception("Error while ending call")
await asyncio.sleep(1)
이렇게 하면 상대방이 응답하지 않을 때 자동으로 통화를 종료할 수 있어요.
3. SIP 통화 상태 모니터링
`sip.callStatus`를 모니터링하시면 통화 상태를 쉽게 확인하실 수 있습니다. 예를 들어, 상태가 `active`로 바뀌면 상대방이 전화를 받은 것이고, `hangup`으로 바뀌면 통화가 종료된 상태입니다.
권장 전략
• LLM 기반 감지를 주로 사용하여 음성사서함 메시지를 잘 감지해 보세요.
• 침묵 감지는 보조적으로 활용하여 응답이 없는 경우를 효과적으로 처리할 수 있습니다.
이 방법들을 적절히 조합하시면 자동응답 시스템으로 넘어가는 상황을 보다 원활하게 관리하실 수 있을 거예요. 언제든지 궁금한 점 있으면 편하게 말씀해 주세요!
Sources: How to detect and handle silence during calls | Making calls using SIP | LiveKit Docs | Making calls using SIP | LiveKit Docs | Agents telephony integration | LiveKit Docs | agent.pylimited-planet-15554
09/23/2025, 8:32 AMtall-airline-16756
09/23/2025, 8:33 AMimport asyncio
import logging
from time import perf_counter
logger = logging.getLogger("sip-monitor")
start_time = perf_counter()
while perf_counter() - start_time < 30:
call_status = participant.attributes.get("sip.callStatus")
if call_status == "active":
<http://logger.info|logger.info>("사용자가 전화를 받았습니다.")
break
elif call_status == "automation":
<http://logger.info|logger.info>("통화가 연결되어 DTMF 번호를 누르는 중입니다.")
elif call_status == "hangup":
<http://logger.info|logger.info>("사용자가 전화를 끊었습니다. 작업을 종료합니다.")
break
await asyncio.sleep(0.1)
if call_status not in ["active", "automation"]:
<http://logger.info|logger.info>("세션이 시간 초과되었습니다.")
2. 이벤트 기반 방식
async def async_on_participant_attributes_changed(changed_attributes, participant):
<http://logger.info|logger.info>(f"참가자 {participant.identity}의 속성이 변경되었습니다: {changed_attributes}")
if 'sip.callStatus' in changed_attributes:
new_status = changed_attributes['sip.callStatus']
<http://logger.info|logger.info>(f"SIP 통화 상태가 업데이트되었습니다: {new_status}")
if new_status == 'active':
<http://logger.info|logger.info>("통화가 활성화되어 연결되었습니다.")
elif new_status == 'automation':
<http://logger.info|logger.info>("통화가 연결되어 DTMF 번호를 누르는 중입니다.")
elif new_status == 'dialing':
<http://logger.info|logger.info>("통화가 걸리고 있으며 수신 대기 중입니다.")
elif new_status == 'hangup':
<http://logger.info|logger.info>("참가자가 통화를 종료했습니다.")
elif new_status == 'ringing':
<http://logger.info|logger.info>("수신 전화가 울리고 있습니다.")
# 이벤트 핸들러를 연결합니다.
ctx.room.on("participant_attributes_changed", async_on_participant_attributes_changed)
이 두 가지 방법을 통해 `sip.callStatus`를 실시간으로 모니터링하거나 주기적으로 확인할 수 있으니, 상황에 맞게 활용해 보시면 좋겠습니다. 언제든 궁금한 점 있으시면 편하게 말씀해 주세요!
Sources: Making outbound calls | LiveKit Docs | SIP & Telephony Integration | livekit/livekit_composite | DeepWiki | SIP participant | LiveKit Docs | Making calls using SIP | LiveKit Docs | telephony/sip_lifecycle.py