아웃바운드 라이브킷 에이젼트 콜에서 전화대상자가 전화를 받음(Accept Call) Or ...
# ask-ai
l
아웃바운드 라이브킷 에이젼트 콜에서 전화대상자가 전화를 받음(Accept Call) Or 안받음(Deny Call)을 명시적으로 알수 있는 방법이 있어?
t
Thanks for reaching out, Dan(송희웅). I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
전화 대상자가 전화를 받았는지(Accept Call) 또는 거부했는지(Deny Call)를 확인하고 싶으시다면,
sip.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.go
l
wait_until_answered=True 로 설정되어 있을때, 통화가 수락되는 시점을 어디서 어떻게 알수 있어?
t
wait_until_answered=True 설정에 대해 궁금해 하시는 점 정말 잘 이해합니다. 혹시 통화가 수락되는 시점을 어떻게 확인하고 싶으신지 구체적인 방법이나 사용 사례를 조금 더 알려주실 수 있을까요? 예를 들어, API 응답을 통해 확인하고 싶으신지, 아니면 다른 방식으로 모니터링을 원하시는지에 따라 더 정확한 도움을 드릴 수 있을 것 같아요. 편하게 말씀해 주세요!
l
대상자가 전화를 받았는지 안받았는지 확인해야되는 부분이 있어서 그래!
t
wait_until_answered=True
설정 시, 대상자가 전화를 받았는지 여부를 API 응답과 예외 처리를 통해 확인할 수 있어요. 함께 차근차근 살펴볼게요. 1. 성공적인 연결: API 호출이 오류 없이 완료되면 대상자가 전화를 수락한 거랍니다. 이때
SIPParticipantInfo
객체가 반환돼요. 2. 거부 또는 실패: 만약 API 호출 중에
TwirpError
예외가 발생한다면, 예외의 `metadata`에서 `sip_status_code`와 `sip_status`를 확인해서 거부나 실패 이유를 알 수 있어요. 예를 들어, `486 Busy Here`는 대상자가 통화를 거부했다는 의미예요. 아래는 Python 예제 코드인데요, 참고하시면 도움이 될 거예요:
Copy code
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 Docs
l
대상자가 전화를 계속 받지 않으면, 저동응답으로 넘어가는데, 그러면 전화를 받은걸로 판단해버려!
t
대상자가 전화를 받지 않고 자동응답 시스템(예: 음성사서함)으로 넘어가는 상황을 다루실 때, 다음과 같은 방법들을 함께 살펴보시면 도움이 될 거예요: 1. LLM 기반 음성사서함 감지 LiveKit의 LLM 기능을 활용하면 자동응답 메시지를 감지하고 적절하게 대응할 수 있답니다. 예를 들어, 음성사서함 메시지를 인식한 후에 메시지를 남기거나 전화를 종료하도록 설정할 수 있어요.
Copy code
@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. 침묵 감지 침묵 감지를 통해 응답이 없을 때를 처리할 수 있어요. 일정 시간 동안 음성이 감지되지 않으면 전화를 종료하도록 설정하는 방법입니다.
Copy code
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.py
l
`sip.callStatus`를 모니터링 하는 샘플코드를 보여줘
t
다음은 `sip.callStatus`를 모니터링하는 샘플 코드입니다. 함께 살펴보면서 이해를 돕고자 해요: 1. 폴링 방식
Copy code
import 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. 이벤트 기반 방식
Copy code
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 &amp; Telephony Integration | livekit/livekit_composite | DeepWiki | SIP participant | LiveKit Docs | Making calls using SIP | LiveKit Docs | telephony/sip_lifecycle.py