TwiML(Twilio Markup Language)이란
TwiML(Twilio Markup Language)이란
전화가 걸려 오면 Twilio는 우리 앱에 '어떻게 응답할까'를 물어와요. 그 답을 Twilio가 이해할 수 있는 언어로 써주는 게 바로 TwiML이에요. TwiML은 Twilio가 정의한 XML 문서로, 통화 녹음·메시지 재생·키패드 입력 수집 같은 동작을 지시하는 특수 태그로 이뤄져 있어요. 코드라기보다는 통화 흐름의 설계도라고 보면 돼요.
TwiML이 어떻게 동작하나
전화가 걸려 오면 Twilio는 우선 해당 번호에 설정된 TwiML을 호스팅하는 URL을 요청해요. 그리고 그 TwiML 지시문을 읽어 통화를 녹음할지, 발신자에게 메시지를 재생할지, 키패드 숫자를 눌러 달라고 할지를 결정해요. 단순히 <Say> 하나만 있어도 그 문구를 읽어주는 식으로요. 발신 통화도 같은 방식으로 TwiML로 제어돼요. 실시간으로는 한 번에 하나의 TwiML 문서만 실행되지만, 여러 문서를 서로 연결해 복잡한 대화형 음성 앱을 만들 수 있어요.
누군가 Twilio 번호로 전화를 걸면 "Hello, world!"를 말하는 최소 예시는 이렇게 생겼어요.
<Response>
<Say>Hello, world!</Say>
</Response>
TwiML 요소: 동사(Verb)와 명사(Noun)
TwiML 문서의 요소는 크게 두 종류로 나뉘어요.
- 동사(Verb) — 주어진 통화에서 Twilio가 어떤 행동을 할지 지시하는 요소예요. 대부분의 TwiML 요소가 이에 속하고, 동사 이름과 속성 이름은 대소문자를 구분해요.
<Say>— 발신자에게 텍스트를 읽어줘요.<Play>— 발신자에게 오디오 파일을 재생해요.<Dial>— 통화에 다른 당사자를 추가해요.<Record>— 발신자의 목소리를 녹음해요.<Gather>— 발신자가 키패드로 입력하는 숫자를 수집해요.<Hangup>— 통화를 끊어요.<Enqueue>— 발신자를 대기열(큐)에 추가해요.<Leave>— 발신자를 대기열에서 제거해요.<Pause>— 다음 지시를 실행하기 전에 기다려요.<Redirect>— 다른 TwiML 문서로 통화 흐름을 리다이렉트해요.<Refer>— Twilio가 IP 통신 인프라 쪽으로 SIP REFER를 시작해요.<Reject>— 과금 없이 들어오는 통화를 거절해요.
- 명사(Noun) — 동사가 행동을 취할 대상, 즉 동사 안에 중첩되는 요소예요.
<Dial>안의<Number>가 다른 전화번호에 연결하듯이, 명사는 동사가 작용하는 대상을 가리켜요.
웹훅 요청과 응답
전화가 오면 Twilio가 우리 애플리케이션으로 HTTP 요청을 보내고, 요청 파라미터에 통화 방향 정보가 들어와요. Direction 파라미터는 inbound(착신), outbound-api(REST API로 시작한 발신), outbound-dial(<Dial> 동사로 시작한 발신)을 구분해요.
통화가 끝나면 상태 콜백(StatusCallback)으로도 정보를 받을 수 있어요. 대표 파라미터는 다음과 같아요.
CallDuration— 방금 끝난 통화의 길이(초).RecordingSid— 이 통화에서 만들어진 Recording의 고유 ID.RecordingDuration— 녹음된 오디오 길이(초).
응답은 XML로 돌려주면 TwiML 인터프리터가 문서 맨 위에서부터 순서대로 동사(지시문)를 실행해요. 예를 들어 아래 코드는 "Hello World"를 읽어주고 나서 https://api.twilio.com/cowbell.mp3를 10번 반복 재생한 뒤 통화를 끊어요.
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Play loop="10">https://api.twilio.com/cowbell.mp3</Play>
</Response>
주의할 점은, 어떤 동사의 action 속성이 설정되면 제어 흐름이 다른 문서로 넘어가서 그 뒤의 동사들이 실행되지 않을 수 있다는 거예요.