使用 Twilio 可编程语音 SDK 接听电话
Receiving a Call Using Twilio Programmable Voice SDK
我在 Heroku 上使用 python 部署来关注 Quickstart Guide,并且能够很好地拨打电话。这是我遇到问题的接收。我没有为 TVOIncomingCall
实例或 PKPushRegistry
修改任何初始化或委托逻辑。事实上,当我编译时,日志显示 "pushRegistry:didUpdatePushCredentials:forType"
和 "Successfully registered for VoIP push notifications."
这让我觉得我的 server.py 上的传入处理程序是问题所在。
我的问题是:在 python 中,触发 VoIP 推送通知以通知用户有来电的正确方法是什么? 我'我已经在我的应用程序中启用了 VoIP 服务并生成了 VoIP 服务证书 (.p12) 并收到了一个有效的 PUSH_CREDENTIAL_SID
作为我的努力,但如何处理它呢?
Quickstart 说要访问我服务器的 'placeCall' 端点,所以我更新了我的 Twilio 号码的传入路径并在仪表板中相应地指向它,但这会导致 "An Application Error has occurred" 每当有人呼叫我的 Twilio 时响应数.
这是我的server.py中的相关代码:
import os
from flask import Flask, request
from twilio.jwt.access_token import AccessToken, VoiceGrant
from twilio.rest import Client
import twilio.twiml
ACCOUNT_SID = 'ACxxxxxxxx'
API_KEY = 'SKxxxxxxxxxxxxxxxx'
API_KEY_SECRET = 'xxxxxxxxxxxxxxxx'
PUSH_CREDENTIAL_SID = 'CRxxxxxxxxxxxxxxxx'
APP_SID = 'APxxxxxxxxxxxxxxxx'
ACCOUNT_AUTH = 'xxxxxxxxxxxxxxxx'
IDENTITY = 'MyApp' #not literally
app = Flask(__name__)
@app.route('/accessToken')
def token():
account_sid = os.environ.get("ACCOUNT_SID", ACCOUNT_SID)
api_key = os.environ.get("API_KEY", API_KEY)
api_key_secret = os.environ.get("API_KEY_SECRET", API_KEY_SECRET)
push_credential_sid = os.environ.get("PUSH_CREDENTIAL_SID", PUSH_CREDENTIAL_SID)
app_sid = os.environ.get("APP_SID", APP_SID)
grant = VoiceGrant(
push_credential_sid = push_credential_sid,
outgoing_application_sid = app_sid
)
token = AccessToken(account_sid, api_key, api_key_secret, IDENTITY)
token.add_grant(grant)
return str(token)
@app.route('/placeCall', methods=['GET', 'POST'])
def placeCall():
account_sid = os.environ.get("ACCOUNT_SID", ACCOUNT_SID)
api_key = os.environ.get("API_KEY", API_KEY)
api_key_secret = os.environ.get("API_KEY_SECRET", API_KEY_SECRET)
push_credential_sid = os.environ.get("PUSH_CREDENTIAL_SID", PUSH_CREDENTIAL_SID)
app_sid = os.environ.get("APP_SID", APP_SID)
CALLER_ID = request.values.get('From')
IDENTITY = request.values.get('To')
#client = Client(api_key, api_key_secret, account_sid)
client = Client(api_key, api_key_secret, account_sid, app_sid, push_credential_sid)
call = client.calls.create(to='client:' + IDENTITY, from_= 'client:' + CALLER_ID)
return str(call.sid)
我的Identity
值显然是错误的。我认为它需要以某种方式等于对应用程序实例的引用。在快速入门 python 示例中,IDENTITY = 'voice_test'
另外,PUSH_CREDENTIAL_SID
在哪里发挥作用?
提前致谢。
更新
______
根据@philnash 的评论,我将 client
名词嵌套在 dial
动词中。这是我的新 /incoming
端点:
@app.route('/incoming', methods=['GET', 'POST'])
def incoming():
CALLER_ID = request.values.get('From')
resp = twilio.twiml.Response()
resp.dial(client = IDENTITY, callerId = CALLER_ID, record = "record-from-answer-dual")
return str(resp)
现在这会导致调试器中的 'Schema validation warning' 指出 'unknown or unexpected nested elements' 是可能的原因。我是否错误地注册了客户端?旧版 SDK 允许您显式传入您的 clientName 作为参数。
我的server.py中的IDENTITY
字符串是:
- 在任何方法范围之外定义。
- 用于生成 accessToken
- 嵌套在
dial
动词的 client
名词中。
使用新的推送凭据 SID 更新应用程序服务器 server.py
文件中的 PUSH_CREDENTIAL_SID
值。它与文件顶部的以下常量一起使用:
ACCOUNT_SID = 'AC***'
API_KEY = 'SK***'
API_KEY_SECRET = '***'
PUSH_CREDENTIAL_SID = 'CR***'
APP_SID = 'AP***'
并且在您的 placeCall
函数中:
def placeCall():
account_sid = os.environ.get("ACCOUNT_SID", ACCOUNT_SID)
api_key = os.environ.get("API_KEY", API_KEY)
api_key_secret = os.environ.get("API_KEY_SECRET", API_KEY_SECRET)
push_credential_sid = os.environ.get("PUSH_CREDENTIAL_SID", PUSH_CREDENTIAL_SID)
app_sid = os.environ.get("APP_SID", APP_SID)
您似乎还遗漏了上面的 APP_SID
,它是对包含一些调用说明的 TwiML app 的引用。
此处为 Twilio 开发人员布道师。
/placeCall
端点不适用于您的 Twilio 号码的来电 webhook。在示例中,它用于简单地生成对您的客户端的调用。
相反,您的来电 webhook 应该指向一个端点,该端点将 return 一些 TwiML instructing Twilio to dial your client. TwiML is just a subset of XML and the elements you will need are <Dial>
with a nested <Client>
。您的端点应该 return 类似于:
<Response>
<Dial>
<Client>YOUR_CLIENT_NAME</Client>
</Dial>
</Response>
如果这有帮助,请告诉我。
更新
根据问题的更新,我们现在需要在Python中生成这个TwiML。您可以 nest TwiML with the Twilio Python helper library 使用 Python 的 with
语法。我相信这应该有效:
@app.route('/incoming', methods=['GET', 'POST'])
def incoming():
CALLER_ID = request.values.get('From')
resp = twilio.twiml.Response()
with resp.dial(callerId = CALLER_ID, record = "record-from-answer-dual") as dial:
dial.client(IDENTITY)
return str(resp)
我在 Heroku 上使用 python 部署来关注 Quickstart Guide,并且能够很好地拨打电话。这是我遇到问题的接收。我没有为 TVOIncomingCall
实例或 PKPushRegistry
修改任何初始化或委托逻辑。事实上,当我编译时,日志显示 "pushRegistry:didUpdatePushCredentials:forType"
和 "Successfully registered for VoIP push notifications."
这让我觉得我的 server.py 上的传入处理程序是问题所在。
我的问题是:在 python 中,触发 VoIP 推送通知以通知用户有来电的正确方法是什么? 我'我已经在我的应用程序中启用了 VoIP 服务并生成了 VoIP 服务证书 (.p12) 并收到了一个有效的 PUSH_CREDENTIAL_SID
作为我的努力,但如何处理它呢?
Quickstart 说要访问我服务器的 'placeCall' 端点,所以我更新了我的 Twilio 号码的传入路径并在仪表板中相应地指向它,但这会导致 "An Application Error has occurred" 每当有人呼叫我的 Twilio 时响应数.
这是我的server.py中的相关代码:
import os
from flask import Flask, request
from twilio.jwt.access_token import AccessToken, VoiceGrant
from twilio.rest import Client
import twilio.twiml
ACCOUNT_SID = 'ACxxxxxxxx'
API_KEY = 'SKxxxxxxxxxxxxxxxx'
API_KEY_SECRET = 'xxxxxxxxxxxxxxxx'
PUSH_CREDENTIAL_SID = 'CRxxxxxxxxxxxxxxxx'
APP_SID = 'APxxxxxxxxxxxxxxxx'
ACCOUNT_AUTH = 'xxxxxxxxxxxxxxxx'
IDENTITY = 'MyApp' #not literally
app = Flask(__name__)
@app.route('/accessToken')
def token():
account_sid = os.environ.get("ACCOUNT_SID", ACCOUNT_SID)
api_key = os.environ.get("API_KEY", API_KEY)
api_key_secret = os.environ.get("API_KEY_SECRET", API_KEY_SECRET)
push_credential_sid = os.environ.get("PUSH_CREDENTIAL_SID", PUSH_CREDENTIAL_SID)
app_sid = os.environ.get("APP_SID", APP_SID)
grant = VoiceGrant(
push_credential_sid = push_credential_sid,
outgoing_application_sid = app_sid
)
token = AccessToken(account_sid, api_key, api_key_secret, IDENTITY)
token.add_grant(grant)
return str(token)
@app.route('/placeCall', methods=['GET', 'POST'])
def placeCall():
account_sid = os.environ.get("ACCOUNT_SID", ACCOUNT_SID)
api_key = os.environ.get("API_KEY", API_KEY)
api_key_secret = os.environ.get("API_KEY_SECRET", API_KEY_SECRET)
push_credential_sid = os.environ.get("PUSH_CREDENTIAL_SID", PUSH_CREDENTIAL_SID)
app_sid = os.environ.get("APP_SID", APP_SID)
CALLER_ID = request.values.get('From')
IDENTITY = request.values.get('To')
#client = Client(api_key, api_key_secret, account_sid)
client = Client(api_key, api_key_secret, account_sid, app_sid, push_credential_sid)
call = client.calls.create(to='client:' + IDENTITY, from_= 'client:' + CALLER_ID)
return str(call.sid)
我的Identity
值显然是错误的。我认为它需要以某种方式等于对应用程序实例的引用。在快速入门 python 示例中,IDENTITY = 'voice_test'
另外,PUSH_CREDENTIAL_SID
在哪里发挥作用?
提前致谢。
更新
______
根据@philnash 的评论,我将 client
名词嵌套在 dial
动词中。这是我的新 /incoming
端点:
@app.route('/incoming', methods=['GET', 'POST'])
def incoming():
CALLER_ID = request.values.get('From')
resp = twilio.twiml.Response()
resp.dial(client = IDENTITY, callerId = CALLER_ID, record = "record-from-answer-dual")
return str(resp)
现在这会导致调试器中的 'Schema validation warning' 指出 'unknown or unexpected nested elements' 是可能的原因。我是否错误地注册了客户端?旧版 SDK 允许您显式传入您的 clientName 作为参数。
我的server.py中的IDENTITY
字符串是:
- 在任何方法范围之外定义。
- 用于生成 accessToken
- 嵌套在
dial
动词的client
名词中。
使用新的推送凭据 SID 更新应用程序服务器 server.py
文件中的 PUSH_CREDENTIAL_SID
值。它与文件顶部的以下常量一起使用:
ACCOUNT_SID = 'AC***'
API_KEY = 'SK***'
API_KEY_SECRET = '***'
PUSH_CREDENTIAL_SID = 'CR***'
APP_SID = 'AP***'
并且在您的 placeCall
函数中:
def placeCall():
account_sid = os.environ.get("ACCOUNT_SID", ACCOUNT_SID)
api_key = os.environ.get("API_KEY", API_KEY)
api_key_secret = os.environ.get("API_KEY_SECRET", API_KEY_SECRET)
push_credential_sid = os.environ.get("PUSH_CREDENTIAL_SID", PUSH_CREDENTIAL_SID)
app_sid = os.environ.get("APP_SID", APP_SID)
您似乎还遗漏了上面的 APP_SID
,它是对包含一些调用说明的 TwiML app 的引用。
此处为 Twilio 开发人员布道师。
/placeCall
端点不适用于您的 Twilio 号码的来电 webhook。在示例中,它用于简单地生成对您的客户端的调用。
相反,您的来电 webhook 应该指向一个端点,该端点将 return 一些 TwiML instructing Twilio to dial your client. TwiML is just a subset of XML and the elements you will need are <Dial>
with a nested <Client>
。您的端点应该 return 类似于:
<Response>
<Dial>
<Client>YOUR_CLIENT_NAME</Client>
</Dial>
</Response>
如果这有帮助,请告诉我。
更新
根据问题的更新,我们现在需要在Python中生成这个TwiML。您可以 nest TwiML with the Twilio Python helper library 使用 Python 的 with
语法。我相信这应该有效:
@app.route('/incoming', methods=['GET', 'POST'])
def incoming():
CALLER_ID = request.values.get('From')
resp = twilio.twiml.Response()
with resp.dial(callerId = CALLER_ID, record = "record-from-answer-dual") as dial:
dial.client(IDENTITY)
return str(resp)