Back to Blog

WebAR 라이브 비디오 스트리밍 웹 애플리케이션 구축

안녕하세요, 모두들. 오늘은 WebXR을 활용해 WebAR과 WebVR 환경 모두에서 존재하는 3D 모델의 일부로 실시간 비디오 스트림을 표시하는 라이브 스트리밍 웹 앱을 만드는 방법을 설명드리겠습니다.

이 프로젝트에서는 두 가지 사용자 역할을 지원하는 간단한 웹 애플리케이션을 개발합니다. WebVR 장면에서는 사용자가 3D 모델에 자신을 방송할 수 있으며, 이 모델을 가상 장면 내에서 회전시키고 이동시킬 수 있습니다. WebAR 장면에서는 사용자가 증강현실(AR)을 통해 가상 장면을 확인할 수 있으며, 이 때 3D 모델과 비디오 스트림은 방송하는 사용자에 의해 제어됩니다.

필요 사항

  • 간단한 웹 서버 — 저는 Live Server를 사용하기를 선호합니다.
  • SSL 인증서를 갖춘 서버 또는 HTTPS 연결을 설정할 수 있는 방법 (저는 ngrok을 사용합니다)
  • 아고라 개발자 계정
  • HTML/CSS/JS에 대한 기본적인 이해에서 중간 수준의 이해까지
  • 부트스트랩jQuery에 대한 기본적인 이해 (최소한의 지식만 필요)

건축 및 구조 설계

How To: 라이브 방송 웹 앱 만들기”에서 해당 앱은 방송 시나리오에 맞게 설계되었습니다. 이번 앱도 유사한 구조를 따르며, 두 가지 사용자 역할(방송자 및 시청자)을 포함합니다. 전통적인 방송 시나리오와 마찬가지로 방송자는 카메라 스트림을 채널에 공유하게 되며, 시청자는 방송자를 시청할 수 있지만, WebXR 기술을 활용한 독특한 요소가 추가됩니다.

이 프로젝트에서 방송사는 3D 모델로 표현되며, 카메라 스트림을 모델의 얼굴 텍스처로 재생할 것입니다.

Broadcaster by digitallysavvy on Sketchfab

이번 프로젝트에서는 3개의 프레임워크를 사용할 계획입니다: AFrame은 가상 DOM을 통해 장면의 구조를 명확하고 쉽게 이해할 수 있기 때문에; AR.js는 크로스플랫폼 웹AR을 지원하기 때문에; 그리고 Agora는 실시간 비디오 통합을 간단하게 만들기 때문에 라이브 스트리밍에 사용할 것입니다.

JS 생태계 전반에 걸쳐 널리 퍼져 있는 분산된 구조를 고려해, 이 튜토리얼을 HTML, CSS, JS의 가장 기본적인 버전으로 작성하고자 했습니다. 진행 과정에서 Vanilla JS와 jQuery를 혼합해 사용한 것을 발견하실 수 있을 것입니다. 이는 의도적인 선택이었으며, 특정 DOM 작업에 대해 Vanilla JS가 다소 번거로울 수 있기 때문에 jQuery를 사용해 몇 가지 작업을 간소화하기 위함이었습니다. WebXR 관련 코드에서는 연결 구조를 명확히 하기 위해 Vanilla JS만을 사용했습니다. 이제 몇 가지 단계를 생략하고 Bootstrap을 사용해 맞춤형 CSS를 너무 많이 작성하지 않아도 되도록 하겠습니다.

Core Structure (HTML)

우리의 라이브 방송 웹 앱에서는 두 개의 클라이언트(방송자/관객)가 각각 자체 UI를 갖게 됩니다. 방송자 UI는 WebVR 부분의 경험을 만들기 위해 AFrame을 사용할 것이며, 관객은 WebAR 부분의 경험을 만들기 위해 AFrame과 함께 AR.js를 사용할 것입니다.

Broadcaster UI

Broadcaster UI의 기본 HTML 구조부터 시작해 보겠습니다. 필수적인 UI 요소들이 몇 가지 있습니다. 먼저, 오디오/비디오 스트림을 전환하는 버튼과 채팅을 나가는 기능을 포함하는 도구 모음이 필요합니다. 또한 AFrame 장면을 위한 3D 캔버스로 사용할 영역도 필요합니다.

시작하기 전에, AFrame이 DOM을 가상화하는 엔티티 컴포넌트 시스템을 구현한다는 점을 알아두는 것이 좋습니다. 우리는 AFrame의 맞춤형 DOM 요소를 사용하여 가상 장면을 구축할 것이며, 먼저 장면을 정의하는 <a-scene> 컴포넌트부터 시작하여 그 컴포넌트의 구성 요소들을 차례로 다룰 것입니다.

  • <a-assets>를 사용하여 장면의 일부로 방송기 모델을 올바르게 로드합니다.
  • <a-sky>장면의 배경 색상을 설정합니다.
  • 2개의 <a-entity> 요소, 하나는 카메라용이고 다른 하나는 카메라의 대상용으로, 이는 aframe-orbit-controls-component를 위한 것입니다.

또한 아고라의 비디오 및 RTM 웹 SDK를 포함할 것입니다. 이 SDK들을 Broadcaster 클라이언트 내에 구현하여 비디오 스트림을 표시하고 Broadcaster가 가상 장면 내에서 3D 모델을 이동할 수 있도록 할 것입니다.

페이지 하단에는 UI 컨트롤을 비활성화하는 코드 블록과 Broadcaster Client 링크를 포함할 것입니다. Broadcaster Client를 구축할 때 사용자가 채널에 가입하면 UI 컨트롤을 활성화할 것입니다.

관객용 사용자 인터페이스

Broadcaster UI가 준비되었으니 이제 Audience UI를 구축할 수 있습니다. Audience UI는 Broadcaster UI보다 훨씬 단순할 것입니다. AR.js/AFrame과 Agora의 Video 및 RTM Web SDK를 사용하여 3D 모델을 표시하는 기능만 지원하면 되기 때문입니다.

장면 내에서 우리는 <a-assets> 요소를 사용하여 방송자 3D 모델을 사전 로드할 것입니다. 하지만 이번에는 <a-entity> 카메라가 비어 있습니다. 왜냐하면 AR.js가 장면 내의 카메라를 제어할 것이기 때문입니다(다른 모든 AR 프레임워크와 마찬가지로).

새로운 요소 <a-marker>를 확인할 수 있습니다. 이 요소는 AR.js가 AR 경험을 위해 추적하는 마커 이미지를 나타냅니다. type='barcode'와 value=6은 마커 유형과 AR.js가 추적할 “지문”을 지정합니다(AR.js 마커 추적에 대한 자세한 내용은 여기 참조). 단순성을 위해 바코드 유형을 선택했습니다.

참고: 우리는 현재 레거시 마커 추적 방식을 사용하고 있으며, 새로운 AR.js NFT 이미지 추적 방식을 사용하지 않고 있습니다. 이는 동적으로 로드되는 모델과 NFT 마커 사이에 문제가 있기 때문입니다. 이 문제가 해결되면 프로젝트를 NFT 이미지 추적 방식으로 업데이트할 계획입니다.

CSS 와 스타일링

위 UI 각각에 Bootstrap 클래스를 포함시켰습니다. Bootstrap은 정말 유용하지만, 기본 설정으로는 완벽하게 조정되지 않는 몇 가지 요소를 조정하기 위해 몇 가지 맞춤형 CSS 블록을 추가해야 합니다. 다양한 버튼에 아이콘을 적용해야 하기 때문에 Font Awesome CSS 프레임워크를 사용할 것입니다. FA는 이를 매우 간단하게 만들어줍니다.

앞서 언급했듯이 Bootstrap은 훌륭하지만, 때로는 약간의 맞춤형 CSS가 필요할 때가 있습니다. 위에서 언급된 style.css의 스타일링 블록입니다. CSS는 특별히 주목할 만한 점이 없이 매우 직관적입니다.

방송사 클라이언트 구축

이제 WebVR Broadcaster 클라이언트를 구축할 준비가 되었습니다. 시작하기 위해 아래에 Agora RTC 및 RTM 웹 SDK의 기본 구현 예제가 제공됩니다. 이 구현 예제는 우리 Broadcaster 클라이언트의 기반이 될 것입니다.

필요한 콜백을 포함하고 핵심 기능을 구현했지만, 해당 기능 블록은 빈 상태로 남겨두었습니다. 이 섹션에서 강조하고 싶은 두 가지 기능은 다음과 같습니다:

  • createBroadcaster 함수는 3D 모델에 비디오 텍스처를 적용한 <a-entity>를 생성합니다.

참고: 스크립트 상단에 아고라 AppID를 추가해야 합니다. 이 정보는 아고라 콘솔의 프로젝트 섹션에서 확인할 수 있습니다.

아고라의 RTM SDK를 사용하여 메시지를 전송하는 몇 가지 빈 함수를 발견하실 수 있습니다. 먼저 Broadcaster 및 Audience 비디오 클라이언트를 추가하는 데 집중한 후, RTM 통합 과정을 단계별로 안내해 드리겠습니다.

참고: 이 구현에서는 동적 사용자 ID를 사용하고 있지만, 사용자 관리 시스템에 연결하여 자체 UID를 사용할 수 있습니다. 위 코드에서는 RTC 및 RTM 클라이언트 모두에 동일한 사용자 ID를 사용합니다.

3D 모델 추가

이제 기본적인 구현을 완료했으니, createBroadcaster 함수를 구현해 보겠습니다.

먼저, 비디오 텍스처의 일부로 사용될 비디오 요소를 생성하고자 합니다. 비디오가 전체 화면으로 재생되지 않도록 webkit-playsinline 및 playsinline 속성을 설정해야 합니다. 비디오 요소가 준비되면, 이를 <a-assets>의 자식 요소로 DOM에 추가할 수 있습니다. AFrame의 자산 로더는 비디오를 로드하는 방식을 처리하여 가상 장면에서 사용할 수 있도록 합니다.

다음으로 3D 모델의 설정(예: 크기, 회전, 위치)을 구성해야 합니다. 이 함수는 처음에는 localStream의 init 내에서 호출되지만, 이 함수는 일반적이며 채널에 새로운 스트림이 추가될 때마다 호출됩니다. 다중 호스트를 지원하기 위해 위치에 오프셋을 포함해야 합니다.

gltfModel의 경우 AFrame의 DOM 가상화 기능을 활용할 것입니다. <a-assets>에서 로드한 3D 모델 자산의 ID를 전달하면 AFrame의 로더가 나머지 작업을 처리합니다. AFrame은 모델 로드 이벤트를 제공하며, 이 이벤트를 감지할 수 있습니다. 모델이 로드되면 메쉬를 탐색하여 'face-geo'라는 이름의 메쉬를 찾을 수 있습니다. 이 이름은 메쉬를 더 쉽게 찾을 수 있도록 제가 지정한 이름입니다.

<a-gltf-model>을 생성하고 있음을 확인할 수 있습니다. 이 컴포넌트는 .glTF.glb 파일을 로드하기 위해 <a-entity>를 감싸는 역할을 합니다. 이 프로젝트에서는 .glb 파일을 사용할 것입니다. 왜냐하면 .glb 파일은 모델을 단일 파일로 효율적으로 압축하기 때문입니다.

'face-geo'를 찾은 후에는 비디오 텍스처를 생성하고 minFilter, magFilter, flipY 속성을 설정하여 비디오가 적절히 샘플링되고 뒤집히지 않도록 해야 합니다. 다음으로 'face-geo' 노드의 재질을 업데이트합니다. 먼저 .map 속성을 비디오 텍스처로 설정합니다. 그 다음 .color를 빈 색상 객체로 설정하여 비디오에 색조가 적용되지 않도록 합니다. 마지막으로 .metalness를 0으로 설정하여 비디오에 반사가 발생하지 않도록 합니다.

실시간 비디오 구현

3D 모델이 장면에 추가되었기 때문에, 비디오 텍스처의 소스로 비디오 스트림을 연결하는 것은 상대적으로 간단합니다.

중요한 점은 스트림을 재생하기 전에 'onloadedmetadata'를 사용하여 스트림이 로드될 때까지 기다리는 것입니다.

방송사 테스트

현재 단계에서 Broadcaster Client를 테스트할 준비가 되었습니다. 로컬 웹 서버를 실행한 후 다음 주소로 이동하세요:

/broadcaster.html

위 단계들을 따라하셨고 모든 것이 정상적으로 작동한다면, 3D 모델에 자신의 모습을 확인할 수 있을 것입니다.

Note: You’ll have to accept camera access permissions

오디언스 클라이언트 구축

이제 작동하는 WebVR Broadcaster 클라이언트를 확보했으니, 이제 WebAR Audience 클라이언트를 구축해야 합니다. 시작하기 위해 아래에 아고라 RTC 및 RTM 웹 SDK의 기본 구현 예시가 제공됩니다. 이 구현 예시는 우리 Audience 클라이언트의 기반이 될 것입니다.

이 부분은 AFrame을 계속 사용하기 때문에 조금 더 쉽습니다. 유일한 차이점은 AR.js를 추가했다는 점이며, 이 사용자는 시청자이기 때문에 스트림을 게시할 필요가 없습니다. 아래에 시청자 클라이언트를 포함시켰습니다. 모델을 추가할 때 두 가지 작은 차이가 있음을 확인할 수 있을 것입니다:

  • 모델은 <a-marker>의 자식으로 추가되어 마커에 대한 추적 기능을 표시하도록 합니다.
  • 모델을 화면에 더 잘 맞추기 위해 스케일을 훨씬 작게 조정했으며, UV를 반전시켜야 했기 때문에 음수 값이 적용되었습니다. 이는 비디오가 반전되어 표시되었기 때문입니다.
  • 모델은 x축을 중심으로 180도 회전됩니다. 이로 인해 마커를 추적할 때 모델이 직립된 상태로 표시됩니다.

참고: 스크립트 상단에 Agora AppID를 추가해야 합니다. 이 정보는 아고라 콘솔의 프로젝트 섹션에서 확인할 수 있습니다.

관객을 테스트하다

로컬 웹 서버를 시작하고, Broadcaster Client로 이동합니다.

/broadcaster.html

여기서 이 애플리케이션을 웹 서버에 배포하거나, ngrok과 같은 터널링 서비스를 사용하여 로컬 웹 서버를 안전한 (HTTPS) URL로 매핑해야 합니다.

모바일 기기에서 다음으로 이동하세요.

/index.html

모바일 기기에서 데모를 실행할 때 AR.js를 위해 카메라 액세스 및 센서 권한을 허용해야 합니다. 휴대폰을 마커 이미지에 향하면 3D 브로드캐스터가 표시됩니다.

Note: On iOS, this only works using Safari

RTM 메시지 추가

좋아요, AR 영상은 정말 멋있지만, 이 기능을 더 흥미롭게 만들기 위해서는 3D 모델을 장면 내에서 이동시킬 수 있는 기능을 추가하고, 이를 모든 클라이언트에 동기화하는 것이 좋을 것 같아요. 이제 Broadcaster와 Audience 클라이언트를 준비했으니, 아고라의 리얼타임 메시징 SDK를 사용하여 메시지를 송수신할 수 있는 기능을 추가하면 됩니다.

RTM 메시지 전송

방송자 클라이언트 내에서 스트리밍 기능을 제어하기 위해 키 바인딩이 설정되어 있음을 확인할 수 있습니다:

  • m 키를 눌러 마이크를 켜거나 끕니다.
  • v를 눌러 동영상을 켜고 끕니다.
  • q를 눌러 채널을 나가세요.

또한 몇 가지 다른 것들도 확인할 수 있습니다:

  • e와 r이 모델을 회전시킵니다.
  • d, x, z, c 키를 각각 앞으로, 뒤로, 왼쪽, 오른쪽으로 이동합니다.

이 버튼을 터치하면 두 가지 기능 중 하나가 실행됩니다.

  • rotateModel을 사용하여 회전을 처리합니다.
  • moveModel을 사용하여 위치 변경을 처리합니다.

각 기능 내에서는 RTM 채널에 속한 다른 클라이언트들이 회전/위치를 업데이트하도록 알리는 RTM 메시지를 전송하기 위해 sendChannelMessage를 호출한다는 점을 확인할 수 있습니다.

sendChannelMessage 함수가 채널 내 다른 사용자에게 업데이트를 전달할 수 있도록 누락된 부분을 채워보겠습니다. 메시지를 구조화하기 위해 JSON 객체를 사용할 것이며, 변경하는 속성과 방향을 지정하기 위해 하나의 키를 할당할 것입니다.

const jsonMsg = {
  property: property,
  direction: direction
};

이 경우 방향은 키워드 집합에 매핑됩니다:

  • 반시계 방향: y축을 중심으로 한 양의 회전
  • 시계 방향: y축을 중심으로 한 음의 회전
  • 전진: z축 방향으로 위치 이동
  • 역방향: z축 위치에서 음의 방향으로 이동합니다.
  • 왼쪽: x축 위치에서 양의 방향으로 이동합니다.
  • 오른쪽: x축 위치에서 음의 방향으로 이동합니다.

다음으로 메시지를 아고라 RTM 메시지로 패키징해 보겠습니다. 아고라 RTM SDK는 메시지를 구조화하기 위해 JSON 객체를 사용하며, 가장 중요한 요소는 메시지를 수신자에게 전달할 텍스트를 포함하는 text 속성입니다. text 속성은 문자열 값을 기대하기 때문에, 객체를 문자열로 변환하기 위해 JSON.stringify()를 사용할 것입니다.

RTM 메시지를 수신합니다.

이제 RTM 채널로 메시지를 전송할 수 있게 되었으니, 메시지가 수신될 때 이를 처리하는 방법도 필요합니다. Broadcaster와 Receiver 클라이언트 모두에 존재하는 .on('ChannelMessage', ... ) 콜백을 살펴보겠습니다.

참고: 이 이벤트를 Broadcaster Client에서 감지하여 각 채널에서 여러 Broadcaster를 지원할 수 있도록 합니다.

메시지를 수신하면 JSON.parse()를 사용하여 문자열을 JSON 객체로 변환합니다. 이로써 해당 속성을 신속하게 업데이트할 수 있습니다.

rtmChannel.on('ChannelMessage', ({ text }, senderId) =&gt; {
  // convert from string to JSON
  const msg = JSON.parse(text);  // Handle RTM msg
  if (msg.property === 'rotation') {
    rotateModel(senderId, msg.direction)
  } else if (msg.property == 'position') {
    moveModel(senderId, msg.direction)
  }
});

RTM 테스트Audience 테스트

로컬 웹 서버를 시작하고, Broadcaster Client로 이동합니다.

/broadcaster.html

다시 한 번 강조하지만, 이 단계에서는 이 애플리케이션을 웹 서버에 배포하거나 터널링 서비스(예: ngrok)를 사용하여 로컬 웹 서버를 안전한(HTTPS) URL로 매핑해야 합니다.

모바일 기기에서 다음으로 이동하세요.

/index.html

모바일 기기에서 데모를 실행할 때 AR.js를 위해 카메라 액세스 및 센서 권한을 허용해야 합니다. 휴대폰을 마커 이미지에 향하면 3D Broadcaster가 표시됩니다.

다음으로 Broadcaster 클라이언트에서 e, r, d, x, c, z 키를 사용하여 가상 장면 내에서 Broadcaster를 이동시키고, 채널 내 모든 사용자에게 실시간으로 업데이트되는 모습을 확인하세요.

모두 완료되었습니다.

와, 정말 강렬했네요! 함께 따라해 주시고 코딩해 주셔서 감사합니다. 아래에 완성된 프로젝트 링크를 첨부합니다. 기능 개선을 위한 포크와 풀 리퀘스트를 자유롭게 제출해 주세요. 이제 이 지식을 활용해 멋진 것을 만들어 보세요.

https://github.com/digitallysavvy/AgoraWebXR

기타 자료

아고라 Video SDK에 대한 자세한 내용은 아고라 Video Web SDK API 참조 문서를 참고해 주시기 바랍니다. 아고라 RTM SDK에 대한 자세한 내용은 아고라 RTM Web SDK API 참조 문서를 참고해 주시기 바랍니다.

또한 아고라 개발자 슬랙 커뮤니티에 참여해 주시기를 초대합니다.

RTE Telehealth 2023
Join us for RTE Telehealth - a virtual webinar where we’ll explore how AI and AR/VR technologies are shaping the future of healthcare delivery.

Learn more about Agora's video and voice solutions

Ready to chat through your real-time video and voice needs? We're here to help! Current Twilio customers get up to 2 months FREE.

Complete the form, and one of our experts will be in touch.

Try Agora for Free

Sign up and start building! You don’t pay until you scale.
Try for Free