webrtc

7 개의 포스트

cloudflare

MoQ를 위한 API: 자체 격리 릴레이 프로비저닝 (새 탭에서 열림)

Cloudflare는 MoQ(Media over QUIC)를 애플리케이션용으로 운영할 수 있도록 격리된 릴레이와 인증·권한 관리 기능을 추가했다. 프로비저닝 API나 대시보드에서 릴레이를 생성하면 별도 서버나 로드 밸런서 없이 Cloudflare 전역 네트워크에 수초 내 배포된다. 퍼블리셔와 구독자에게 서로 다른 토큰을 발급해 실시간 미디어 스트림의 접근 권한도 분리할 수 있다. ## MoQ의 구조와 장점 - MoQ는 IETF에서 개발 중인 공개 표준 기반의 publish/subscribe 프로토콜이다. - 퍼블리셔는 이름이 지정된 데이터 스트림을 전송하고, 구독자는 스트림 이름으로 원하는 데이터를 요청한다. - 릴레이는 데이터 내용을 해석하지 않고 스트림을 구독자들에게 복제·전달한다. - 하나의 프로토콜로 라이브 비디오, 화상 통화, 저지연 메시징 등 다양한 실시간 데이터를 처리할 수 있다. - QUIC을 기반으로 하므로 HTTP/3와 같은 낮은 지연 특성을 활용한다. - 애플리케이션이 직접 미디어 서버를 구축하거나 대규모 fan-out 서버를 운영할 필요가 줄어든다. ## 공개 프리뷰의 한계 - Cloudflare는 지난해 330개 이상의 도시에 있는 서버를 MoQ 릴레이로 개방했다. - 인증 없이 누구나 사용할 수 있어 프로토콜 테스트와 클라이언트 개발에 적합했다. - 그러나 인증이 없으면 누가 퍼블리시하거나 구독할 수 있는지 통제할 수 없다. - 예를 들어 경매 서비스에서는 시청자가 방송자의 트랙을 탈취하지 못하도록 퍼블리셔와 구독자의 권한을 분리해야 한다. - 따라서 기밀성, 인증, 역할 기반 접근 제어가 필요한 운영 환경에는 기존 공개 릴레이를 사용할 수 없었다. ## Cloudflare 릴레이의 격리 방식 - 릴레이를 생성해도 VM, 컨테이너, 전용 프로세스가 새로 실행되는 것은 아니다. - 기존 Cloudflare 글로벌 네트워크 위에 애플리케이션별 격리된 범위를 생성한다. - 각 범위는 다음을 분리한다. - 애플리케이션의 네임스페이스 - 미디어 트랙과 객체 - 접속 가능한 클라이언트 - 퍼블리시·구독 권한 - 클라이언트는 Anycast 엔드포인트에 접속하고, Cloudflare가 전 세계 네트워크로 라우팅한다. - 지역 선택, 용량 산정, 서버 배포, 로드 밸런서 설정 없이 즉시 사용할 수 있다. - 웹 호스팅에서 새 서버를 띄우는 것보다 가상 호스트를 추가하는 방식에 가깝다. ## 프로비저닝 API와 토큰 권한 - 프로비저닝 API는 미디어 데이터를 처리하지 않는 제어 평면이다. - 관리 대상은 두 가지다. - **Relay**: 애플리케이션별로 격리된 MoQ 실행 범위 - **Token**: 특정 릴레이에 대한 작업 권한을 부여하는 인증 정보 - 토큰은 다음 권한을 조합할 수 있다. - `publish` - `subscribe` - `publish`와 `subscribe` 모두 - 토큰마다 만료 시간을 설정할 수 있고, 개별적으로 폐기할 수 있다. - 기본적으로 토큰 권한은 릴레이 전체에 적용된다. - 현재는 세부 트랙별 권한보다 릴레이 단위 권한을 제공하며, 향후 더 정교한 권한 체계를 개발할 예정이다. - Cloudflare는 MoQ Transport draft-14와 draft-16 및 인증 기능을 지원한다. ## 릴레이 생성과 기본 토큰 - HTTP API에서는 릴레이 이름만 지정해 생성할 수 있다. - 생성 결과로 릴레이 ID와 기본 토큰 2개가 반환된다. - 퍼블리시와 구독이 모두 가능한 토큰 - 구독만 가능한 토큰 - 추가 토큰을 생성해 시청자, 방송자, 운영 도구 등 역할별로 권한을 세분화할 수 있다. - 예를 들어 시청자용 토큰은 `subscribe`만 허용하고, 2027년 1월 1일 만료되도록 설정할 수 있다. - 동일한 작업은 Cloudflare 대시보드의 **Media > Realtime > MoQ Relay** 메뉴에서도 수행할 수 있다. - 릴레이는 베타 기간 동안 무료로 제공된다. ## 퍼블리셔와 구독자의 연결 - 방송자에게는 `publish` 권한이 포함된 토큰을 제공한다. - 시청자에게는 `subscribe` 전용 토큰을 제공한다. - 클라이언트는 MoQ 세션을 열 때 토큰을 전달한다. - 릴레이는 토큰의 권한을 확인해 퍼블리시와 구독 작업을 허용하거나 거부한다. - 토큰은 MoQ 접속 URL 경로를 통해 전달되며, `moq-rs` 같은 오픈소스 도구와 FFmpeg를 이용해 fragmented MP4 스트림을 퍼블리시할 수 있다. ## 실용적인 결론 실시간 영상이나 저지연 데이터 서비스를 구축한다면 Cloudflare MoQ 릴레이를 통해 서버 운영과 확장 부담을 줄일 수 있다. 운영 시에는 방송자와 시청자 토큰을 반드시 분리하고, 만료 기간과 폐기 정책을 설정해 권한 탈취 위험을 최소화하는 것이 좋다.

line

AI로 웹 엔지니어 없이 LINE 앱 안에서 그룹 영상 통화 서비스 만들기 (새 탭에서 열림)

LINE OA와 LIFF, LINE Planet SDK를 결합하면 별도 앱 설치 없이 LINE 안에서 그룹 영상 통화 서비스를 구현할 수 있다. 글에서는 LINE Planet 팀의 PM과 Android 엔지니어가 웹 엔지니어 없이 만든 사례를 바탕으로, LIFF 웹 앱과 액세스 토큰 발급용 앱 서버만 직접 개발하면 된다는 구조를 설명한다. LINE의 인증·WebRTC·글로벌 네트워크 인프라를 활용하므로 핵심은 각 컴포넌트를 연결하고 통화 흐름을 구현하는 것이다. ## LINE OA와 LIFF의 역할 - **LINE OA** - 사용자와 소통하는 접점이자 서비스 진입 채널이다. - 상담, 교육, 라이브 방송, 게임 음성 채팅 등 다양한 서비스를 제공할 수 있다. - **LIFF** - LINE 앱 내부 웹뷰에서 실행되는 웹 애플리케이션이다. - LINE 로그인 정보인 `userId`, `displayName` 등을 전달하므로 별도 인증 서버 없이 사용자를 식별할 수 있다. - **LINE Planet** - WebRTC 기반의 음성·영상 통화와 미디어 처리를 담당한다. - 글로벌 네트워크 인프라를 제공해 개발자가 통화 인프라를 직접 구축하지 않아도 된다. ## 구현해야 하는 전체 구조 - 직접 개발할 부분은 크게 두 가지다. - LIFF에서 실행되는 그룹 영상 통화 웹 앱 - LINE Planet 액세스 토큰을 발급하는 앱 서버 - 앱 서버는 Firebase Cloud Functions로 구성하면 별도의 서버 인프라 설정을 줄일 수 있다. - LINE OA와 LIFF가 사용자 인증을, LINE Planet이 미디어 통신을 처리하므로 개발자는 서비스 화면과 연결 로직에 집중할 수 있다. - 실제 구현 대상은 웹 앱 레이어와 서버 레이어의 앱 서버이며, LINE OA·LIFF·LINE Planet의 기반 기능은 외부 플랫폼을 활용한다. ## 적용 가능한 서비스 사례 - **전문 상담** - 변호사, 재무 설계사, 심리 상담사와의 1:1 화상 상담 - 별도 앱 설치 없이 LINE 앱에서 상담방 입장 - **원격 교육** - 수업 예약과 화상 수업을 LINE OA에서 제공 - 여러 강사가 동시에 독립적인 통화방 운영 가능 - 화면 공유를 이용한 문서·문제 풀이 지원 - **실시간 소통 방송** - 기본 500명에서 최대 1만 명까지 동시 참여 가능 - 팬미팅, 라이브 이벤트, 진행자와 청중이 대화하는 양방향 방송 구현 - **게임 음성 채팅** - LINE 친구와 게임 중 별도 앱 전환 없이 실시간 음성 대화 ## 개발 전 준비 사항 - **개발 환경** - Node.js 20 LTS 이상 - npm 기반 프로젝트 - LIFF 특성상 HTTPS 배포 필요 - 로컬 개발에서는 ngrok 같은 HTTPS 터널링 도구 사용 가능 - **LINE Developers 설정** - Business ID로 개발자 계정 등록 - Provider 생성 - LINE OA 생성 후 Messaging API 활성화 - 같은 Provider에 LINE Login 채널 생성 - LINE Login 채널의 LIFF 탭에서 LIFF 앱 등록 - **주의할 설정** - 발급된 LIFF ID를 이후 모든 초기화 과정에서 사용하므로 별도 보관해야 한다. - 친구 초대 기능인 `shareTargetPicker`를 사용하려면 LINE Login 채널이 `Published` 상태여야 한다. - **LINE Planet 준비** - LINE Planet Console 계정과 서비스 ID가 필요하다. - 해당 정보는 LINE Planet 팀에 요청해 발급받는다. ## 통화방 ID 설계 - 사용자가 통화에 입장하기 전에 방 ID를 생성하거나 URL에서 복원한다. - 데모에서는 `crypto.randomUUID()`에서 하이픈을 제거한 뒤 앞 16자리를 사용해 랜덤 방 ID를 만든다. - 초대 링크에 `roomId`가 포함되어 있으면 query string에서 해당 값을 읽어 같은 방에 입장한다. - 서비스 목적에 따라 다음과 같이 확장할 수 있다. - 관심사별 고정 방 - 사용자 그룹별 자동 방 생성 - 예약된 수업이나 상담 일정에 연결된 방 - 방 ID 자체만으로 권한을 판단하지 말고, 실제 서비스에서는 서버에서 접근 권한과 만료 여부를 검증해야 한다. ## `MediaStreamManager`를 활용한 미리보기 - 일반적인 웹 구현의 `getUserMedia` 대신 PlanetKit의 `MediaStreamManager`를 사용한다. - 미리보기 화면에서 생성한 MSM 인스턴스를 통화방 입장 후에도 재사용할 수 있다. - 이 방식의 장점은 다음과 같다. - 페이지 전환 시 카메라와 마이크 권한을 다시 요청하지 않음 - 모바일 웹뷰에서 권한 프롬프트가 반복적으로 노출되는 문제 완화 - 기존 미디어 스트림을 통화 연결 과정까지 유지 - 구현 흐름은 다음과 같다. - 컴포넌트 마운트 시 `MediaStreamManager`를 한 번 생성 - 비디오가 켜져 있으면 `createMediaStream()`으로 미디어 스트림 생성 - 이미 스트림이 있으면 `changeVideoInputDevice()`로 비디오 입력 장치만 교체 - 스트림을 HTML `<video>` 요소의 `srcObject`에 연결 - 마이크 끄기/켜기는 권한을 다시 요청하지 않고 오디오 트랙의 `enabled` 속성만 변경한다. ## 모바일 카메라 전환 처리 - 모바일 기기에서는 전면·후면 카메라 전환 기능을 제공할 수 있다. - `useIsMobileDevice`로 모바일 환경을 판별하고, 모바일에서만 전환 버튼을 노출한다. - `resolveFacingModeDeviceId`를 통해 `front` 또는 `back` 방향에 해당하는 카메라 장치 ID를 찾는다. - 카메라가 꺼진 상태에서는 전환 버튼을 비활성화해 불필요한 장치 변경을 막는다. - 데스크톱에서는 기본 장치를 사용하고, 모바일에서는 방향 기반 장치 선택을 적용한다. ## 데모 코드의 범위와 주의점 - 글의 코드는 핵심 흐름을 보여주는 데모 코드다. - 통화 셋업, 미리보기, 통화 화면의 세부 UI와 전체 사용자 경험은 직접 구현해야 한다. - 프로덕션 적용 전 다음 항목을 추가 검토해야 한다. - 액세스 토큰 및 방 접근 권한 보안 - 네트워크 오류와 권한 거부 처리 - 통화 종료 및 리소스 정리 - 모바일 브라우저별 호환성 - 성능 최적화와 사용자 상태 동기화 - 앱 서버에서는 LINE Planet 액세스 토큰을 안전하게 발급하고 클라이언트에 비밀 키가 노출되지 않도록 해야 한다. ## 실용적인 결론 LINE OA를 이미 운영 중이라면 LIFF와 LINE Planet을 조합해 상담·교육·방송 같은 실시간 서비스를 빠르게 확장할 수 있다. 초기 구현은 랜덤 방 ID, `MediaStreamManager` 기반 미리보기, Firebase Cloud Functions 기반 토큰 서버로 단순화할 수 있지만, 실제 출시 단계에서는 방 권한 검증과 토큰 보안, 모바일 환경의 예외 처리를 반드시 보강해야 한다.

discord

Discord 음성을 엣지로 이전한 방법 (새 탭에서 열림)

Discord는 음성·영상 트래픽을 기존 약 30개 클라우드 리전에서 Cloudflare의 300개 이상 엣지 PoP로 이전해 사용자와 가까운 서버를 제공하려 했다. 그 결과 전체 트래픽의 80% 이상이 Cloudflare에서 처리되고, 프랑크푸르트에서는 평균 핑이 34%, 패킷 손실이 42% 감소했다. 그러나 단순히 가까운 PoP를 추가하는 것만으로는 충분하지 않았으며, 통화 호스트 배치와 ISP 간 네트워크 경로·피어링 상태가 품질을 좌우했다. ## 클라우드 리전에서 엣지 네트워크로 - 기존 인프라는 주요 클라우드 사업자의 데이터센터가 있는 약 30개 도시 중심으로 구성됐다. - Reykjavik, Auckland, Lagos 등 일부 지역은 가까운 음성 서버가 없어 수백 km 떨어진 리전으로 트래픽이 우회했다. - Cloudflare는 300개 이상의 도시에서 소규모 PoP를 운영하므로 사용자와 더 가까운 위치에 Discord의 음성·영상 서버를 배치할 수 있었다. - CDN은 주로 정적 콘텐츠 캐싱에 사용되지만, Discord는 Cloudflare 네트워크에서 실시간 UDP 패킷을 처리하는 방식을 적용했다. - 이전보다 지리적 커버리지는 크게 넓어졌지만, 각 PoP에 Discord 소프트웨어를 배포하고 운영해야 하는 부담은 남았다. ## 아이슬란드: 가까운 서버가 항상 최선은 아니다 - 2025년 2월, Reykjavik PoP에 음성 서버를 배치해 첫 실험을 진행했다. - 아이슬란드 사용자끼리 통화할 때는: - 핑 9% 감소 - 패킷 손실 11% 감소 - 그러나 아이슬란드와 독일처럼 여러 지역의 사용자가 섞인 통화에서는: - 비아이슬란드 사용자 핑이 2.7배 증가 - 패킷 손실 9% 증가 - Discord는 하나의 SFU가 통화 전체를 호스팅하고, 모든 참가자가 통화가 끝날 때까지 해당 SFU에 연결되는 구조다. - 따라서 독일 사용자 3명과 아이슬란드 사용자 1명의 통화가 Reykjavik에 배정되면, 독일 사용자들의 패킷이 아이슬란드까지 갔다가 돌아와야 했다. - 이 경험을 통해 새로운 PoP를 추가하는 것보다, 통화가 실제로 지역적으로 유지되도록 호스트 배치 로직을 개선하는 것이 중요하다는 점을 확인했다. ## 로테르담: ISP 피어링이 병목이 되다 - 2025년 4월, 기존 로테르담 트래픽을 Cloudflare의 암스테르담 PoP로 이전했다. - 대부분의 ISP에서는 문제가 없었지만, 프랑스 ISP Orange 사용자에게 심각한 품질 저하가 발생했다. - 피크 시간대 Orange 사용자의 통화 지연은 1초를 넘었고, 음성 프리즈 비율은 30% 악화됐다. - 원인은 Cloudflare 자체가 아니라 Orange와 암스테르담 사이의 네트워크 경로였다. - Orange와 Cloudflare의 연결은 Telia의 중계망을 거쳤으며, 피크 시간대 Telia와 Orange 간 인계 구간이 이미 포화 상태였다. - Cloudflare로 트래픽을 더 많이 옮길수록 해당 구간의 혼잡이 심해지는 구조였다. ## 롤백과 피어링 중심의 배포 전략 - Discord는 약 10일 후 암스테르담 이전을 되돌리고, 기존 공급자의 용량으로 Orange 트래픽을 처리했다. - 이후 Cloudflare는 Orange와 직접 피어링을 협상했다. - Orange 트래픽에 더 짧은 경로를 제공하기 위해 파리와 런던 PoP에 SFU를 배치했다. - 이 사건 이후 지역 이전 여부를 단순한 서버 용량이 아니라 ISP별 피어링 여유 공간을 기준으로 판단했다. - 주요 ISP와 Cloudflare 사이의 경로가 포화되어 있으면 해당 지역의 마이그레이션을 보류하는 방식으로 배포 절차를 변경했다. ## 마이그레이션에서 얻은 교훈 - 가까운 PoP는 일반적으로 지연 시간을 줄이지만, 통화 참가자가 여러 지역에 분산되어 있으면 전체 품질을 악화시킬 수 있다. - 최적의 서버 위치는 사용자와의 물리적 거리만으로 결정되지 않는다. - SFU 호스트 배치, 참가자 분포, ISP 간 라우팅, 트랜짓 사업자의 용량을 함께 고려해야 한다. - 초기에는 대규모 지역을 빠르게 이전하려 했지만, 아이슬란드와 로테르담 사례 이후 지역별·단계별 rollout으로 전환했다. - 결과적으로 배포 속도는 느려졌지만, 피어링 분석과 점진적인 트래픽 전환을 통해 장애 위험을 줄일 수 있었다. 실무적으로는 엣지 서버를 늘리는 것보다 먼저 통화·세션의 호스트 배치 정책과 ISP별 네트워크 경로를 분석해야 한다. 특히 글로벌 실시간 서비스는 서버 위치, 사용자 분포, 피어링 용량을 함께 검증한 뒤 소규모 트래픽으로 단계적으로 이전하는 전략이 안전하다.

meta

포크에서 벗어나기: Meta가 50개 이상의 유스케이스에서 WebRTC를 현대화한 방법 (새 탭에서 열림)

메타는 대규모 오픈소스 프로젝트인 WebRTC를 커스터마이징하여 사용하며 겪었던 '포크 트랩(Forking Trap)'을 해결하기 위해, 최신 업스트림 버전과 내부 최적화 버전을 동시에 실행할 수 있는 듀얼 스택 아키텍처를 구축했습니다. 이를 통해 50개 이상의 유즈케이스에서 안전하게 A/B 테스트를 수행하며 성공적인 마이그레이션을 마쳤고, 결과적으로 성능 향상과 바이너리 크기 최적화 및 보안 강화를 달성했습니다. 현재 메타는 이 구조를 바탕으로 모노레포 환경에서도 업스트림의 최신 업데이트를 지속적으로 반영하며 기술적 부채 없이 서비스를 운영하고 있습니다. **포크 트랩과 모노레포 환경의 도전 과제** * 오픈소스 프로젝트를 내부적으로 포크하여 오래 사용하면 업스트림과의 격차가 벌어져 최신 기능을 반영하기 어려워지는 '포크 트랩'이 발생합니다. * 빌리언 단위의 사용자를 보유한 서비스에서 대규모 라이브러리를 한 번에 교체하는 것은 리스크가 크기 때문에, 구버전과 신버전을 동시에 실행하며 검증할 수 있는 A/B 테스트 역량이 필수적이었습니다. * 하지만 메타의 모노레포 환경과 정적 링크(Static Linking) 방식에서는 동일한 라이브러리의 두 버전을 동시에 포함할 때 '단일 정의 원칙(ODR)' 위반으로 인한 수천 개의 심볼 충돌 문제가 발생했습니다. **심(Shim) 레이어와 듀얼 스택 아키텍처** * 애플리케이션과 WebRTC 구현체 사이에 프록시 역할을 하는 '심(Shim) 레이어'를 구축하여 통합된 API를 제공했습니다. * 애플리케이션은 버전과 무관한 심 API를 호출하고, 심 레이어는 런타임 설정(Flavor)에 따라 레거시 또는 최신 구현체로 호출을 전달합니다. * 모든 라이브러리를 복제하는 대신 최하위 레이어에서 심을 구현함으로써, 바이너리 크기 증가폭을 예상치(38MB) 대비 약 87% 감소한 5MB 수준으로 억제했습니다. **심볼 충돌 해결과 하위 호환성 유지** * 자동화된 네임스페이스 재명명(Renamespacing) 스크립트를 통해 `webrtc::` 네임스페이스를 각 버전에 맞게 `webrtc_legacy::`, `webrtc_latest::` 등으로 분리했습니다. * 네임스페이스 외부에 존재하는 글로벌 C 함수와 변수들은 버전별 식별자를 추가하여 충돌을 방지했습니다. * 기존 코드의 수정을 최소화하기 위해 C++의 `using` 선언을 활용하여, 외부 호출부에서는 여전히 기존 네임스페이스를 사용하는 것처럼 보이게 하면서 내부적으로는 올바른 버전에 연결되도록 설계했습니다. **런타임 버전 디스패치 및 관리** * 템플릿 기반의 헬퍼 라이브러리를 사용하여 중복 로직을 줄이고 버전별 특화 동작을 정의했습니다. * 앱 시작 시점에 결정되는 글로벌 플래그(Enum)를 통해 어떤 WebRTC 버전을 사용할지 동적으로 결정합니다. * 패치 관리의 복잡성을 해결하기 위해 모노레포 내에서 업스트림 버전을 주기적으로 가져오고 내부 패치를 반복적으로 적용하는 워크플로우를 정립했습니다. 대규모 오픈소스 프로젝트를 운영할 때 직접적인 포크보다는 이와 같은 모듈식 아키텍처와 자동화된 네임스페이스 관리를 도입하는 것이 기술적 고립을 막는 효과적인 전략이 될 수 있습니다. 이는 특히 안전한 배포와 지속적인 업스트림 동기화가 중요한 대규모 시스템에서 실무적인 해법을 제시합니다.

discord

모든 디스코드 (새 탭에서 열림)

Discord는 음성·영상 통화의 표준을 DAVE 기반 종단간 암호화(E2EE)로 전환하며, 브라우저·콘솔·Social SDK까지 지원 범위를 확대한다. 2026년 3월 1일부터는 DAVE를 지원하지 않는 클라이언트와 앱이 Discord 통화에 참여할 수 없다. 브라우저 환경에서는 WebRTC Encoded Transform API, Web Worker, WebAssembly를 조합해 보안성과 성능을 확보했다. ## DAVE의 전 플랫폼 확대 - DAVE는 Discord의 음성·영상 통화에 E2EE를 제공하는 프로토콜이다. - 이미 매일 수천만 건의 통화에 적용되고 있으며, 이번 작업으로 다음 플랫폼까지 지원한다. - 웹 브라우저 - 콘솔 - Discord Social SDK - 2026년 3월 1일부터 비-DAVE 클라이언트는 음성 채널과 영상 통화에 참여할 수 없다. - 이는 기존 실험적 도입을 종료하고 DAVE를 Discord 통화의 기본 보안 표준으로 삼는 단계다. ## WebRTC Encoded Transform API 활용 - 브라우저에서는 WebRTC 미디어 파이프라인 내부의 인코딩 전후 지점에서 오디오·영상 프레임을 암호화한다. - Encoded Transform API를 사용하면 브라우저의 코덱과 WebRTC 기능을 유지하면서 DAVE 암호화를 삽입할 수 있다. - Discord는 H.265, AV1 등 최신 코덱의 하드웨어 지원도 활용할 수 있도록 설계했다. - 더 높은 화질 - 더 효율적인 대역폭 사용 - 플랫폼별 코덱 지원 유지 ## Firefox에서 발견한 교착 상태 문제 - 초기 테스트에서는 Firefox에서도 DAVE가 정상 작동했지만, 실제 Discord 통화에서는 암호화용 Web Worker가 프레임을 받지 못했다. - 원인은 Firefox의 `FrameTransformerProxy`가 비디오 데이터가 너무 일찍 전달될 때 교착 상태에 빠지는 엣지 케이스였다. - 지연 처리를 위해 저장된 비디오 데이터가 뮤텍스를 사용했으며, 변환 작업이 같은 뮤텍스에 재진입하면서 재귀적 교착이 발생했다. - Discord 팀은 Firefox를 직접 빌드해 브라우저 수준에서 문제를 추적하고 Mozilla에 패치를 제출했다. - 수정 사항은 Firefox 142.0에 포함되며, DAVE를 사용하려면 최소 Firefox 142.0이 필요하다. ## Web Worker 기반 암호화 구조 - 각 Discord 연결은 미디어 암호화와 복호화를 담당하는 전용 Web Worker를 사용한다. - 일반 통화에서는 다음 미디어를 처리한다. - 통화 오디오 - 카메라 영상 - 화면 공유나 게임 스트림은 오디오와 영상별로 별도의 Worker가 처리한다. - 각 WebRTC 스트림에는 고유한 SSRC가 있으며, DAVE는 SSRC를 기준으로 프레임에 사용할 대칭키를 식별한다. - Worker는 다음과 같은 최소한의 상태만 유지한다. - 송수신 오디오·영상 정보 - SSRC와 사용자 ID의 매핑 - 각 사용자에 대한 암호화 키 ## 메인 스레드와 암호화 Worker의 역할 분리 - 메인 JavaScript 스레드는 WebRTC 연결과 참여자, 미디어 트랙을 관리한다. - 사용자 입장·퇴장 시 필요한 MLS(Message Layer Security) 협상도 메인 스레드에서 수행한다. - MLS 그룹 변경을 Worker에서 처리하지 않기 때문에, Worker가 프레임 암호화를 끝낼 때까지 메인 스레드가 대기할 필요가 없다. - MLS 상태가 바뀌면 메인 스레드가 Worker에 비동기 메시지를 보내 암호화 상태를 갱신한다. - 이 구조는 멤버 변경 중에도 미디어 암호화를 계속 수행해 통화 지연을 줄인다. ## 검증된 C++ 구현의 WebAssembly 재사용 - Discord는 데스크톱과 모바일에서 이미 대규모로 검증된 DAVE C++ 코드베이스를 WebAssembly로 컴파일했다. - 동일한 암호화 구현을 여러 플랫폼에서 재사용하면 플랫폼별 재구현으로 인한 보안 취약점과 동작 차이를 줄일 수 있다. - WebRTC 패킷에는 라우팅과 패킷 처리를 위해 일부 메타데이터가 평문으로 남아 있어야 한다. - 암호화된 데이터가 WebRTC 패킷화기, SFU, 역패킷화기를 거치는 동안 변경되면 복호화가 실패한다. - 따라서 프레임을 바이트 단위로 파싱하고 필요한 부분만 선택적으로 암호화해야 한다. - 이 작업은 JavaScript로 직접 구현하기에는 복잡하고 오류 가능성이 높지만, WebAssembly를 사용하면 네이티브에 가까운 성능으로 처리할 수 있다. ## WebAssembly와 SubtleCrypto의 성능 절충 - WebAssembly는 프레임 파싱과 선택적 암호화 로직을 효율적으로 처리한다. - 반면 암호화 연산 자체는 브라우저의 네이티브 API인 `SubtleCrypto`보다 약간 느릴 수 있다. - Discord의 벤치마크는 두 방식의 성능 차이가 단순하지 않으며, 실제 병목이 암호화 연산뿐 아니라 프레임 처리와 데이터 이동에도 있음을 시사한다. - 최종 선택은 단순한 최고 암호화 속도보다 다음 요소를 종합한 결과다. - 검증된 코드 재사용 - 플랫폼 간 동작 일관성 - 프레임 파싱 성능 - 보안 로직의 유지보수성 ## 실용적인 권장 사항 - Discord 통화에 계속 참여하려면 2026년 3월 1일 전까지 DAVE 지원 클라이언트로 업데이트해야 한다. - Firefox 사용자는 최소 Firefox 142.0 이상으로 업그레이드해야 한다. - Discord용 앱이나 Social SDK를 개발 중이라면 DAVE 지원 여부를 확인하고, 비-E2EE 통화에 의존하는 구현을 제거해야 한다.

datadog

서버 의존성 없이 실시간 클라이언트 사이드 노이즈 억제 라이브러리를 구축한 방법 (새 탭에서 열림)

Datadog의 CoScreen 팀은 원격 협업 중 발생하는 배경 소음을 실시간으로 제거하기 위해, 높은 성능과 이식성을 갖춘 오픈소스 라이브러리인 `dtln-rs`를 개발했습니다. 기존의 노이즈 억제 도구들은 WebRTC와의 통합이 어렵거나 고성능 서버 자원을 요구한다는 한계가 있었으나, 이 라이브러리는 클라이언트 측에서 효율적으로 동작하도록 설계되었습니다. 결과적으로 M1 맥북 프로 기준 1초의 오디오를 단 33ms 만에 처리하며, 서버 의존성 없이 다양한 플랫폼에서 고품질의 실시간 소음 제거를 가능하게 합니다. **dtln-rs: 경량화된 실시간 노이즈 억제 라이브러리** * DTLN(Dual-Signal Transformation LSTM Network) 모델을 기반으로 구축된 Rust 언어 기반의 프로젝트입니다. * WebAssembly(WASM), Native Rust, Node.js 네이티브 모듈 등 다양한 타겟으로 빌드할 수 있어 웹 브라우저와 네이티브 앱 모두에 쉽게 통합 가능합니다. * 실제 테스트에서 이웃의 잔디 깎는 기계 소음을 완전히 제거할 정도로 뛰어난 성능을 보여주었으며, 이를 통해 사용자에게 실제적인 가치를 전달합니다. **DTLN 모델의 작동 원리와 효율성** * STFT(단시간 푸리에 변환)를 사용하여 소리를 작은 단위로 분해하고, 주파수별 볼륨(크기 스펙트럼)과 위상(Phase) 정보를 분석합니다. * LSTM(장단기 메모리) 신경망이 포함된 모델을 통해 분석된 데이터 중 어떤 부분이 음성이고 어떤 부분이 소음인지 실시간으로 판단합니다. * 위상 정보와 크기 성분을 모두 활용하는 딥러닝 방식 덕분에 에어컨 소음, 카페 소음, 종이 부스럭거리는 소리 등 다양한 환경에 동적으로 적응하며 즉각적인 감쇠가 가능합니다. **기존 기술의 한계와 개발 배경** * 기존의 고성능 AI 노이즈 제거 모델들은 대부분 강력한 서버 하드웨어를 필요로 하며, 이는 추가적인 지연 시간(Latency)과 막대한 서버 비용을 발생시킵니다. * WebRTC는 널리 쓰이는 오픈소스 기술임에도 불구하고 내장된 노이즈 제거 기능은 구세대 솔루션에 머물러 있어 현대적인 협업 도구들의 품질 요구 수준을 충족하지 못했습니다. * Google 등 대기업이 사용하는 최첨단 모델은 비공개 소스이거나 전용 서버 인프라에 종속되어 있어, 소규모 팀이나 일반 개발자들이 자신들의 앱에 고품질 기능을 구현하기에는 제약이 컸습니다. 실시간 오디오 및 비디오 애플리케이션을 개발하면서 서버 비용 부담 없이 고성능 노이즈 캔슬링 기능을 추가하고 싶다면 `dtln-rs`를 검토해 보시기 바랍니다. 클라이언트 측 리소스를 효율적으로 활용하면서도 WebRTC와 매끄럽게 결합되는 이 라이브러리는 사용자 경험을 한 단계 끌어올리는 실용적인 해결책이 될 것입니다.

discord

디스코드에서 수백만 (새 탭에서 열림)

디스코드(Discord)는 서비스 초기 광범위한 호환성을 위해 32비트 아키텍처를 선택했으나, 현대적인 컴퓨팅 환경에 발맞춰 64비트 전환의 필요성을 강조하고 있습니다. 32비트는 단일 버전으로 거의 모든 윈도우 환경을 지원할 수 있다는 장점이 있었지만, 엄격한 메모리 제한으로 인해 발생하는 크래시 문제와 라이브러리 지원 중단이라는 한계에 봉착했습니다. 결과적으로 디스코드는 더 높은 안정성과 성능을 제공하기 위해 최신 하드웨어 표준인 64비트 아키텍처로의 이전을 추진하고 있습니다. ### 초기 32비트 선택의 배경과 이점 * **광범위한 호환성**: 2015년 출시 당시 디스코드는 윈도우의 하위 호환성 레이어를 활용해 32비트와 64비트 기기 모두에서 작동하는 단일 앱 버전을 유지하고자 했습니다. * **개발 효율성**: 하나의 실행 파일만 관리하면 되었기에 초기 개발 단계에서 리소스를 집중하고 사용자 접근성을 높이는 데 유리했습니다. * **적은 메모리 사용량**: 이론적으로 32비트 애플리케이션은 64비트에 비해 포인터 크기가 작아 메모리를 덜 사용하는 특성이 있습니다. ### 32비트 아키텍처의 기술적 한계 * **메모리 주소 지정 제한**: 32비트 애플리케이션은 사용할 수 있는 메모리 양에 물리적인 상한선이 존재합니다. 64비트 기기에서 실행하더라도 이 제한을 초과하면 성능 저하나 예기치 않은 크래시가 발생합니다. * **성능 저하 및 오류**: 디스코드가 고도화됨에 따라 메모리 집약적인 작업이 늘어났고, 32비트의 한계치에 도달하여 사용자 경험을 해치는 사례가 빈번해졌습니다. ### 64비트 전환의 필연성 * **라이브러리 생태계의 변화**: 디코드의 기반이 되는 Electron, WebRTC와 같은 주요 라이브러리들은 이미 수년 전부터 64비트를 기본 아키텍처로 채택하고 있습니다. * **유지보수 및 보안 리스크**: 업계 표준이 64비트로 이동함에 따라 32비트 라이브러리에 대한 버그 수정이나 최적화가 줄어들고 있으며, 이는 장기적으로 잠재적인 보안 취약점과 비효율성에 노출될 위험을 높입니다. * **미래 지향적 최적화**: 64비트 환경에서는 더 많은 시스템 자원을 안정적으로 활용할 수 있어, 인게임 오버레이와 같은 고성능 기능을 더욱 매끄럽게 구현할 수 있습니다. 데스크톱 애플리케이션 개발 시 초기에는 32비트의 범용성이 매력적일 수 있으나, 서비스의 규모가 커지고 현대적인 라이브러리를 지속적으로 활용해야 한다면 64비트 전환은 선택이 아닌 필수입니다. 안정적인 메모리 관리와 커뮤니티의 기술 지원을 받기 위해서는 하드웨어 표준에 맞춘 아키텍처 업데이트가 반드시 선행되어야 합니다.