实现Twilio掩码号码呼叫未接听时的语音留言功能

admin 百科 12

实现Twilio掩码号码呼叫未接听时的语音留言功能

实现Twilio掩码号码呼叫未接听时的语音留言功能-第2张图片-佛山资讯网

本文详细介绍了如何为twilio掩码号码的呼叫转发功能实现语音留言回退机制。当客户拨打掩码号码,而转发至用户真实号码的呼叫未能接通(如无人接听、占线或不可达)时,系统将引导客户录制语音留言。教程涵盖了twiml dial 动词的超时配置、record 动词的使用,以及如何通过webhook回调处理录音,实现语音留言的存储、转文本和邮件通知。

Twilio掩码号码呼叫转发与语音留言回退机制

在构建基于Twilio的通信应用时,为用户提供掩码号码并实现呼叫转发是常见需求。然而,当被转发的用户无法接听电话时,提供一个语音留言选项能显著提升用户体验。本教程将指导您如何结合Twilio的TwiML(Twilio Markup Language)动词,实现这一高级功能:当客户拨打掩码号码,且呼叫转发至用户真实号码失败时,自动引导客户录制语音留言。

核心概念与Twilio TwiML动词

实现此功能主要依赖于Twilio的两个TwiML动词:

  1. 动词与 timeout 属性:用于将当前呼叫连接到另一个电话号码。timeout 属性定义了Twilio在放弃尝试连接被叫方之前等待的时间(秒)。如果在此时间内被叫方未接听,Twilio将继续执行TwiML响应中的下一个动词。
  2. 动词与 recordingStatusCallback 属性:用于录制呼叫方的语音。recordingStatusCallback 属性指定一个URL,Twilio会在录音完成后向该URL发送HTTP请求,其中包含录音的详细信息和URL。

实现步骤

我们将基于现有的Express应用和Twilio Webhook配置进行扩展。

1. 配置呼叫转发与超时

首先,修改处理入站语音呼叫的/webhook/voice路由。在case "ringing"逻辑中,使用动词尝试将呼叫转发到用户的真实号码。关键在于为设置一个timeout属性。如果用户未在指定时间内接听,Twilio将执行TwiML响应中的下一个动词。

const twilio = require("twilio");
const express = require("express");
const router = express.Router();

// 假设这些是您的数据库和邮件发送工具函数
const { getNumberWithoutUser, updateQuota } = require("../db/dbOperations");
const { sendMessageNotificationEmail } = require("../emailing/email");
const { sendSms, client } = require("../twilioFunctions");
const { appendMessage } = require("../db/messagingCollectionUtils");
const { appendCall } = require("../db/callsCollectionUtils");

router.post("/webhook/voice", async (req, res) => {
  const { To, From, CallStatus } = req.body;

  const [numbers] = await getNumberWithoutUser(To);
  if (!numbers) {
    console.warn(`User does not own number: ${To}`);
    return res.status(400).send("User does not own this number");
  }

  const activeSubscription = numbers.numbers.subscriptions.find(
    (subscription) => subscription.active
  );
  if (!activeSubscription) {
    console.warn(`No active subscription for number: ${To}`);
    return res.send("Call Forwarding is disabled or package has finished");
  }

  const type = activeSubscription.type;
  const isToPrimaryPhone = numbers?.numbers?.settings?.forwarding?.toPrimaryPhone;
  const primaryPhoneNumber = numbers?.numbers?.settings?.forwarding?.primaryPhoneNumber;

  console.log("CallStatus", CallStatus);

  if (isToPrimaryPhone && primaryPhoneNumber) {
    const twiml = new twilio.twiml.VoiceResponse();

    switch (CallStatus) {
      case "ringing":
        // 尝试拨打用户主号码,设置15秒超时
        // 如果在15秒内未接听,Twilio将继续执行TwiML响应中的下一个动词
        twiml.dial({ timeout: 15 }, primaryPhoneNumber);

        // 如果呼叫未接通(超时、占线、无人接听),则播放提示音并开始录音
        twiml.say("您拨打的用户当前无法接听,请在哔声后留言,按星号键结束。");
        twiml.record({
          recordingStatusCallback: "https://your-ngrok-url/webhook/voicemail-callback", // 替换为您的Webhook URL
          maxLength: 60, // 最长录音时间60秒
          finishOnKey: '*' // 按星号键结束录音
        });
        twiml.say("感谢您的留言,再见。"); // 录音结束后播放
        twiml.hangup(); // 结束通话

        await updateQuota(numbers._id, To, "callForwarding", type);
        res.type("text/xml");
        return res.send(twiml.toString());

      case "completed":
        // 呼叫成功完成,记录通话信息
        await appendCall(numbers._id, To, From, req.body);
        return res.send("success");

      // 可以根据需要处理其他CallStatus,例如 "no-answer", "busy", "failed"
      // 但对于语音留言回退,主要逻辑已在 'ringing' 状态的TwiML中处理
    }
  } else {
    console.log("Call Forwarding is disabled or primaryPhoneNumber is not set.");
  }
  res.send("Call Forwarding is disabled or package has finished");
});

// 导出router以供主应用使用
module.exports = router;

登录后复制

代码解释:

标签: js app 工具 ai switch 路由 邮箱 red

发布评论 0条评论)

还木有评论哦,快来抢沙发吧~