아웃바운드 시 통화연결음 + 수취쪽에서 통화가 왔다고 울리지 않는다

크롬에 로컬네트워크 접근 허가 기능이 생겼는데, 해당 기능을 사용자가 인지못함

(별도 알림창이나 팝업이 뜬 경우 이번에만 허용을 눌렀거나 그냥 닫은 경우일 수 있겠다.)

<aside> 💡

Chrome 142부터 로컬 네트워크 액세스 권한 메시지가 정식 출시됩니다.

공개 웹사이트(HTTPS)에서 사용자의 로컬 네트워크(192.168.x.x, 127.0.0.1 등)로 요청을 보낼 때 사용자 권한 승인이 필수가 됩니다.

</aside>

사용중인 amozon-connect-streams 자체는 문제가 없으나 initCCP의 ***allowSoftPhone*** 을 키는 순간 문제가 발생한다.

그럼 allowSoftPhone옵션을 사용하면 내부적으로 발생하는 단계에 대해 알아보자.

1단계: initCCP()SoftphoneManager 생성

// core.js (initCCP 내부)
connect.core.initSoftphoneManager = function(softphoneParams) {
  connect.core.softphoneManager = new SoftphoneManager(softphoneParams);
};

2단계: SoftphoneManager 생성자 → RtcPeerConnectionFactory 생성

var SoftphoneManager = function (softphoneParams = {}) {

  // 핵심: 부모 페이지 컨텍스트에서 RtcPeerConnectionFactory 생성
  this._refreshRtcPeerConnectionFactory = function () {
    this.rtcPeerConnectionFactory = new connect.RtcPeerConnectionFactory(
      logger,
      connect.core.getWebSocketManager(),
      softphoneClientId,
      connect.hitch(self, requestIceAccess, { // ← AWS에 ICE 서버 정보 요청
        transportType: "softphone",
        softphoneClientId: softphoneClientId
      }),
      connect.hitch(self, publishError)
    );
  };

  this._refreshRtcPeerConnectionFactory(); // 즉시 실행

3단계: 통화 감지 → startSession() 호출

// 연락(contact) 이벤트 감지
var onRefreshContact = function (contact, agentConnectionId) {

  if (contact.isSoftphoneCall() && !callsDetected[agentConnectionId] && (
    contact.getStatus().type === connect.ContactStatusType.CONNECTING ||
    contact.getStatus().type === connect.ContactStatusType.INCOMING
  )) {
    // 통화 감지 → startSession 호출
    self.startSession(contact, agentConnectionId);
  }
};

4단계: startSession()RTCSession(RTCPeerConnection) 생성

this.startSession = function (_contact, _agentConnectionId) {

  // RTCSession 생성 = 내부적으로 RTCPeerConnection 생성
  session = new connect.RTCSession(
    callConfig.signalingEndpoint,  // WebSocket 시그널링
    callConfig.iceServers,         // STUN/TURN 서버
    softphoneInfo.callContextToken,
    logger,
    contact.getContactId(),
    agentConnectionId,
    webSocketProvider
  );
};

RTCSession객체를 만들고 초기화하는 과정에서 다음의 로직이 추가적으로 들어감

결과적으로 setLocalDescription()과정에서 local network의 검증이 들어간다.

connect.RTCSession
    │
    ├── navigator.mediaDevices.getUserMedia()   ← 마이크 권한
    │       ↓
    ├── new RTCPeerConnection(iceServers)        ← P2P 연결 객체 생성
    │       │
    │       ├── .createOffer()                  ← SDP Offer 생성
    │       ├── .setLocalDescription()          ← 로컬 SDP 설정
    │       │       ↓
    │       │   onicecandidate 이벤트 시작       ← ★ LNA 트리거 지점
    │       │   192.168.x.x, 127.0.0.1 수집
    │       │
    │       ├── .setRemoteDescription()         ← AWS Answer SDP 적용
    │       ├── .addIceCandidate()              ← 원격 ICE 후보 추가
    │       ├── .getStats()                     ← RTP 통계 수집 (30초마다)
    │       └── .getSenders()[0].replaceTrack() ← 마이크 장치 교체
    │
    ├── new WebSocket(signalingEndpoint)        ← 시그널링 서버 연결
    │   wss://rtc.connect-telecom.*.amazonaws.com
    │
    └── new RTCIceCandidate(initDict)           ← ICE 후보 객체 생성

LNA와 직접 연결되는 지점 정리

setLocalDescription()을 호출하는 순간 브라우저가 ICE 수집을 시작하고, onicecandidate 콜백에서 192.168.x.x127.0.0.1 같은 로컬 IP가 등장합니다. Chrome 142+는 바로 이 시점에 LNA 권한 프롬프트를 띄웁니다.

방어 로직 넣어두기