python - Twilio 可编程语音调用立即完成

标签 python ios twilio

我正在使用带有 Swift 和 Python 的新 Twilio 可编程语音 SDK。我已经开始了各自的快速入门项目,并且大部分情况都有效。我能够获得有效的访问 token ,能够成功创建调用,甚至能够接听调用。问题出在房子的调用者一侧。

当我尝试通过 Swift SDK 调用电话时,调用在另一端开始响铃之前就已断开。

我在 Twilio 文档中读到,如果您不处理 status_callback 事件,client.calls.create 函数将立即返回完成状态。我尝试添加此内容,但每当我这样做时,我都会收到一条错误消息,指出键 status_callback 不是 client.calls.create 函数的有效参数。另外,我在任何地方都找不到任何实际如何处理调用状态的示例。

我的问题是我在这里做错了什么?任何帮助将不胜感激。

这是我的 Python 代码

@app.route('/outgoing', methods=['GET', 'POST'])
def outgoing():

  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)

  from_number = [HARD_CODED_PHONE_NUMBER_FOR_CALLER]
  to_number = [HARD_CODED_PHONE_NUMBER_FOR_RECIPIENT]

  client = Client(api_key, api_key_secret, account_sid)
  call = client.calls.create(url='http://twimlets.com/holdmusic?Bucket=com.twilio.music.ambient', to=to_number, from_=from_number)

  # return str(call.sid)
  resp = twilio.twiml.Response()
  resp.say("Thank you for calling");
  return str(resp)

这是我的相关iOS代码。请记住,这不是我的完整来源。我只提供了本次事件中必要的内容。我的完整来源确实包括处理注册表和邀请代表。我也没有包含显示/隐藏我的事件调用用户界面的源代码,因为这没有问题。这只是为了展示我如何发出调用并接收调用完成委托(delegate)。

class VoiceManager: NSObject, PKPushRegistryDelegate, TVONotificationDelegate, TVOCallDelegate, AVAudioPlayerDelegate {

    //MARK: - Singleton

    static let sharedManager = VoiceManager()

    //MARK: - Private Constants

    private let baseURLString = [MY_WEBAPP_ENDPOINT]
    private let accessTokenEndpoint = "/accessToken"

    //MARK: - Private Variables

    private var deviceTokenString:String?

    private var callInvite: TVOCallInvite?
    private var call: TVOCall?
    private var status: VoiceStatus = .idle

    //MARK: - Getters

    private func fetchAccessToken() -> String? {

        guard let accessTokenURL = URL(string: baseURLString + accessTokenEndpoint) else {
            return nil
        }

        return try? String.init(contentsOf: accessTokenURL, encoding: .utf8)
    }

    func placeCall(withParameters params: VoiceParameters, completion: @escaping (_ success: Bool, _ error: VAError?) -> Void) {

        if (call != nil) {
            call?.disconnect()
            completion(false, .phoneCallInProgress)
            status = .callEnded
            hideActiveCallUI()

        } else {

            guard let accessToken = fetchAccessToken() else {
                completion(false, .phoneAccessTokenFetchFailed)
                return
            }

            guard let paramsDict = params.toDictionary() else {
                completion(false, .phoneAccessTokenFetchFailed)
                return
            }

            playOutgoingRingtone(completion: { [weak self] in

                if let strongSelf = self {

                    strongSelf.call = VoiceClient.sharedInstance().call(accessToken, params: [:], delegate: strongSelf) //NOTE: The params here are not necessary as the phone numbers for now are hard coded on the server

                    if (strongSelf.call == nil) {
                        strongSelf.status = .callEnded
                        completion(false, .phoneCallFailed)
                        return

                    } else {
                        strongSelf.status = .callConnecting
                        self?.showActiveCallUI(withParameters: params)
                        completion(true, nil)
                    }
                }
            })
        }
    }

    // MARK: TVOCallDelegate
    func callDidConnect(_ call: TVOCall) {

        NSLog("callDidConnect:")

        self.call = call
        status = .inCall

        routeAudioToSpeaker()
    }

    func callDidDisconnect(_ call: TVOCall) {

        NSLog("callDidDisconnect:")

        playDisconnectSound()

        self.call = nil
        status = .callEnded

        hideActiveCallUI()
    }

    func call(_ call: TVOCall, didFailWithError error: Error) {

        NSLog("call:didFailWithError: \(error)");

        self.call = nil
        status = .callEnded
        hideActiveCallUI()
    }
}

最佳答案

这里是 Twilio 开发者布道者。

您的 Swift 代码表明您的电话号码目前已硬编码在服务器上。正如 Robert 也所说,问题在于,当您收到从 Twilio 到 /outbound 端点的回调时,您正在使用 REST API 生成调用。

实际发生的情况是,当您generate the call in Swift时在启动应用程序调用的设备上。然后,Twilio 向您的 /outbound 端点发出 HTTP 请求,以查看如何处理该调用。所以,而不是 generating a new call with the REST API ,您需要回复 TwiML告诉 Twilio 接下来如何处理该调用。

在这种情况下,听起来您正在尝试 dial直接到另一个number 。为此,您应该尝试以下响应:

@app.route('/outgoing', methods=['GET', 'POST'])
def outgoing():
  from_number = [HARD_CODED_PHONE_NUMBER_FOR_CALLER]
  to_number = [HARD_CODED_PHONE_NUMBER_FOR_RECIPIENT]

  resp = twilio.twiml.Response()
  with resp.dial(callerId=from_number) as r:
    r.number(to_number)
  return str(resp)

请告诉我这是否有帮助。

关于python - Twilio 可编程语音调用立即完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42673441/

相关文章:

javascript - 如何为 Twiml Nodejs 提供服务

python - 反冲\与逃逸之间的混淆以及\的使用\"

python - 提取文本文件中两个字符串之间的值

python - Microsoft Python 语言服务器无法识别 `for` 循环 `zip()`

objective-c - Apple 代码示例 : TouchCells, 它是如何工作的?

ios - 无法将 AKAudioFile 加载到 AKSampler 中

ios - Swift 中从 Core Data 异步加载图像

javascript - 类型错误 : Cannot read property 'Digits' of undefined in twilio when gathering user input from call

javascript - 在 twilio-video 中,如果我连接到一个 automaticSubscription 设置为 false 的房间,我以后如何订阅远程轨道?

python - opencv python中的特定像素如何透明?