본문 바로가기
Python

[Python] Twilio를 이용한 모바일 Voip 서비스 만들기

by 태진아밴드 2022. 1. 4.

2022년 새해 첫 줄.

 

작년 11월달부터 두목님께서 회사 메신저앱에 Voip 기능을 구현하라고 해서 진짜 눈물나는 기간이였다.

 

오픈소스를 활용하라는 말씀에 처음에는 Asterisk를 가지고 진짜 두달 내내 삽질하고 결국 구현은 했는데,

 

SIP Register가 불안정해서 앱이 안켜져있을경우에는 통화 자체가 안되는 일들이 빈번했다😂

 

결국 저번달부터 오픈소스가 아닌 유료로 사용하는 솔루션을 알아보자는 얘기가 나와서 이것저것 찾아보다가

 

몇년 전 해외 문자발송때문에 사용했었던 Twilio라는 서비스에서 Voip기능을 제공한다 해서 가져다 쓰게 되었다.

 

문서도 상세하고 샘플 코드들도 있길래 그냥 가져다 쓰면 되겠지하고 세팅을 하는데,

 

예제들이 죄다 Text to live 같은거밖에 없고 앱 <-> 앱 서로 통화하는 예제가 너무 없어서

 

진짜 여기저기 구글링하고 삽질하다가 오늘 최종적으로 마무리 되서 여기에 간단하게 적어두려고 한다.

 

https://www.twilio.com/

 

Twilio - Communication APIs for SMS, Voice, Video and Authentication

Cloud communications platform for building SMS, Voice & Messaging applications on an API built for global scale. Get started with a free trial.

www.twilio.com

 

일단 사이트에 들어가서 회원가입부터 진행하자.

 

나는 예전에 가입해둔 계정이 있어서 그대로 사용했다.

 

회원가입 후 결제 카드를 등록하고나면 ACCOUNT_SID와 AUTH_TOKEN을 부여받게 된다.

 

그 다음 이제 API KEY를 발급받으러 가자.

 

콘솔 페이지 상단 검색창에 API Keys라고 검색한 뒤 맨 위에 나오는걸로 이동하자.

 

이동하면 오른쪽 상단에 Create API Key라는 버튼이 있는데 그걸 눌러주자.

 

Friendly name에는 자기가 편한 이름으로 설정을 하고 Region은 기본설정인 US1으로 고정, Key Type은 Main으로 설정해주자.

 

그러면 하단부에 API용 SID와 Secret이 발급되는데 SID는 다시 확인이 가능한데 Secret은 생성이후에는 확인이 불가능하니 잘 기억해두도록하자.

 

그리고 Done을 눌러주면 API 설정은 완료.

 

이제 앱 설정 및 푸시 설정만 해주러 가자.

 

아까처럼 검색창에 TwiML Apps 라고 검색한 뒤 들어가보면 Create New TwiML App이라는 버튼이 있는데 클릭.

 

마찬가지로 편한 이름으로 생성하고 Request URL 부분은 우선 비워둔채로 생성하면 TwiML App SID가 발급이 된다.

 

URL은 나중에 설정해주는걸로 하고 푸시 설정을 해주러 가자.

 

다시 검색창에 notify services를 검색. 

 

+ 버튼을 눌러서 이름을 설정해주면 서비스가 생성되는데 APN설정, GCM, FCM 설정들을 해줄수있다.

 

저기 here을 눌러보면 설정할수있는 페이지가 나오는데 사용하고있는 push 서비스에 맞게끔 입력해주면 된다.

다시 Notify service 설정하는 페이지로 돌아와서 각각 설정한대로 APN, GCM 등을 설정해주고 저장해주자.

 

이제 Voip 통화를 연결시켜줄 서버를 하나 올려야하는데 간단한 웹서버라서 Flask로 구현하였다.

 

우선 터미널을 열고 Flask와 Twilio 모듈을 설치해주자.

 

# Flask 설치
pip install flask
# twilio 모듈설치
pip install twilio

그리고 나머지 웹 서버설정은 아래와 같다.

 

from flask import Flask, request
from twilio.jwt.access_token import AccessToken
from twilio.jwt.access_token.grants import VoiceGrant
from twilio.twiml.voice_response import Dial, VoiceResponse
import traceback

app = Flask(__name__)

ACCOUNT_SID = '가입시 발급받은 ACCOUNT_SID (ACXXX...)'
AUTH_TOKEN = '가입시 발급받은 AUTH_TOKEN'
API_KEY = 'API_KEY 값 (SKXXX...)'
API_KEY_SECRET = 'API_KEY_SECRET 값'
OUTGOING_APPLICATION_SID = 'TwiML App 생성시 발급받은 SID (APXXX...)'
ANDROID_PUSH_CREDENTIAL_SID = '안드로이드 PUSH 키 값 (CRXXX...)'
IOS_PUSH_CREDENTIAL_SID = 'ios PUSH 키 값 (CRXXX...)'


try:

	# access token 발급
    @app.route('/token', methods=['GET'])
    def get_access_token():
        print('------------token start------------')
        IDENTITY = request.values.get("identity")
        DEVICE = request.values.get("device")

        # 디바이스 타입에 따라 분기처리
        # FCM 사용시에는 상관없음
        if DEVICE.__eq__('android'):
            PUSH_CREDENTIAL_SID = ANDROID_PUSH_CREDENTIAL_SID
        elif DEVICE.__eq__('ios'):
            PUSH_CREDENTIAL_SID = IOS_PUSH_CREDENTIAL_SID
        else:
            PUSH_CREDENTIAL_SID = ''
            
        print('IDENTITY : ' + str(IDENTITY))
        print('DEVICE : ' + str(DEVICE))
        print('PUSH_CREDENTIAL_SID : ' + PUSH_CREDENTIAL_SID)

        token = AccessToken(ACCOUNT_SID, API_KEY, API_KEY_SECRET, identity=IDENTITY)

		# 음성권한 추가
        voice_grant = VoiceGrant(
            outgoing_application_sid=OUTGOING_APPLICATION_SID,
            incoming_allow=True,
            push_credential_sid=PUSH_CREDENTIAL_SID
        )
        token.add_grant(voice_grant)
        print('JWT : ' + token.to_jwt())
        print('------------token end--------------')
        return token.to_jwt()

	# 통화 연결
    @app.route('/placeCall', methods=['GET', 'POST'])
    def place_call():
        print('------------placeCall start------------')
        To = request.values.get("To")
        print('To : ' + str(To))
        resp = VoiceResponse()
        dial = Dial()
        dial.client(To)
        resp.append(dial)
        print('------------placeCall end---------------')
        return str(resp)

    if __name__ == '__main__':
        app.run(host='0.0.0.0', debug=True)

except Exception as ex:
    print(traceback.format_exc())

라우터가 2개뿐인 간단한 소스..!

 

해당 소스를 서버에 업로드 하고 실행시킨 뒤 아까전에 TwiML Apps을 설정했던 페이지로 돌아가보자.

 

Request URL 부분에 해당서버 도메인 + 통화연결하는쪽 url을 적어주고 저장하자.

 

이제 앱쪽에서 통화 호출 전 access token을 발급받는 부분을 호출한 뒤 twilio sdk를 통해 전화를 연결해주면

 

상대방에게 전화가 연결된다!

 

Asterisk보다 속도도 훨씬 빠르고 통화품질도 괜찮아서 성공적인 이전이였다🙌

 

비용관련 링크는 아래와 같다.

https://www.twilio.com/voice/pricing/kr

 

Programmable Voice Pricing | Twilio

Learn about Twilio Programmable Voice pricing. Build engaging, globally scalable voice calling experiences with pay-as-you-go, no commitment pricing and available high volume and committed use discounts.

www.twilio.com

 

분당 5~6원선으로 크게 비싸지 않아서 사용하는데 큰 지장은 없을거 같은데 사용자가 더 많아져

 

비용이 너무 많이나온다면 다시 갈아타라고 할지도 모르겠다....😢