<aside>

</aside>

개요

여느 화상 회의 플랫폼 처럼 현재 말하고있는 참가자가 누구인지를 시각적으로 알려주는 기능이 필요하다. 특히 비디오를 끄고 있는 상황에서는 누가 말하고 있는 것인지 알 수가 없으므로, 이 기능은 UX 측면에서 굉장히 중요한 부분이라고 볼 수 있다.

‘누가 말하고 있는지’를 어떻게 판단할 수 있을까? 상대적이지만, 오디오 스트림의 볼륨을 획득해서 특정 임계값 이상인 경우 활성 화자라고 판단하는 식으로 구현할 수 있을 것이다.

이를 구현하기 위한 방법을 알아보자!

자료 조사

분명 같은 기능을 구현하기 위해 고군분투한 개발자들이 있을 것이다.

처음으로 발견한 기술은 GetSynchronizationSources()라는 메소드이다.

GetSynchronizationSources

Checking audio levels - WebRTC Courses

이 메소드는 WebRTC에서, 현재 RTC 연결에서 사용 가능한 모든 동기화 소스(SSRC)의 정보를 가져오기 위해 사용한다. 동기화 소스란 미디어 스트림을 고유하게 식별하는 식별자이다.

예를 들어 한 참가자가 비디오와 오디오를 전송하고 있을 때, 각각의 스트림은 서로 다른 SSRC를 가지게 되는데 이때 GetSynchronizationSources()를 호출하면 각 SSRC의 상세한 정보를 알 수 있다. 즉 이 메소드는 RTCRtpReceiver 객체에 대해 호출한다. 이 객체가 미디어 스트림을 수신하는 역할을 하기 때문이다. 따라서 이 메소드를 호출하면 현재 수신 중인 스트림에 대한 정보를 알 수 있는 것이다.

활성 화자 표시를 위해 이 메소드가 필요한 이유는, 바로 그 반환 값에 audioLevel이라는 속성이 있기 때문이다. 따라서 이 메소드를 통해 현재 받고 있는 스트림의 오디오 레벨이 얼마인지 알 수 있고, 특정 임계값 이상이라면 원하는 행동을 취할 수 있을 것이다.

예를 들어 다음과 같이 사용할 수 있다.

setInterval(() => {
  const sources = audioReceiver.getSynchronizationSources();
  sources.forEach(source => {
      // audioLevel이 0.1 이상인 경우를 활성 발화자로 간주
      if (source.audioLevel > 0.1) {
          console.log(`활성 발화자 SSRC: ${source.ssrc}`);
          // UI에 표시하기 위한 로직
      }
  });
}, 100); // 100ms 마다 체크

그러나 이 방식은 우리 프로젝트에 적합하지 않았다.

우리는 순수 WebRTC를 사용하는 것이 아니라 mediasoup를 통해 SFU 방식으로 구현하고 있기 때문이다. 순수 WebRTC에서는 브라우저 간에 직접적인 P2P 연결이 이루어지기 때문에, 각 브라우저에서 RTCPeerConnection 인스턴스를 통해 상대방의 미디어 스트림을 직접 받아오게 된다. GetSynchronizationSources 메소드는 이 RTCPeerConnection의 reciver에 대해 호출할 수 있는 메소드인 것이다.

그러나 mediasoup를 사용할 때는, 참가자들이 서로 직접 연결하는 것이 아니라 미디어 서버를 통해 통신하기 때문에 원본 스트림이 이미 서버에서 처리되어 전달된다. 따라서 구조적으로 GetSynchronizationSources 메소드를 사용할 수 없는 것이다.