如何通过PHP/Symfony+Twilio JS Voice SDK将排队呼叫转至会议室实现监控辅导
解决方案:基于Twilio TaskRouter实现排队呼叫转会议室+主管监控
核心思路:通过自定义Dequeue回调URL将入队呼叫接入动态专属会议室,再单独呼叫坐席、主管进入该会议室,全程保留TaskRouter的任务队列路由逻辑。
步骤1:服务器端新增会议室TwiML路由(PHP/Symfony)
创建控制器方法,生成将呼叫接入指定会议室的TwiML,用Reservation SID作为会议室名称后缀保证唯一性:
// src/Controller/VoiceController.php use Twilio\TwiML\VoiceResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** * @Route("/voice/conference", name="voice_conference") */ public function conferenceAction(Request $request) { $reservationSid = $request->query->get('reservationSid'); $conferenceName = 'support-call-' . $reservationSid; $voiceResponse = new VoiceResponse(); $voiceResponse->conference($conferenceName, [ 'startConferenceOnEnter' => true, 'endConferenceOnExit' => false, 'record' => 'record-from-answer', 'statusCallback' => 'https://your-domain.com/anon/voice/status', 'statusCallbackEvent' => 'initiated,ringing,answered,completed' ]); return new Response($voiceResponse->asXml(), Response::HTTP_OK, ['Content-Type' => 'text/xml']); }
步骤2:修改客户端Dequeue逻辑
不再直接将呼叫转接到坐席,而是先将排队呼叫导入会议室,再主动呼叫坐席进入该会议室:
this.dequeueReservation = function(data) { let reservation = self.getReservation(data.phone_number); if(!reservation) return; const conferenceName = 'support-call-' + reservation.sid; const dequeueUrl = `https://your-domain.com/voice/conference?reservationSid=${reservation.sid}`; // 1. 将排队呼叫转接到专属会议室 reservation.dequeue( dequeueUrl, null, 'record-from-answer', 30, 'https://your-domain.com/anon/voice/status', 'initiated,ringing,answered,completed', null, // 取消原contactUri参数,由dequeueUrl返回的TwiML处理路由 (error, newReservation) => { if(!error) { // 2. 呼叫坐席进入同一会议室 self.joinConference(conferenceName); } onDequeue(data, error, newReservation); } ); } // 新增方法:让坐席接入指定会议室 this.joinConference = function(conferenceName) { let contactUri = self.getContactUri(); if(!contactUri) return; self.twilioDevice.connect({ To: `conference:${conferenceName}`, AgentId: self.agent.id }); }
步骤3:实现主管监控/辅导功能
支持三种监控模式:监听(仅听不说)、耳语(仅和坐席对话)、辅导(三方通话),通过服务器端路由控制会议权限:
服务器端主管接入路由
/** * @Route("/voice/supervisor-conference", name="voice_supervisor_conference") */ public function supervisorConferenceAction(Request $request) { $conferenceName = $request->query->get('conferenceName'); $mode = $request->query->get('mode', 'listen'); $agentClientId = $request->query->get('agentClientId'); // 坐席的Twilio Client标识 $voiceResponse = new VoiceResponse(); $dial = $voiceResponse->dial(); $confParams = [ 'startConferenceOnEnter' => true, 'endConferenceOnExit' => false, 'beep' => 'true' ]; switch($mode) { case 'listen': $confParams['muted'] = true; break; case 'whisper': $confParams['whisper'] = $agentClientId; break; case 'coach': $confParams['coach'] = $agentClientId; break; } $dial->conference($conferenceName, $confParams); return new Response($voiceResponse->asXml(), Response::HTTP_OK, ['Content-Type' => 'text/xml']); }
客户端主管接入逻辑
// 主管后台调用此方法接入指定会议 function supervisorJoinConference(conferenceName, mode = 'listen', agentClientId) { const supervisorUri = `client:${self.supervisor.username}`; const connectUrl = `https://your-domain.com/voice/supervisor-conference?conferenceName=${conferenceName}&mode=${mode}&agentClientId=${agentClientId}`; self.supervisorDevice.connect({ To: supervisorUri, Url: connectUrl }); }
关键注意事项
- 会议室唯一性:用Reservation SID作为会议室名称后缀,避免不同呼叫的会议室冲突
- TaskRouter状态同步:Dequeue操作完成后,TaskRouter会自动更新任务状态,保留原队列路由逻辑
- 权限控制:主管接入功能需添加身份验证,仅授权用户可触发监控操作
- 会议参数调整:可根据业务需求修改
startConferenceOnEnter、endConferenceOnExit等参数,比如设置客户等待坐席接入时不启动会议
内容的提问来源于stack exchange,提问作者AQuirky
相关产品推荐
相关产品推荐

