在 Twilio 客户端快速入门中接收真正的来电

Posted

技术标签:

【中文标题】在 Twilio 客户端快速入门中接收真正的来电【英文标题】:Receiving a real incoming call in Twilio's ClientQuickstart 【发布时间】:2018-08-14 12:18:13 【问题描述】:

目前我在 Twilio 中使用测试帐户,但我希望这与我的问题无关。

作为我迈向 Twilio 的第一个实验步骤,我正在 Windows 上的 Visual Studio 2017 上测试 client-quickstart-csharp-1.4 包。

我的已验证手机可以正常拨出电话,但我在拨入电话时遇到问题。 当我从真实电话向我的 Twilio 电话号码拨打电话时,我在 VoiceController.cs 中的代码无法运行(没有遇到任何断点),我听到一条语音消息说我应该重新配置我的应用程序(但我不明白,什么)。与此相反,当我从我的 TwiMLApp 配置页面拨打电话时,按下红色的呼叫按钮(见图),

然后我的代码在断点处停止,并说出我在 response.Say() 的参数中编写的文本。

我的问题:

    为什么通话工作方式与真实电话和我的电话不同 TwiMLApp 配置页面? 当我从真实手机拨打电话时,如何实现我的代码运行(即说我在代码中编写的文本)? 如何在来电时在来电者电话与我的计算机扬声器和麦克风之间实现真实、实时的语音对话(类似于 拨出电话)?

备注 1.

使用 Twilio 小部件进行语音通话,在 Agile CRM 中拨出和拨入电话都可以正常工作。但在我的实验期间,我删除了这个小部件(以及来自 Twilio 的“Agile CRM Twilio Saga”TwiML 应用程序),以避免不同应用程序之间的干扰。

备注2。

也许我应该用这个屏幕配置一些东西(截图找到here),但我在我的 twilio 门户上找不到这个页面。

而不是这个,我有一个这样的页面:

但我不知道要在这里更改什么才能使我的程序正常运行。

【问题讨论】:

今天问题 1(因此也是 2)已经消失。除了将 TWiML APP 切换到“Agile CRM Twilio Saga”,然后在最后一个屏幕截图中看到的页面上再次切换回“TwimL APP 1 MMA”之外,我什么也没做。现在,从真实电话呼叫或从图 1 所示页面呼叫之间的唯一区别是,在第一种情况下,“request.To”包含我的 Twilio 号码,而在后一种情况下,它为空。 我得到了 Twilio 支持的提示。据称可以在这里找到我的第三个问题的解决方案:twilio.com/docs/voice/client/tutorials/…。我会尽快检查这个。但是,唉,目前我还有其他事情要做。 【参考方案1】:

看来这个应用是设计出来的

管理拨出电话(到真实电话,或到此的其他客户端 应用程序)和 接受来自网络的呼叫(来自另一个客户端, 或来自 TwiML 应用程序设置页面,在 o.p. 的第一个屏幕截图中可以看到),但不是来自真实手机。

每个(呼出或呼入)调用都属于VoiceController 类的Index() 方法。此方法尝试找出来电是呼入还是呼出。

在呼出的情况下,该方法的request参数的To属性是电话号码,而在来自网络的呼入时是字符串(用户名),或者null(当调用来自 TwiML App 设置页面)。这证明了原始代码中的 if-else 结构(仅扩展了我以 (mma) 开头的评论)

public ActionResult Index(VoiceRequest request)

  var callerId = ConfigurationManager.AppSettings["TwilioCallerId"];

  var response = new TwilioResponse();
  if (!string.IsNullOrEmpty(request.To))
  
    // wrap the phone number or client name in the appropriate TwiML verb
    // by checking if the number given has only digits and format symbols
    if (Regex.IsMatch(request.To, "^[\\d\\+\\-\\(\\) ]+$")) //(mma) supposed to be an outgoing call
    
      response.Dial(new Number(request.To), new  callerId );
    
    else //(mma) a call from one client to antorher
    
      response.Dial(new Client(request.To), new  callerId ); 
    
  
  else //(mma) incoming call from the TwiML App setting page
  
    response.Say("Thanks for calling!");
  
  return TwiML(response);

问题3.可分为以下两部分:

    如果在来电时我们想与预先指定的客户端(比如calledUser)建立真正的连接,而不是读出“感谢您的来电!”消息,我们应该将response.Say("Thanks for calling!"); 替换为response.Dial(cl, new request.From ); 其中cl = new Client(calledUser); 我们可以将calledUser 的值放入Local.config 中,这样我们就可以从那里读取它:var calledUser = ConfigurationManager.AppSettings["calledUser"]; 如果我们想接听来自真实电话的电话,那么我们应该认识到这种情况。这正是 request.To == callerId( = our Twilio phononumber) 的时候,所以我们必须根据这个拆分第一个条件。新分支将调用预先指定的用户。

将这些放在一起,VoiceController.cs 中的新代码将如下所示:

public ActionResult Index(VoiceRequest request)

  var callerId = ConfigurationManager.AppSettings["TwilioCallerId"];
  var calledUser = ConfigurationManager.AppSettings["calledUser"];


  var response = new TwilioResponse();
  if (!string.IsNullOrEmpty(request.To))
  
    // wrap the phone number or client name in the appropriate TwiML verb
    // by checking if the number given has only digits and format symbols
    if (Regex.IsMatch(request.To, "^[\\d\\+\\-\\(\\) ]+$"))
    
      if (request.To != callerId) //(mma) supposed to be an outgoing call
      
        response.Dial(new Number(request.To), new  callerId );
      
      else //(mma) supposed to be an incoming call from a real phone
      
        var cl = new Client(calledUser);
        response.Dial(cl, new  request.From );
      
    
    else //(mma) a call from one client to antorher
    
        response.Dial(new Client(request.To), new  request.From );
    
  
  else //(mma) incoming call from the TwiML App setting page
  
      var cl = new Client(calledUser);
      response.Dial(cl, new  request.From );
  
  return TwiML(response);

当然,如果我们想接听电话,那么我们应该使用预定义的用户名(calledUser)启动一个客户端。为此,我们可以引入一个新的 Url 参数User,将其值通过HomeController 放入TempData["User"],并将TokenController.cs 中的var identity = Internet.UserName().AlphanumericOnly(); 行更改为var identity = TempData["User"] == null ? Internet.UserName().AlphanumericOnly() : TempData["User"].ToString();

所以,我们的新 HomeController 和 TokenController 看起来像这样:

  public class HomeController : Controller
  
    public ActionResult Index(string user)
    
            TempData["User"] = user;
      return View();
    
  

还有这个:

  public class TokenController : Controller
  
    // GET: /token
    public ActionResult Index()
    
      // Load Twilio configuration from Web.config
      var accountSid = ConfigurationManager.AppSettings["TwilioAccountSid"];
      var authToken = ConfigurationManager.AppSettings["TwilioAuthToken"];
      var appSid = ConfigurationManager.AppSettings["TwilioTwimlAppSid"];

      // Create a random identity for the client
      var identity = TempData["User"] == null ? Internet.UserName().AlphanumericOnly() : TempData["User"].ToString();

      // Create an Access Token generator
      var capability = new TwilioCapability(accountSid, authToken);
      capability.AllowClientOutgoing(appSid);
      capability.AllowClientIncoming(identity);
      var token = capability.GenerateToken();

      return Json(new
      
        identity,
        token
      , JsonRequestBehavior.AllowGet);
    
  

当然,我们的 Local.config 文件应该包含这样一行:

  <add key="calledUser" value="TheNameOfThePreDefinedUser" />

【讨论】:

以上是关于在 Twilio 客户端快速入门中接收真正的来电的主要内容,如果未能解决你的问题,请参考以下文章

twilio停止接收消息

使用 ngrok 地址来电自动设置 Twilio webhook 地址

在 Android 原生来电屏幕上弹出窗口,如真正的来电者 Android 应用程序

Twilio 使用 Node.js 接收和回复 SMS

客快物流大数据项目(八十八):ClickHouse快速入门

twilio - 使用本地(在 NAT 之后)HTTP 服务器