HTML <usermedia> 요소를 소개합니다

샛별·4일 전

translations.zip

목록 보기
31/31
post-thumbnail

원문: Introducing the <usermedia> HTML element

Chrome 144에서 <geolocation> 요소를 선보인 데 이어, Chrome 151부터는 카메라와 마이크를 위한 <usermedia> HTML 요소를 사용할 수 있습니다. Capability Elements 제품군에 새롭게 합류한 이 요소는 범용 권한을 요청하던 기존 방식에서 벗어나, 사용자가 필요한 기능을 직접 활성화하는 방식으로의 전환을 보여줍니다.

<usermedia>는 스크립트가 띄우는 권한 프롬프트를 선언적이고 사용자 동작에 기반한 경험으로 대체합니다. 덕분에 반복적인 코드가 줄고 보안이 향상되며, 접근을 거부했던 사용자도 권한을 복구할 수 있습니다. 오랫동안 문제로 남아 있던 권한의 구멍(permission hole)을 효과적으로 해결하게 됩니다.

권한 관리에서 기능 제공으로

<usermedia><geolocation>에 이어 Capability Elements 제품군에서 두 번째로 출시되는 기능별 HTML 요소입니다. PEPC(Page-Embedded Permission Control) 이니셔티브에 포함되었던 초기의 범용 <permission> 제안에서 발전한 형태입니다. 기능마다 별도의 요소를 제공하면 브라우저가 각 하드웨어의 고유한 동작과 복잡성을 더 효과적으로 처리할 수 있습니다. 초기 제안에선 허용과 거부 같은 권한 관리에 주로 초점을 맞췄지만, Capability Elements는 데이터 중개자 역할을 합니다.

<geolocation> 요소가 사이트에 위치 객체를 제공한다면, <usermedia>는 카메라와 마이크 접근에 필요한 전체 과정을 관리합니다. 사용자의 선택을 확인하고, 브라우저 권한 프롬프트를 관리한 뒤, 애플리케이션에 MediaStream 객체를 전달합니다. 따라서 getUserMedia()를 별도로 호출할 필요가 없어 구현이 단순해지며, 브라우저도 사용자가 직접 요청한 권한이라는 사실을 알 수 있습니다.

실제 환경에서 검증된 효과

정식 출시에 앞서 실제 사이트에서 시험한 결과, 권한이 필요한 시점에 사용자가 직접 요청하도록 하자 권한 설정 성공률이 크게 높아졌습니다.

  • Cisco에 따르면 처음에 권한을 거부한 사용자가 기존 프롬프트로 권한을 부여하는 비율은 약 10%에 불과했습니다. 새로운 요소를 사용하자 이 수치가 65% 이상으로 상승했습니다.
  • Zoom은 시스템 수준의 차단과 같은 카메라·마이크 캡처 오류가 46.9% 감소했다고 보고했습니다. 이 요소를 통해 사용자가 문제를 복구하도록 안내했기 때문입니다.
  • Google Meet에서는 "마이크가 작동하지 않는다"는 피드백이 17% 감소했고, 기존에 접근을 거부했던 사용자가 권한을 복구한 비율이 131% 증가했습니다.

<usermedia> 요소를 사용해야 할까?

<usermedia><geolocation>에서 확립한 패턴을 바탕으로, 강력한 기능의 권한을 요청할 때 발생하는 핵심 문제를 해결합니다. 기존 미디어 권한 요청은 명령형 자바스크립트 호출에 의존하기 때문에, 사용자가 아직 카메라나 마이크를 사용하려 하지 않았는데도 갑자기 권한을 묻는 상황이 생길 수 있습니다. 사용자가 실수로 권한을 거부하면 이 결정을 되돌리기 위해 브라우저 설정 깊숙한 곳까지 찾아가야 합니다. 이런 권한의 구멍은 결국 사용자가 기능 자체를 포기하게 만들곤 합니다.

<usermedia> 요소는 다음과 같은 방법으로 이 문제를 해결합니다.

  • 분명한 의도와 타이밍: 브라우저가 관리하는 요소를 사용자가 직접 누른 뒤에만 권한 요청 창이 나타납니다. 브라우저도 사용자가 지금 카메라나 마이크를 쓰려 한다는 사실을 확실히 알 수 있으므로, 일반적인 스크립트 기반 요청에 적용하는 자동 차단을 건너뛸 수 있습니다.
  • 간단한 권한 복구: 이전에 접근을 거부했더라도 요소를 탭하면 전용 복구 과정이 시작됩니다. 복잡한 브라우저 설정으로 이동하지 않고 현재 페이지에서 곧바로 카메라나 마이크를 다시 활성화할 수 있습니다.
  • 스트림에 직접 접근: 이 요소는 데이터 중개자로서 미디어 스트림을 직접 노출합니다. 애플리케이션에서 콜백과 오류 상태를 관리하기 위해 작성하던 반복적인 코드가 줄어듭니다.
비교 항목getUserMedia() JS API<usermedia> HTML 요소
권한 프롬프트가 실행되는 시점명령형 스크립트 실행(getUserMedia)사용자가 브라우저에서 관리하는 요소를 클릭할 때
브라우저의 역할상태와 휴리스틱을 바탕으로 프롬프트 표시 여부를 결정데이터 중개자 역할을 수행하며 동의 과정과 스트림 전달을 관리
사이트의 역할자바스크립트 API를 직접 호출하고 콜백과 오류를 관리stream 이벤트를 수신하고 stream 프로퍼티에 접근
핵심 목표기본적인 카메라·마이크 접근스트림 접근, 권한 관리, 불편을 줄인 권한 복구

구현 방법

<usermedia> 요소는 기존 자바스크립트 API보다 훨씬 적은 코드로 통합할 수 있습니다. <geolocation>에서 확립한 선언적 패턴에 따라 HTML에 <usermedia> 태그를 추가하고, setConstraints() 메서드로 필요한 하드웨어 조건을 설정하면 됩니다.

참고: 아래 설명은 브라우저가 <usermedia> 요소를 지원한다고 가정합니다. 지원하지 않는 브라우저까지 처리하려면 뒤에서 설명할 직접 폴백을 구현하는 패턴을 참고하세요.

<usermedia id="media-ctrl">
  <button>카메라와 마이크 활성화</button>
</usermedia>
const el = document.getElementById("media-ctrl");

// 사용자가 상호작용하기 전에 원하는 하드웨어 조건 지정
el.setConstraints({
  video: { width: 1280, height: 720 },
  audio: { echoCancellation: true },
});

// 스트림을 성공적으로 가져온 경우.
el.addEventListener("stream", () => {
  videoPreview.srcObject = el.stream;
});

// 스트림을 가져오지 못한 경우
el.addEventListener("error", () => {
  console.error(`접근 실패: ${el.error?.name}`);
});

// 사용자가 프롬프트를 취소하거나 닫은 경우
el.addEventListener("cancel", () => {
  console.log("사용자가 권한 프롬프트를 닫았습니다.");
});

주요 프로퍼티와 메서드

  • stream: 사용자가 접근을 허용하면 MediaStream 객체를 제공하는 읽기 전용 프로퍼티입니다.
  • setConstraints(): 사용자와 상호작용하기 전에 deviceId나 해상도 같은 하드웨어 조건을 변경할 수 있는 메서드입니다.
  • error: 요청이 실패하거나 닫힌 경우 NotAllowedError와 같은 DOMException을 반환하는 읽기 전용 프로퍼티입니다.
  • onstream: 미디어 트랙을 가져오는 즉시 실행되는 이벤트 핸들러입니다.
  • onerror: 스트림을 가져오려는 시도가 실패하면 실행되는 이벤트 핸들러입니다.
  • oncancel: 스트림을 가져오는 도중 사용자가 권한 프롬프트를 취소하거나 닫으면 실행되는 이벤트 핸들러입니다.

스타일 제약 사항

요소를 투명하게 만들거나 다른 콘텐츠로 가려 사용자가 의도하지 않은 권한을 허용하게 만드는 일을 막기 위해서 <usermedia> 요소에는 다른 Capability Elements와 마찬가지로 엄격한 스타일 제약이 적용됩니다.

  • 가독성: 브라우저는 권한 요청을 항상 읽을 수 있도록 텍스트와 배경색의 명암비가 충분한지 확인합니다. 최소 명암비는 3:1입니다. 요소를 눈에 띄지 않게 투명하게 만드는 일을 막기 위해 알파 채널(opacity)은 반드시 1로 설정해야 합니다.
  • 크기와 여백: 브라우저는 width, height, font-size에 최솟값과 최댓값을 적용합니다. 요소를 시각적으로 가릴 수 없도록 음수 마진과 음수 outline-offset도 비활성화합니다.
  • 시각적 무결성: 브라우저는 요소를 왜곡하는 효과를 제한합니다. 예를 들어 transform에는 2D 이동과 비율을 유지하는 확대·축소만 사용할 수 있습니다.
  • CSS 의사 클래스: 권한이 활성화되고 스트림을 가져오면 적용되는 :granted 같은 상태 기반 스타일을 지원합니다. :hover, :active와 같은 일반적인 상호작용 상태도 사용할 수 있습니다.

점진적 향상과 마이그레이션 전략

<usermedia> 요소는 <geolocation>에서 확립한 설계 패턴에 따라, 지원하지 않는 환경에서도 자연스럽게 기능이 축소되도록 만들어졌습니다. 이 요소를 지원하지 않는 브라우저는 <usermedia>HTMLUnknownElement로 취급하고 자식 요소를 렌더링합니다. 덕분에 모든 사용자를 위한 폴백 경험을 제공할 수 있습니다.

직접 폴백을 구현하는 패턴

먼저 자바스크립트에서 <usermedia> 요소 지원 여부를 감지합니다.

if ("HTMLUserMediaElement" in window) {
  // 최신 <usermedia> 요소 사용
} else {
  // 기존 getUserMedia() API로 폴백
}

이 감지 로직과 함께 <usermedia> 요소 안에 일반 버튼을 추가하고, 지원하지 않는 환경에서는 기존 getUserMedia() API를 실행하도록 만들 수 있습니다.

<usermedia id="stream-handler">
  <button id="fallback-stream-handler">카메라와 마이크 활성화</button>
</usermedia>
// 비디오·오디오 스트림을 처리하는 함수
function handleStream(event) {
  /* ... */
}

if ("HTMLUserMediaElement" in window) {
  // <usermedia> 요소를 지원하는 경우
  const streamHandler = document.getElementById("stream-handler");
  streamHandler.addEventListener("stream", (event) => {
    handleStream(event);
  });
} else {
  // <usermedia> 요소를 지원하지 않으므로 기존 API 사용
  const fallbackStreamHandler = document.getElementById(
    "fallback-stream-handler",
  );

  fallbackStreamHandler.addEventListener("click", (event) => {
    navigator.mediaDevices
      .getUserMedia({ video: true, audio: true })
      .then(handleStream);
  });
}

시험 운영 참여자를 위한 마이그레이션

앞서 시험 운영에 참여해 범용 <permission> 요소를 사용하고 있었다면, 몇 가지만 바꿔 <usermedia>로 전환할 수 있습니다.

  1. 태그 변경: <permission type="camera microphone"><usermedia>로 교체하세요. 기존 <permission> 요소를 대상으로 하던 모든 선택자도 <usermedia> 요소를 사용하도록 변경해야 합니다.
  2. 기능 감지 변경: HTMLPermissionElement를 확인하던 코드를 HTMLUserMediaElement로 변경하세요.

앞으로의 계획

<usermedia> 요소는 오디오와 비디오를 함께 요청하는 상황을 처리합니다. 향후 Capability Elements에는 다음과 같은 요소도 추가될 예정입니다.

  • <camera>: 비디오만 필요한 상황을 위한 요소
  • <microphone>: 오디오만 필요한 상황을 위한 요소

이처럼 기능별로 나뉜 요소를 활용하면 개발자는 더욱 직관적이고 신뢰할 수 있는 미디어 경험을 만들 수 있습니다. 자세한 내용은 Capability Elements 기술 가이드를 참고하세요.

관련 자료

profile
["NAVER", "FE", "PLACE", "UX"]

0개의 댓글