오픈 스크린 애플리케이션 프로토콜

W3C 작업 초안,

이 문서에 대한 자세한 정보
이 버전:
https://www.w3.org/TR/2026/WD-openscreen-application-20260210/
최신 공개 버전:
https://www.w3.org/TR/openscreen-application/
편집자 초안:
https://w3c.github.io/openscreenprotocol/application.html
이전 버전:
이력:
https://www.w3.org/standards/history/openscreen-application/
피드백:
GitHub
명세 내 인라인
편집자:
Mark Foltz (Google)

초록

오픈 스크린 애플리케이션 프로토콜은 사용자 에이전트가 Presentation APIRemote Playback API를 상호 운용 가능한 방식으로 구현할 수 있게 한다.

이 문서의 상태

이 절은 이 문서가 공개된 시점의 상태를 설명한다. 현재 W3C 간행물 목록과 이 기술 보고서의 최신 개정판은 W3C 표준 및 초안 색인에서 확인할 수 있다.

이 문서는 Second Screen Working Group권고안 트랙을 사용하여 작업 초안으로 공개했다. 이 문서는 W3C 권고안이 되는 것을 목표로 한다.

Second Screen Working Group은 그룹이 아직 처리하지 않은 모든 버그 보고서 목록을 유지한다. 이 초안은 워킹 그룹에서 아직 논의해야 하는 일부 대기 중인 이슈를 강조한다. 이슈의 유효 여부를 포함하여, 이러한 이슈의 결과에 대해서는 아직 결정된 바가 없다. 미해결 이슈에 대한 제안 명세 텍스트가 포함된 풀 리퀘스트를 강력히 권장한다.

작업 초안으로 공개되었다고 해서 W3C 및 그 회원들의 승인을 의미하지는 않는다. 이는 초안 문서이며 언제든지 다른 문서에 의해 갱신, 대체 또는 폐기될 수 있다. 이 문서를 진행 중인 작업 이외의 것으로 인용하는 것은 부적절하다.

이 문서는 W3C 특허 정책에 따라 운영되는 그룹이 작성했다. W3C는 그룹의 산출물과 관련하여 이루어진 모든 특허 공개의 공개 목록을 유지하며, 해당 페이지에는 특허를 공개하기 위한 지침도 포함되어 있다. 자신이 실제로 알고 있는 특허가 필수 청구항을 포함한다고 믿는 개인은 W3C 특허 정책의 제6절에 따라 그 정보를 공개해야 한다.

이 문서는 2025년 8월 18일 W3C 프로세스 문서의 적용을 받는다.

1. 소개

오픈 스크린 애플리케이션 프로토콜은 공유된 청중을 위해 웹 콘텐츠를 렌더링할 수 있는 장치에 브라우저를 연결한다. 일반적으로 이러한 장치는 인터넷에 연결된 TV, HDMI 동글, 스마트 스피커와 같은 장치이다.

오픈 스크린 애플리케이션 프로토콜은 브라우저와 장치 간의 다양한 연결 기술에서 지원되도록 의도되었다. 브라우저와 장치가 서로를 발견하고 인증할 수 있도록 하는 특정 요구사항이 있지만, 이러한 요구사항은 여러 가능한 구현으로 충족될 수 있다. 상호 운용성을 극대화하기 위해, 브라우저와 장치는 오픈 스크린 네트워크 프로토콜을 지원하는 것이 좋다. 이 프로토콜은 브라우저와 장치가 로컬 영역 네트워크에서 서로를 발견하고, 연결하고, 인증할 수 있는 방법을 제공한다.

오픈 스크린 애플리케이션 프로토콜은 브라우저가 URL을 표시하고, HTML 미디어 요소의 원격 재생을 시작하며, 미디어 데이터를 다른 장치로 스트리밍할 수 있게 한다.

오픈 스크린 애플리케이션 프로토콜은 확장 가능하도록 의도되었으므로, 시간이 지나면서 추가 기능을 더할 수 있다. 여기에는 기존 Web API에 대한 추가 사항이나 새로운 Web API가 포함될 수 있다.

동반 해설서는 이 프로토콜에 대한 더 많은 배경 정보를 제공한다.

1.1. 용어

오픈 스크린 프로토콜 에이전트(또는 OSP 에이전트)는 이 프로토콜의 모든 구현체(브라우저, 디스플레이, 스피커 또는 기타 소프트웨어)를 말한다.

일부 OSP 에이전트는 Presentation API를 지원한다. 이 API는 제어 사용자 에이전트가 다른 장치에서 웹 콘텐츠의 프레젠테이션을 시작할 수 있게 한다. 우리는 이 에이전트를 줄여서 컨트롤러라고 부른다. 수신 사용자 에이전트는 웹 콘텐츠를 렌더링할 책임이 있으며, 이를 줄여서 수신자라고 부른다. 웹 콘텐츠 자체는 프레젠테이션이라고 부른다.

일부 OSP 에이전트는 Remote Playback API도 지원한다. 이 API는 에이전트가 미디어 요소원격 재생 장치에서 렌더링할 수 있게 한다. 이 문서에서는 이를 수신자라고 부른다. 이는 더 짧고 프레젠테이션과 원격 재생 사이의 용어 일관성을 유지하기 때문이다. 마찬가지로, 원격 재생을 시작, 종료 및 제어하는 에이전트를 지칭하기 위해 컨트롤러라는 용어를 사용한다.

미디어 스트리밍의 경우, 미디어 스트림을 보내는 OSP 에이전트를 미디어 발신자라고 하고, 미디어 스트림을 수신하는 에이전트를 미디어 수신자라고 한다. 에이전트는 미디어 발신자이면서 동시에 미디어 수신자일 수 있다는 점에 유의한다.

Presentation API 또는 Remote Playback API에 특정한 추가 용어와 관용구는 해당 명세를 참조하라.

2. 요구사항

2.1. 에이전트 발견 요구사항

발견 요구사항 정의 [Issue #342]

2.2. 전송 계층 요구사항

전송 계층 요구사항 정의 [Issue #342]

2.3. Presentation API 요구사항

  1. 컨트롤러수신자가 특정 프레젠테이션 요청 URL을 렌더링할 수 있는 합리적인 능력이 있는지 확인할 수 있어야 한다.

  2. 컨트롤러는 프레젠테이션 요청 URL프레젠테이션 식별자가 주어졌을 때, 수신자에서 새로운 프레젠테이션을 시작할 수 있어야 한다.

  3. 컨트롤러는 수신자에 있는 기존 프레젠테이션에 대해, 그 프레젠테이션 요청 URL프레젠테이션 식별자가 주어졌을 때, 새로운 PresentationConnection을 만들 수 있어야 한다.

  4. 컨트롤러와 프레젠테이션 사이의 PresentationConnection을 닫고, 연결이 닫힌 이유를 양쪽에 신호로 알릴 수 있어야 한다.

  5. 여러 컨트롤러가 하나의 프레젠테이션에 동시에 연결할 수 있어야 한다.

  6. 컨트롤러가 보낸 메시지는 신뢰할 수 있고 순서가 보장되는 방식으로 프레젠테이션에 전달되어야 한다(또는 그 반대 방향도 마찬가지이다).

  7. 메시지를 전달할 수 없는 경우, 컨트롤러는 연결을 error 이유로 닫아야 함을 수신자에게 신호로 알릴 수 있어야 한다 (또는 그 반대 방향도 마찬가지이다).

  8. 컨트롤러와 프레젠테이션은 DOMString 메시지 (ECMAScript에서 string 타입으로 표현됨)를 보내고 받을 수 있어야 한다.

  9. 컨트롤러와 프레젠테이션은 바이너리 메시지 (HTML5의 Blob 객체 또는 ECMAScript의 ArrayBufferArrayBufferView 타입으로 표현됨)를 보내고 받을 수 있어야 한다.

  10. 컨트롤러는 프레젠테이션 요청 URL프레젠테이션 식별자가 주어졌을 때, 수신자에게 프레젠테이션을 종료하도록 신호를 보낼 수 있어야 한다.

  11. 수신자는 프레젠테이션이 종료될 때 연결된 모든 컨트롤러에게 신호를 보낼 수 있어야 한다.

2.4. Remote Playback API 요구사항

  1. 컨트롤러는 주어진 HTMLMediaElement에 대해 호환 가능한 수신자가 하나 이상 있는지를 즉시 및 지속적으로 확인할 수 있어야 한다.

  2. 컨트롤러는 HTMLMediaElement원격 재생을 시작하여 호환 가능한 수신자로 보낼 수 있어야 한다.

  3. 컨트롤러는 HTMLMediaElement에서 미디어 소스를 URL로, 그리고 텍스트 트랙을 호환 가능한 수신자로 보낼 수 있어야 한다.

  4. 컨트롤러는 HTMLMediaElement에서 미디어 데이터를 호환 가능한 수신자로 보낼 수 있어야 한다.

  5. 원격 재생 중에, 컨트롤러와 원격 재생 장치는 HTMLMediaElement미디어 요소 상태를 동기화할 수 있어야 한다.

  6. 원격 재생 중에, 컨트롤러 또는 수신자 중 어느 한쪽은 상대방과의 연결을 끊을 수 있어야 한다.

  7. 컨트롤러는 원격 재생 중 텍스트 렌더링을 돕기 위해 로케일 및 텍스트 방향 정보를 수신자에게 전달할 수 있는 것이 좋다.

2.5. 비기능 요구사항

  1. 저가형 스마트폰, 스마트 TV 또는 스트리밍 장치에서 볼 수 있는 것과 유사한 제한된 하드웨어 요구사항으로 OSP 에이전트를 구현할 수 있어야 한다. 에이전트 하드웨어 사양은 장치 사양 문서를 참조하라.

  2. 프로토콜 작업이 실패할 때 에이전트는 사용자에게 합리적인 정보를 제공하는 것이 좋다. 예를 들어, 컨트롤러가 프레젠테이션을 시작할 수 없는 경우, 그것이 네트워크 오류인지, 인증 오류인지, 또는 프레젠테이션 콘텐츠 로드 실패인지 컨트롤러 인터페이스에서 보고할 수 있어야 한다.

  3. 에이전트 간 메시지 지연은 상호작용적 사용을 허용하도록 최소화하는 것이 좋다. 예를 들어, 한 에이전트의 폼에 입력한 텍스트가 실시간으로 프레젠테이션에 표시되는 것이 편안해야 한다. 게임이나 마우스 사용을 위한 실시간 지연은 이상적이지만 요구사항은 아니다.

  4. 프레젠테이션 또는 원격 재생을 시작하는 컨트롤러는 수신자가 해당 로케일로 콘텐츠를 렌더링할 수 있도록 선호 로케일을 수신자에게 전달하는 것이 좋다.

  5. 기본 API의 실험과 향상을 촉진하기 위해, 명세에서 명시적으로 정의하지 않은 선택적 기능으로 애플리케이션 프로토콜을 확장할 수 있어야 한다.

3. 메타데이터 발견

추가 메타데이터를 알아내기 위해, 에이전트는 agent-info-request 메시지를 보내고 agent-info-response 메시지를 되돌려 받을 수 있다. 어떤 에이전트든 다른 장치의 상태와 기능을 알아내기 위해 언제든지 이 요청을 보낼 수 있으며, 이러한 상태와 기능은 agent-info-responseagent-info 메시지로 설명된다.

에이전트가 자신의 agent-info 메시지의 정보를 변경하면, 새로운 agent-info와 함께 모든 다른 연결된 에이전트에게 agent-info-event 메시지를 보내는 것이 좋다 (agent-info-request를 기다리지 않는다).

agent-info 메시지는 다음 필드를 포함한다:

display-name (required)

요청자가 사용자에게 표시하도록 의도된 에이전트의 표시 이름이다. 응답자가 인증되지 않았거나 표시 이름이 변경되는 경우, 요청자는 UI를 통해 이를 표시하는 것이 좋다.

model-name (optional)

에이전트가 하드웨어 장치인 경우, 해당 장치의 모델 이름이다. 이는 주로 디버깅 목적으로 사용되지만, 요청 에이전트의 사용자에게 표시될 수도 있다.

capabilities (required)

에이전트가 지원하는 제어 프로토콜, 역할 및 미디어 타입이다. 존재하면 기능이 있음을 나타내고, 없으면 해당 기능이 없음을 나타낸다. 기능은 에이전트가 사용자에게 표시되는 방식에 영향을 주는 것이 좋다. 예를 들어, 오디오, 비디오 또는 둘 다를 수신하는지에 따라 다른 아이콘을 그릴 수 있다.

state-token (required)

[0-9A-Za-z] 범위의 8자로 구성된 임의의 영숫자 값이다. 이 값은 에이전트가 첫 연결을 만들기 전에 설정되며, 에이전트가 재설정되거나 이 프로토콜과 관련된 모든 상태를 잃으면 새 값으로 설정되어야 한다.

locales (required)

지역화된 콘텐츠 표시를 위한 에이전트의 선호 로케일이며, 사용자 선호 순서로 나열된다. 각 항목은 RFC5646 언어 태그이다.

다양한 기능은 다음 의미를 가진다:

receive-audio

에이전트는 자신이 지원하는 다른 프로토콜을 통해 오디오를 렌더링할 수 있다. 이러한 다른 프로토콜은 스트리밍 프로토콜에서 특정 오디오 코덱 지원과 같은 더 구체적인 기능을 보고할 수 있다.

receive-video

에이전트는 자신이 지원하는 다른 프로토콜을 통해 비디오를 수신할 수 있다. 이러한 다른 프로토콜은 스트리밍 프로토콜에서 특정 비디오 코덱 지원과 같은 더 구체적인 기능을 보고할 수 있다.

receive-presentation

에이전트는 프레젠테이션 프로토콜을 사용하여 프레젠테이션을 수신할 수 있다.

control-presentation

에이전트는 프레젠테이션 프로토콜을 사용하여 프레젠테이션을 제어할 수 있다.

receive-remote-playback

에이전트는 원격 재생 프로토콜을 사용하여 원격 재생을 수신할 수 있다.

control-remote-playback

에이전트는 원격 재생 프로토콜을 사용하여 원격 재생을 제어할 수 있다.

receive-streaming

에이전트는 스트리밍 프로토콜을 사용하여 스트리밍을 수신할 수 있다.

send-streaming

에이전트는 스트리밍 프로토콜을 사용하여 스트리밍을 보낼 수 있다.

NOTE: 알려진 모든 기능 목록은 기능 레지스트리를 참조하라(이 명세에서 정의한 것과 § 10 프로토콜 확장을 통해 정의된 것을 모두 포함한다).

QUIC에 의존하지 않도록 다시 작성하거나 agent-status 메시지를 네트워크 명세로 이동 [Issue #343]

수신 대기 에이전트가 광고 에이전트로부터 메시지를 받기를 원하거나, 광고 에이전트가 수신 대기 에이전트에게 메시지를 보내기를 원하면, QUIC 연결을 유지하기를 원할 수 있다. 어느 쪽도 메시지 송수신을 위해 연결을 유지할 필요가 없어지면, 연결은 오류 코드 5139로 닫는 것이 좋다. QUIC 연결을 유지하기 위해, 에이전트는 agent-status-request 메시지를 보낼 수 있으며, agent-status-request 메시지를 받은 모든 에이전트는 agent-status-response 메시지를 보내는 것이 좋다. 이러한 메시지는 QUIC idle_timeout 전송 매개변수보다 더 자주 보내는 것이 좋으며 (QUIC의 전송 매개변수 인코딩 참조), QUIC PING 프레임은 사용하지 않는 것이 좋다. 25초의 idle_timeout 전송 매개변수가 권장된다. 에이전트는 QUIC 스트림에서 메시지를 보낼 때마다 idle_timeout보다 짧은 타이머가 재설정되는 것처럼 동작하는 것이 좋다. 타이머가 만료되면, agent-status-request 메시지를 보내는 것이 좋다.

수신 대기 에이전트가 광고 에이전트에게 메시지를 보내려는 경우, 수신 대기 에이전트는 광고 에이전트에 "필요 시" 연결할 수 있으며, 연결을 유지할 필요는 없다.

OSP 에이전트가 (예: 절전 이유로) 네트워크 연결을 일시 중단하는 경우, 네트워크 연결이 복원되면 이전에 연결되어 있던 OSP 에이전트에 대한 QUIC 연결을 재개하려고 시도하는 것이 좋다. 다시 연결되면, 해당 에이전트에게 agent-status-request 메시지를 보내는 것이 좋다.

agent-infoagent-status-response 메시지는 § 10.1 프로토콜 확장 필드에 설명된 것처럼 이 명세에서 정의하지 않은 추가 정보를 포함하도록 확장될 수 있다.

4. CBOR를 사용한 메시지 전달

QUIC에 의존하지 않도록 다시 작성 [Issue #343]

메시지는 CBOR를 사용하여 직렬화된다. 메시지 그룹을 순서대로 보내려면, 해당 메시지 그룹은 하나의 QUIC 스트림에서 보내야 한다. 독립적인 메시지 그룹(그룹 간 순서 의존성이 없는 경우)은 서로 다른 QUIC 스트림에서 보내는 것이 좋다. 여러 CBOR 직렬화 메시지를 같은 QUIC 스트림에 넣기 위해 다음이 사용된다.

각 메시지에 대해, OSP 에이전트는 단방향 QUIC 스트림에 다음을 써야 한다:

  1. 메시지 타입을 나타내는 타입 키. 이는 가변 길이 정수로 인코딩된다 (타입 키는 부록 A: 메시지 참조)

  2. CBOR로 인코딩된 메시지.

에이전트가 인식하지 못하는 타입 키의 메시지를 수신하면, 해당 에이전트는 애플리케이션 오류 코드 404로 QUIC 연결을 닫아야 하며, CONNECTION_CLOSE 프레임의 이유 구문에 알 수 없는 타입 키를 포함하는 것이 좋다.

가변 길이 정수는 Variable-Length Integer Encoding으로 인코딩되며, 이는 QUIC에서 사용된다.

많은 메시지는 요청과 응답이므로, 이를 위한 공통 형식이 정의된다. 요청과 응답은 요청자가 선택한 부호 없는 정수인 요청 ID를 포함한다. 응답은 자신이 연결된 요청의 요청 ID를 포함해야 한다.

4.1. 타입 키 하위 호환성

메시지가 시간이 지나면서 수정되거나 확장됨에 따라, 오래된 버전의 메시지를 이해하는 에이전트와의 하위 호환성을 유지하기 위해 특정 규칙을 따라야 한다.

  1. 필수 필드가 메시지에 추가되거나 제거되는 경우(메시지에 직접 또는 필드의 필드를 통해 간접적으로), 해당 메시지에는 새 타입 키가 할당되어야 한다. 이는 사실상 새 메시지이며, 수신 에이전트가 새 타입 키를 이해한다는 것이 알려져 있지 않다면 보내서는 안 된다.

  2. 선택적 필드가 메시지에 추가되는 경우(메시지에 직접 또는 필드의 필드를 통해 간접적으로), 추가된 필드를 이해하지 못하는 이전 수신 에이전트의 동작이 해당 필드를 포함하는 새로운 송신 에이전트와 호환된다면 타입 키는 그대로 유지될 수 있다. 그렇지 않으면 새 타입 키가 할당되어야 한다.

  3. 선택적 필드가 메시지에서 제거되는 경우(메시지에서 직접 또는 필드의 필드를 통해 간접적으로), 제거된 필드를 이해하지 못하는 새로운 수신 에이전트의 동작이 해당 필드를 포함하는 이전 송신 에이전트와 호환된다면 타입 키는 그대로 유지될 수 있다. 그렇지 않으면 새 타입 키가 할당되어야 한다.

  4. 필수 필드는 audio-frame과 같은 배열 기반 메시지에 추가되거나 제거될 수 없다.

5. 프레젠테이션 프로토콜

이 절은 Presentation API에서 정의한 프레젠테이션을 시작, 종료 및 제어하기 위해 오픈 스크린 프로토콜을 사용하는 방식을 정의한다. § 5.1 Presentation APIPresentation API의 API가 이 절에서 정의한 프로토콜 메시지에 어떻게 매핑되는지 정의한다.

특정 프레젠테이션 요청 URL 또는 URL 집합에 대해 어떤 수신자가 사용 가능한 프레젠테이션 디스플레이인지 알아내기 위해, 컨트롤러는 다음 값을 가진 presentation-url-availability-request 메시지를 보낼 수 있다:

urls

프레젠테이션 URL 목록. 비어 있어서는 안 된다.

watch-duration

컨트롤러가 해당 URL에 대한 변경 업데이트를 수신하는 데 관심이 있는 기간이다.

watch-id

수신자가 URL 사용 가능성에 대한 업데이트를 보낼 때 사용해야 하는 식별자이며, 컨트롤러가 수신자가 어떤 URL을 지칭하는지 알 수 있게 한다.

응답으로, 수신자는 다음 값을 가진 하나의 presentation-url-availability-response 메시지를 보내는 것이 좋다:

url-availabilities

URL 사용 가능성 상태 목록. 각 상태는 요청의 같은 목록 인덱스에 있는 URL에 대응해야 한다.

감시가 유효한 동안(watch-duration이 만료되지 않은 동안), 수신자는 URL 사용 가능성이 변경될 때 presentation-url-availability-event 메시지를 보내는 것이 좋다. 이러한 이벤트는 다음 값을 포함한다:

watch-id

presentation-url-availability-response에서 주어진 watch-id이며, 사용 가능성이 변경된 프레젠테이션 URL을 지칭하는 데 사용된다.

url-availabilities

URL 사용 가능성 상태 목록. 각 상태는 watch-id가 지칭하는 요청의 URL에 대응해야 한다.

이러한 메시지는 모든 컨트롤러에게 브로드캐스트되지 않는다는 점에 유의한다. 원래의 사용 가능성 요청의 감시 기간 내에 사용 가능성 상태가 변경된 URL에 대해 사용 가능성을 요청한 컨트롤러에게 개별적으로 보내진다.

절전을 전송 요구사항으로 추가하고 다음 내용을 제거. [Issue #342]

전력을 절약하기 위해, 컨트롤러는 QUIC 연결을 끊고 나중에 다시 연결하여 사용 가능성 요청을 보내고 사용 가능성 응답 및 업데이트를 받을 수 있다. 다시 연결할 때 QUIC 연결 ID는 같을 수도 있고 같지 않을 수도 있다.

프레젠테이션을 시작하기 위해, 컨트롤러는 다음 값을 가진 presentation-start-request 메시지를 수신자에게 보낼 수 있다:

presentation-id

프레젠테이션 식별자

url

선택된 프레젠테이션 URL

headers

수신자가 프레젠테이션 URL을 가져올 때 사용해야 하는 헤더. 예를 들어, Presentation API의 6.6.1절은 HTTP Accept-Language 헤더가 제공되어야 한다고 말한다.

프레젠테이션 식별자는 Presentation API의 6.1절에서 정의한 제한을 따라야 하며, 최소 16개의 ASCII 문자로 구성되어야 한다.

수신자가 presentation-start-request를 수신하면, 프레젠테이션 URL을 가져와 로드했거나 그렇게 하는 데 실패한 후 presentation-start-response 메시지를 되돌려 보내는 것이 좋다. 실패한 경우, 적절한 결과(예: invalid-url 또는 timeout)로 응답해야 한다. 성공한 경우, 성공 결과로 응답해야 한다.

또한, 응답은 다음을 포함해야 한다:

connection-id

두 에이전트가 서로에게 연결 메시지를 보낼 때 사용할 수 있는 ID이다. 구현의 용이성을 위해 수신자가 선택한다. 메시지 수신자가 connection-id를 선택하면, 연결 전반에서 ID를 고유하게 유지할 수 있으므로 메시지 역다중화/라우팅이 쉬워진다.

응답은 다음을 포함하는 것이 좋다:

http-response-code

프레젠테이션 URL을 가져올 때 반환된 숫자 HTTP 응답 코드(리디렉션 후).

프레젠테이션 메시지를 보내기 위해, 컨트롤러 또는 수신자는 다음 값을 가진 presentation-connection-message를 보낼 수 있다:

connection-id

presentation-start-response 또는 presentation-connection-open-response 메시지의 ID.

message

프레젠테이션 메시지 데이터.

다음 NOTE를 모든 메시지 전송에 대한 전송 요구사항으로 다시 작성. [Issue #342]

NOTE: OSP 에이전트는 반드시 필요한 것(즉, CBOR 직렬화)을 넘어서는 송수신 메시지의 버퍼링 및 처리를 최소화하는 것이 좋다. 메시지 페이로드는 미디어 스트림의 재생을 에이전트 간에 동기화하거나 기타 저지연 사용 사례에 사용될 수 있으므로 실시간 데이터로 취급하는 것이 좋다. [ITU-R-BT.1359-1]에서 권장하는 동기화 임계값은 미디어 재생 중 효과적인 립싱크를 허용하려면 전체 에이전트 간 처리 지연(직렬화, 버퍼링 및 네트워크 지연 포함)이 45ms를 넘지 않아야 함을 의미한다.

프레젠테이션을 종료하기 위해, 컨트롤러는 다음 값을 가진 presentation-termination-request 메시지를 보낼 수 있다:

presentation-id

종료할 프레젠테이션의 ID.

reason

애플리케이션이 종료를 요청한 경우 application-request로 설정하고, 사용자가 종료를 요청한 경우 user-request로 설정한다. (이 값들은 presentation-termination-requestreason에 대한 유일한 유효 값이다.)

수신자presentation-termination-request를 수신하면, 요청한 컨트롤러에게 presentation-termination-response 메시지를 되돌려 보내는 것이 좋다.

또한 presentation-termination-event 메시지를 보내 종료를 다른 컨트롤러에게 알리는 것이 좋다. 그리고 컨트롤러의 요청 없이 프레젠테이션을 종료하는 경우에도 동일한 메시지를 보낼 수 있다. 이 메시지는 다음 값을 포함한다:

presentation-id

종료된 프레젠테이션의 ID.

source

종료가 presentation-termination-request에 대한 응답으로 이루어진 경우 controller로 설정하고, 그렇지 않으면 receiver로 설정한다.

reason

프레젠테이션이 종료된 자세한 이유.

컨트롤러로부터 들어오는 연결 요청을 수락하려면, 수신자는 다음 값을 포함하는 presentation-connection-open-request 메시지를 수신하고 처리해야 한다:

presentation-id

연결할 프레젠테이션의 ID.

url

연결할 프레젠테이션의 URL.

수신자는 presentation-connection-open-request 메시지를 수신하면, 다음 값을 포함하는 presentation-connection-open-response 메시지를 되돌려 보내는 것이 좋다:

result

성공 또는 실패 및 실패 이유를 나타내는 코드

connection-id

두 에이전트가 서로에게 연결 메시지를 보낼 때 사용할 수 있는 ID이다. 구현의 용이성을 위해 수신자가 선택한다(메시지 수신자가 connection-id를 선택하면, 연결 전반에서 ID를 고유하게 유지할 수 있으므로 메시지 역다중화/라우팅이 쉬워진다).

connection-count

들어오는 연결 요청을 받은 프레젠테이션에 대해 새로 열린 연결의 수.

presentation-connection-open-response 메시지가 성공을 나타내는 경우, 수신자는 해당 프레젠테이션에 대해 활성 프레젠테이션 연결을 가진 모든 다른 엔드포인트에게 다음 값을 가진 presentation-change-event도 보내는 것이 좋다:

presentation-id

방금 새 프레젠테이션 연결을 받은 프레젠테이션의 ID.

connection-count

해당 프레젠테이션에 대해 열린 연결의 새 총수.

컨트롤러는 프레젠테이션을 종료하지 않고 연결을 닫기 위해 다음 값을 가진 presentation-connection-close-event 메시지를 수신자에게 보낼 수 있다:

connection-id

닫힌 연결의 ID.

reason

close-method-called 또는 connection-object-discarded로 설정한다.

수신자도 프레젠테이션을 종료하지 않고 연결을 닫을 수 있다. 그렇게 하는 경우, 다음 값을 가진 presentation-connection-close-event 메시지를 컨트롤러에게 보내는 것이 좋다:

connection-id

닫힌 연결의 ID.

reason

close-method-called 또는 connection-object-discarded로 설정한다.

connection-count

남아 있는 열린 프레젠테이션 연결의 수.

수신자가 어떤 이유로든 프레젠테이션 연결을 닫는 경우, 해당 프레젠테이션에 열린 연결을 가진 모든 다른 컨트롤러에게 다음 값을 가진 presentation-change-event를 보내는 것이 좋다:

presentation-id

방금 연결을 닫은 프레젠테이션의 ID.

connection-count

남아 있는 열린 프레젠테이션 연결의 수.

Note: 에이전트가 프레젠테이션 연결을 닫는 것은 항상 성공하므로 요청 및 응답 메시지가 필요하지 않다. 프레젠테이션 종료 요청은 성공하거나 실패할 수 있으므로 응답 메시지가 필요하다.

5.1. Presentation API

오픈 스크린 프로토콜 에이전트Presentation API제어 사용자 에이전트인 경우, control-presentation 기능을 지원해야 한다. OSP 에이전트Presentation API수신 사용자 에이전트인 경우, receive-presentation 기능을 지원해야 한다. 동일한 OSP 에이전트는 제어 사용자 에이전트이면서 수신 사용자 에이전트일 수 있다.

Presentation API§ 5 프레젠테이션 프로토콜을 사용하는 방식은 다음과 같다:

6.4.2절이 "이 프레젠테이션 디스플레이 목록은 ... 구현별 발견 메커니즘을 기반으로 채워진다"라고 말할 때, 컨트롤러는 수신자를 발견하기 위해 이 명세에서 앞서 정의한 mDNS, QUIC, agent-info-requestpresentation-url-availability-request 메시지를 사용할 수 있다.

6.4.2절이 "전력을 더 절약하기 위해, ... 프레젠테이션 디스플레이에 대한 구현별 발견은 재개되거나 일시 중단될 수 있다."라고 말할 때, 에이전트는 이전 절에서 정의한 절전 메커니즘을 사용할 수 있다.

6.3.4절이 "구현별 메커니즘을 사용하여, U에게 D, presentationUrl 및 I를 매개변수로 하는 수신 브라우징 컨텍스트를 만들라고 지시한다."라고 말할 때, U(컨트롤러)는 D(수신자)에게 presentation-start-request 메시지를 보낼 수 있으며, I를 프레젠테이션 식별자로, presentationUrl을 선택된 프레젠테이션 URL로 사용한다.

6.3.5절이 "newConnection과 프레젠테이션 연결을 설정한다"라고 말할 때, U를 newConnection의 presentationURL로 하고 I를 newConnection의 프레젠테이션 식별자로 한다. 에이전트는 U를 url로, I를 presentation-id로 하는 presentation-connection-open-request 메시지를 보내는 것이 좋다.

6.5.2절이 "구현별 메커니즘을 사용하여, messageOrData의 내용을 프레젠테이션 메시지 데이터로, messageType을 프레젠테이션 메시지 타입으로 대상 브라우징 컨텍스트에 전송한다"라고 말할 때, 컨트롤러는 messageOrData를 프레젠테이션 메시지 데이터로 하여 presentation-connection-message를 보낼 수 있다. messageType은 인코딩된 CBOR 타입에 포함되며 메시지에 추가 값이 필요하지 않다는 점에 유의한다.

6.5.5절이 "대상 브라우징 컨텍스트에 해당 PresentationConnection을 닫으려는 의도를 신호로 보내기 시작한다"라고 말할 때, 에이전트는 대상 브라우징 컨텍스트와 함께 presentation-connection-close-event 메시지를 다른 에이전트에게 보낼 수 있고, 필요한 경우 presentation-change-event도 보낼 수 있다.

6.5.6절이 "구현별 메커니즘을 사용하여 프레젠테이션에 대한 종료 요청을 그 수신 사용자 에이전트에게 보낸다"라고 말할 때, 컨트롤러는 reasonapplication-request로 하여 presentation-termination-request 메시지를 수신자에게 보낼 수 있다.

6.7.1절이 "구현별 메커니즘을 사용하여 제어 브라우징 컨텍스트로부터 들어오는 연결 요청을 반드시 수신하고 수락해야 한다"라고 말할 때, 수신자는 presentation-connection-open-request를 수신하고 처리해야 한다.

6.7.1절이 "구현별 메커니즘을 사용하여 제어 브라우징 컨텍스트와 수신 브라우징 컨텍스트 사이의 연결을 설정한다."라고 말할 때, 수신자는 presentation-connection-open-response 메시지를 보내야 하며, 필요한 경우 presentation-change-event 메시지도 보내야 한다.

6. 시간 표현

§ 7 원격 재생 프로토콜§ 8 스트리밍 프로토콜은 시점과 지속 시간을 time scale로 표현한다. time scale은 값이 정밀도 손실 없이 유리수로 표현될 수 있게 하는 시간 값의 공통 분모이다. time scale은 헤르츠로 표현되며, 예를 들어 비디오에 흔히 쓰이는 time scale인 90000 Hz의 경우 90000이다.

7. 원격 재생 프로토콜

이 절은 Remote Playback API에서 정의한 미디어의 원격 재생을 시작, 종료 및 제어하기 위해 오픈 스크린 프로토콜을 사용하는 방식을 정의한다. § 7.2 Remote Playback APIRemote Playback API의 API가 이 절에서 정의한 프로토콜 메시지에 어떻게 매핑되는지 정의한다.

이 절에서 정의한 모든 메시지에 대한 전체 CDDL 정의는 부록 A: 메시지를 참조하라.

특정 URL 또는 URL 집합에 대해 어떤 수신자가 호환 가능한 원격 재생 장치인지 알아내기 위해, 컨트롤러는 다음 값을 가진 remote-playback-availability-request 메시지를 보낼 수 있다:

sources

미디어 리소스 목록이며, remote-playback-start-request 메시지에서 지정된 것과 동일하다. 비어 있어서는 안 된다.

headers

수신자가 URL을 가져올 때 사용해야 하는 헤더. 예를 들어, Remote Playback API의 6.2.4절은 Accept-Language 헤더가 제공되어야 한다고 말한다.

watch-duration

컨트롤러가 해당 URL에 대한 변경 업데이트를 수신하는 데 관심이 있는 기간이다.

watch-id

수신자가 URL 사용 가능성에 대한 업데이트를 보낼 때 사용해야 하는 식별자이며, 컨트롤러가 수신자가 어떤 URL을 지칭하는지 알 수 있게 한다.

응답으로, 수신자는 다음 값을 가진 remote-playback-availability-response 메시지를 보내는 것이 좋다:

url-availabilities

URL 사용 가능성 상태 목록. 각 상태는 요청의 같은 목록 인덱스에 있는 URL에 대응해야 한다.

수신자는 나중에(현재 시간에 request watch-duration을 더한 시점까지) URL 사용 가능성이 변경되는 경우 remote-playback-availability-event 메시지를 보내는 것이 좋다. 이러한 이벤트는 다음 값을 포함한다:

watch-id

remote-playback-availability-response에서 주어진 watch-id이며, 사용 가능성이 변경된 원격 재생 URL을 지칭하는 데 사용된다.

url-availabilities

URL 사용 가능성 상태 목록. 각 상태는 watch-id가 지칭하는 요청의 URL에 대응해야 한다.

이러한 메시지는 모든 컨트롤러에게 브로드캐스트되지 않는다는 점에 유의한다. 원래의 사용 가능성 요청의 감시 기간 내에 사용 가능성 상태가 변경된 URL에 대해 사용 가능성을 요청한 컨트롤러에게 개별적으로 보내진다.

절전을 전송 요구사항으로 추가하고 다음 내용을 제거. [Issue #342]

전력을 절약하기 위해, 컨트롤러는 QUIC 연결을 끊고 나중에 다시 연결하여 사용 가능성 요청을 보내고 사용 가능성 응답 및 업데이트를 받을 수 있다. 다시 연결할 때 QUIC 연결 ID는 같을 수도 있고 같지 않을 수도 있다.

원격 재생을 시작하기 위해, 컨트롤러는 다음 값을 가진 remote-playback-start-request 메시지를 수신자에게 보낼 수 있다:

remote-playback-id

이 원격 재생에 대한 식별자이다. 모든 원격 재생 사이에서 전역적으로 고유한 것이 좋다.

Note: 버전 4(의사 난수) UUID가 권장된다. 이는 remote-playback-id에 대한 요구사항을 충족하기 때문이다.

sources (optional)

컨트롤러가 수신자에서 재생하도록 선택한 미디어 리소스이다. 각 소스는 소스 URL을 포함해야 하며, 해당 미디어 리소스에 대해 사용할 수 있는 경우 확장 MIME 타입을 포함하는 것이 좋다. sources가 없거나 비어 있으면, 컨트롤러가 인코딩된 미디어를 보내기 위해 스트리밍 세션을 사용할 것이므로 remoting 필드가 채워져야 한다.

text-track-urls

미디어 리소스와 연결된 텍스트 트랙의 URL.

controls

§ 7.1 원격 재생 상태 및 제어에서 정의한, 원격 재생의 초기 상태를 수정하기 위한 초기 제어이다. 컨트롤러는 수신자가 지원하는지 알기 전에 수신자가 지원할 선택적 제어를 보낼 수 있다. 수신자가 이를 지원하지 않으면 무시할 것이며, 컨트롤러는 remote-playback-start-response 메시지에서 그것을 지원하지 않는다는 사실을 알게 된다.

remoting (optional)

이 원격 재생과 연결된 스트리밍 세션을 시작하기 위한 매개변수이다. 포함되지 않으면 스트리밍 세션은 시작되지 않는다. sources가 없거나 비어 있을 때 필요하다.

수신자가 remote-playback-start-request 메시지를 수신하면, remote-playback-start-response 메시지를 되돌려 보내는 것이 좋다. 보통 미디어 리소스가 로드되기 전에 빠르게 그렇게 하는 것이 좋으며, 대신 remote-playback-state-event 메시지를 통해 로드 진행 상황의 업데이트를 제공한다. 단, 수신자가 리소스 로드를 전혀 시도하지 않기로 결정한 경우는 예외이다. 그렇게 하지 않기로 선택한 경우, 적절한 실패 결과 (예: timeout 또는 invalid-url)로 응답해야 한다. 또한, 응답은 다음을 포함해야 한다:

state

§ 7.1 원격 재생 상태 및 제어에서 정의한 원격 재생의 초기 상태.

remoting (optional)

이 원격 재생과 연결된 시작된 스트리밍 세션에 대한 응답이다. 포함되지 않으면 스트리밍 세션은 시작되지 않는다.

스트리밍 세션이 시작되면, streaming-session-modify-requestvideo-frame 같은 스트리밍 메시지를, 마치 스트리밍 세션이 streaming-session-start-requeststreaming-session-start-response로 시작된 것처럼 해당 스트리밍 세션에 사용할 수 있다. 스트리밍 세션은 원격 재생이 종료되기 전에 종료될 수 있지만, 원격 재생이 먼저 종료되면 연결된 스트리밍 세션도 자동으로 종료된다.

컨트롤러가 원격 재생의 상태를 수정하려는 경우(예: 일시 중지, 재개, 건너뛰기 등), 다음 값을 가진 remote-playback-modify-request 메시지를 보낼 수 있다:

remote-playback-id

수정할 원격 재생의 ID.

controls

§ 7.1 원격 재생 상태 및 제어에서 정의한 갱신된 제어.

수신자가 remote-playback-modify-request를 수신하면, 다음 값을 가진 remote-playback-modify-response 메시지로 응답하는 것이 좋다:

state

§ 7.1 원격 재생 상태 및 제어에서 정의한 원격 재생의 갱신된 상태.

컨트롤러의 수정 요청 없이 원격 재생 상태가 변경되는 경우(예: 수신자에서 사용자 상호작용으로 인해 건너뛰거나 일시 중지되는 경우), 수신자는 컨트롤러에게 remote-playback-state-event를 보낼 수 있다.

수신자는 다음 중 어느 경우든 remote-playback-state-event 메시지를 보내는 것이 좋다:

다음 메서드 중 하나가 호출되는 경우:

다음 속성 중 하나가 마지막으로 보낸 remote-playback-state-event 메시지 이후 관찰 가능하게 변경되는 경우:

재생과 연결된 타임라인 오프셋이 마지막으로 보낸 remote-playback-state-event 메시지 이후 변경되는 경우:

stalled 이벤트가 연결된 HTMLMediaElement 인스턴스에서 발생해야 하는 경우.

마지막 remote-playback-state-event 메시지 이후 250ms가 넘게 지나고, 다음 속성 중 하나가 마지막 remote-playback-state-event 메시지 이후 관찰 가능하게 변경되는 경우. 새롭게 추가되는 지속적으로 변경되는 모든 속성은 이 규칙에 속한다.

NOTE: 미디어 요소는 250ms마다 또는 그보다 더 빨리 timeupdate 이벤트를 발생시켜야 한다.

remote-playback-id

상태가 변경된 원격 재생의 ID.

state

§ 7.1 원격 재생 상태 및 제어에서 정의한 원격 재생의 갱신된 상태.

원격 재생을 종료하기 위해, 컨트롤러는 다음 값을 가진 remote-playback-termination-request 메시지를 보낼 수 있다:

remote-playback-id

종료할 원격 재생의 ID.

reason

원격 재생이 종료되는 이유.

수신자가 remote-playback-termination-request를 수신하면, 컨트롤러에게 remote-playback-termination-response 메시지를 되돌려 보내는 것이 좋다.

수신자가 컨트롤러의 요청 없이 원격 재생을 종료하는 경우, 다음 값을 가진 remote-playback-termination-event 메시지를 컨트롤러에게 보내야 한다:

remote-playback-id

종료된 원격 재생의 ID.

reason

원격 재생이 종료된 이유.

Remote Playback API 6.2.7절에서 언급했듯이, 원격 재생을 종료한다는 것은 컨트롤러가 더 이상 원격 재생을 제어하지 않음을 의미하며, 반드시 수신자에서 미디어 렌더링을 중지한다는 의미는 아니다. 수신자가 미디어 렌더링을 중지하는지 여부는 수신자의 구현에 달려 있다.

7.1. 원격 재생 상태 및 제어

컨트롤러와 수신자가 원격 재생의 상태와 관련하여 동기화 상태를 유지하기 위해, 컨트롤러는 상태를 수정하는 제어를 보낼 수 있고(예: remote-playback-modify-request 메시지를 통해), 수신자는 상태 변경에 대한 업데이트를 보낼 수 있다(예: remote-playback-state-event 메시지를 통해).

컨트롤러가 보내는 제어는 다음과 같은 개별 제어 값을 포함하며, 각 값은 선택 사항이다. 이를 통해 컨트롤러는 매번 모든 제어 값을 지정하지 않고도 하나의 제어 값이나 여러 제어 값을 한 번에 변경할 수 있다. 존재하지 않는 제어 값은 변경이 없음을 나타낸다. 존재하는 제어 값은 아래에 정의된 변경을 나타낸다. 이러한 제어는 의도적으로 HTMLMediaElement의 설정 가능한 속성과 메서드를 반영한다.

source

미디어 리소스를 변경한다. 자세한 내용은 HTMLMediaElement.src를 참조하라. remote-playback-start-request 메시지의 초기 제어에서는 사용해서는 안 된다(이미 미디어 리소스가 포함되어 있기 때문이다).

preload

미디어를 얼마나 적극적으로 미리 로드할지 설정한다. 자세한 내용은 HTMLMediaElement.preload를 참조하라. 이는 remote-playback-start-request 메시지의 초기 제어에서만 또는 소스가 변경될 때만 사용하는 것이 좋다. 초기 제어에서 설정되지 않은 경우 수신자가 결정하도록 둔다. 이는 수신자가 지원할 선택 사항이며, 지원되지 않으면 수신자는 이것이 설정되지 않은 것처럼 동작한다.

loop

미디어를 반복할지 여부를 설정한다. 자세한 내용은 HTMLMediaElement.loop를 참조하라. 이는 remote-playback-start-request의 초기 제어에서만 사용하는 것이 좋다. 초기 제어에서 설정되지 않은 경우 false로 간주된다.

paused

true이면 일시 중지하고, false이면 재개한다. 자세한 내용은 HTMLMediaElement.pause()HTMLMediaElement.play()를 참조하라. 초기 제어에서 설정되지 않은 경우 수신자가 결정하도록 둔다.

muted

true이면 음소거하고, false이면 음소거를 해제한다. 자세한 내용은 HTMLMediaElement.muted를 참조하라. 초기 제어에서 설정되지 않은 경우 수신자가 결정하도록 둔다.

volume

오디오 볼륨을 0.0에서 1.0까지의 포함 범위로 설정한다. 자세한 내용은 HTMLMediaElement.volume를 참조하라. 초기 제어에서 설정되지 않은 경우 수신자가 결정하도록 둔다.

seek

정확한 시간으로 탐색한다. 자세한 내용은 HTMLMediaElement.currentTime를 참조하라.

fast-seek

가능한 한 빠르게 근사 시간으로 탐색한다. 자세한 내용은 HTMLMediaElement.fastSeek()를 참조하라.

playback-rate

미디어가 재생되는 속도를 설정한다. 자세한 내용은 HTMLMediaElement.playbackRate를 참조하라. 초기 제어에서 설정되지 않은 경우 수신자가 결정하도록 둔다. 이는 수신자가 지원할 선택 사항이며, 지원되지 않으면 수신자는 이것이 설정되지 않은 것처럼 동작한다.

poster

비디오 데이터를 사용할 수 없을 때 표시할 이미지의 URL을 설정한다. 자세한 내용은 poster frame을 참조하라. 초기 제어에서 설정되지 않은 경우 포스터는 사용되지 않으며, 수신자는 비디오 데이터를 사용할 수 없을 때 무엇을 렌더링할지 선택할 수 있다. 이는 수신자가 지원할 선택 사항이며, 지원되지 않으면 수신자는 이것이 설정되지 않은 것처럼 동작한다.

enabled-audio-track-ids

포함된 오디오 트랙을 ID로 활성화하고 다른 모든 오디오 트랙은 비활성화한다. 자세한 내용은 HTMLMediaElement.audioTracks를 참조하라.

selected-video-track-id

주어진 비디오 트랙을 ID로 선택하고 다른 모든 비디오 트랙은 선택 해제한다. 자세한 내용은 HTMLMediaElement.videoTracks를 참조하라.

added-text-tracks

주어진 종류, 레이블 및 언어를 가진 텍스트 트랙을 추가한다. 자세한 내용은 HTMLMediaElement.addTextTrack()를 참조하라. 이는 수신자가 지원할 선택 사항이며, 지원되지 않으면 수신자는 이것이 설정되지 않은 것처럼 동작한다.

changed-text-tracks

텍스트 트랙을 ID로 변경한다. 다른 모든 텍스트 트랙은 변경되지 않는다. 모드를 설정하고, 큐를 id로 추가 및 제거한다. 자세한 내용은 HTMLMediaElement.textTracks를 참조하라. 향후 명세나 이 명세의 확장은 text-track-cue에 새 필드 (예: 텍스트 크기, 정렬, 위치 등)를 추가할 것으로 예상된다. 큐 추가 및 제거는 수신자가 지원할 선택 사항이며, 지원되지 않으면 수신자는 어떤 큐도 추가되거나 제거되지 않은 것처럼 동작한다(추가와 제거는 모두 "added-cues" 지원을 통해 표시된다). HTMLMediaElement.textTracks에서 지정한 것처럼, 큐 ID가 유효하지 않은 경우(예: 추가되지 않은 ID를 제거하거나 ID를 두 번 추가하는 경우), 수신자는 텍스트 트랙 변경을 거부할 수 있다.

필드 초기 제어의 기본값 수신자 지원
source remote-playback-start-requesturls 필수
preload 수신자가 결정 필수 아님
loop False 필수
paused 수신자가 결정 필수
muted 수신자가 결정 필수
volume 수신자가 결정 필수
seek (없음) 필수
fast-seek (없음) 필수
playback-rate 수신자가 결정 필수 아님
poster 수신자가 결정 필수 아님
enabled-audio-track-ids (없음) 필수
selected-video-track-id (없음) 필수
added-text-tracks (없음) 필수 아님
changed-text-tracks (없음) 필수 아님

수신자가 보내는 상태는 다음과 같은 개별 상태 값을 포함하며, 각 값은 선택 사항이다. 이를 통해 수신자는 매번 모든 상태 값을 지정하지 않고도 둘 이상의 상태 값에 대해 컨트롤러를 한 번에 업데이트할 수 있다. 존재하지 않는 상태 값은 상태가 변경되지 않았음을 나타낸다.

supports

수신자가 지원하는 제어이다. 이는 미디어 리소스에 따라 달라질 수 있으며, 미디어 리소스도 변경되지 않는 한 변경되지 않는 것이 좋다. remote-playback-start-response 메시지의 초기 상태에 대한 기본값은 비어 있음(아무것도 지원하지 않음)이다.

source

현재 미디어 리소스이다. HTMLMediaElement.currentSrc를 참조하라. remote-playback-start-response 메시지의 초기 상태에 반드시 존재해야 하며, 이를 통해 컨트롤러는 재생에 어떤 미디어 리소스가 선택되었는지 알 수 있다.

loading

미디어 리소스를 로드하기 위한 네트워크 활동 상태이다. HTMLMediaElement.networkState를 참조하라. remote-playback-start-response 메시지의 초기 상태에 대한 기본값은 empty(NETWORK_EMPTY)이다.

loaded

로드된 미디어의 상태(재생하기에 충분히 로드되었는지 여부)이다. HTMLMediaElement.readyState를 참조하라. remote-playback-start-response 메시지의 초기 상태에 대한 기본값은 nothing(HAVE_NOTHING)이다.

error

원격 재생이 계속되는 것을 막는 중대한 오류가 발생했다. HTMLMediaElement.error미디어 오류 코드를 참조하라. remote-playback-start-response 메시지의 초기 상태에 대한 기본값은 오류 없음이다.

epoch

미디어 타임라인의 "zero time"이며, 에포크 기준 밀리초 단위이다. 타임라인 오프셋HTMLMediaElement.getStartDate()를 참조하라. remote-playback-start-response 메시지의 초기 상태에 대한 기본값은 알 수 없는 epoch이며, null로 표현된다.

duration

미디어 타임라인의 지속 시간이며, 초 단위이다. HTMLMediaElement.duration를 참조하라. remote-playback-start-response 메시지의 초기 상태에 대한 기본값은 알 수 없는 duration이며, null로 표현된다.

buffered-time-ranges

미디어가 버퍼링된 시간 범위이다. HTMLMediaElement.buffered를 참조하라. remote-playback-start-response 메시지의 초기 상태에 대한 기본값은 빈 배열이다.

played-time-ranges

정상 재생 중 재생 위치가 도달한 시간 범위이다. HTMLMediaElement.played를 참조하라. remote-playback-start-response 메시지의 초기 상태에 대한 기본값은 빈 배열이다.

seekable-time-ranges

컨트롤러 또는 수신자가 미디어를 탐색할 수 있는 시간 범위이다. HTMLMediaElement.seekable를 참조하라. remote-playback-start-response 메시지의 초기 상태에 대한 기본값은 빈 배열이다.

position

재생 위치이다. 공식 재생 위치HTMLMediaElement.currentTime를 참조하라. remote-playback-start-response 메시지의 초기 상태에 대한 기본값은 0이다.

playbackRate

1.0이 "정상 속도"인 척도에서의 현재 재생 속도이다. HTMLMediaElement.playbackRate를 참조하라. remote-playback-start-response 메시지의 초기 상태에 대한 기본값은 1.0이다.

paused

미디어가 일시 중지되었는지 여부이다. HTMLMediaElement.paused를 참조하라. remote-playback-start-response 메시지의 초기 상태에 대한 기본값은 false이다.

seeking

수신자가 탐색 중인지 여부이다. HTMLMediaElement.seeking을 참조하라. remote-playback-start-response 메시지의 초기 상태에 대한 기본값은 false이다.

stalled

true이면 충분한 미디어가 로드되지 않아 미디어가 재생되지 않음을 의미하고, 그렇지 않으면 false이다. stalled 이벤트를 참조하라. remote-playback-start-response 메시지의 초기 상태에 대한 기본값은 false이다.

ended

미디어가 끝에 도달했는지 여부이다. HTMLMediaElement.ended를 참조하라. remote-playback-start-response 메시지의 초기 상태에 대한 기본값은 false이다.

volume

0.0에서 1.0까지의 척도에서의 현재 재생 볼륨이다. HTMLMediaElement.volume를 참조하라. remote-playback-start-response 메시지의 초기 상태에 대한 기본값은 1.0이다.

muted

오디오가 음소거되어 있으면 true(볼륨 값을 재정의함), 그렇지 않으면 false이다. HTMLMediaElement.muted를 참조하라. remote-playback-start-response 메시지의 초기 상태에 대한 기본값은 false이다.

resolution

비디오의 "intrinsic width" 및 "intrinsic width"이다. HTMLVideoElement.videoWidthHTMLVideoElement.videoHeight를 참조하라. remote-playback-start-response 메시지의 초기 상태에 대한 기본값은 알 수 없는 해상도이며, null로 표현된다.

audio-tracks

사용 가능한 오디오 트랙이며, 각각을 활성화하거나 비활성화할 수 있다. HTMLMediaElement.audioTracks를 참조하라. remote-playback-start-response 메시지의 초기 상태에 대한 기본값은 빈 배열이다.

video-tracks

사용 가능한 비디오 트랙이다. 하나만 선택될 수 있다. HTMLMediaElement.videoTracks를 참조하라. remote-playback-start-response 메시지의 초기 상태에 대한 기본값은 빈 배열이다.

text-tracks

사용 가능한 텍스트 트랙이며, 각각을 표시, 숨김 또는 비활성화할 수 있다. HTMLMediaElement.textTracks를 참조하라. 컨트롤러는 텍스트 트랙에 큐를 추가하거나 제거할 수도 있다. remote-playback-start-response 메시지의 초기 상태에 대한 기본값은 빈 배열이다.

미디어 위치, 지속 시간 및 시간 범위는 HTML에 지정된 미디어 타임라인의 관점에서 정의되며, 이는 0과 미디어 지속 시간 사이의 소수 초이다.

NOTE: 오픈 스크린 에이전트는 부록 C: 미디어 시간 변환의 단계를 사용하여 미디어 타임라인의 값과 개별 미디어 프레임과 함께 전송되는 미디어 동기화 시간 사이를 변환할 수 있다.

필드 초기 상태의 기본값
supports 비어 있음
source remote-playback-start-responsestate 안의 url (필수 필드)
loading empty
loaded nothing
error 오류 없음
epoch null
duration null
buffered-time-ranges 빈 배열
played-time-ranges 빈 배열
seekable-time-ranges 빈 배열
position 0.0
playbackRate 1.0
paused False
seeking False
stalled False
ended False
volume 1.0
muted False
resolution null
audio-tracks 빈 배열
video-tracks 빈 배열
text-tracks 빈 배열

7.2. Remote Playback API

오픈 스크린 프로토콜 에이전트Remote Playback API를 구현하는 경우, control-remote-playback 기능을 지원해야 한다. 또한 미디어 리모팅을 통해 HTMLMediaElement 미디어 데이터를 보낼 수 있도록 send-streaming 기능을 지원할 수 있다.

OSP 에이전트Remote Playback API원격 재생 장치인 경우, receive-remote-playback 기능을 지원해야 한다. 또한 미디어 리모팅을 통해 HTMLMediaElement 데이터를 받을 수 있도록 receive-streaming 기능을 지원할 수 있다.

동일한 OSP 에이전트는 Remote Playback API를 구현하면서 동시에 그 API에 대한 원격 재생 장치일 수 있다.

Remote Playback API§ 7 원격 재생 프로토콜에서 정의한 메시지를 사용하는 방식은 다음과 같다:

5.2.1.2절이 "이 목록은 원격 재생 장치를 포함하며, 구현별 발견 메커니즘을 기반으로 채워진다"라고 말하고, 5.2.1.4절이 "사용 가능한 원격 재생 장치를 검색한다(구현별 메커니즘 사용)"라고 말할 때, 사용자 에이전트는 수신자를 발견하기 위해 이 명세에서 앞서 정의한 mDNS, QUIC, agent-info-requestremote-playback-availability-request 메시지를 사용할 수 있다. remote-playback-availability-request URL은 availability sources set을 포함해야 한다.

5.2.4절이 "원격 장치에 대한 연결을 요청한다. 이 단계의 구현은 사용자 에이전트에 특화된다." 및 "현재 미디어 요소 상태를 원격 재생 상태와 동기화한다"라고 말할 때, 컨트롤러는 원격 재생을 시작하기 위해 remote-playback-start-request 메시지를 수신자에게 보낼 수 있다. remote-playback-start-request URL은 remote playback source를 포함해야 한다. 현재 Remote Playback API는 단일 소스만 허용하지만, 프로토콜은 여러 소스를 허용하며 향후 버전의 Remote Playback API는 여러 소스를 허용할 수 있다.

5.2.4절이 "사용자 에이전트와 원격 재생 장치를 연결하고 원격 재생 소스를 재생하는 데 사용되는 메커니즘은 사용자 에이전트의 구현 선택이다. 연결은 미디어 요소 상태와 원격 재생 상태를 동기화된 상태로 유지하기 위해, 원격 재생 장치에 미디어 명령을 전달하고 미디어 재생 상태를 수신할 수 있는 양방향 메시징 추상화를 제공해야 할 가능성이 높다"라고 말할 때, 컨트롤러는 로컬 미디어 요소의 변경에 따라 원격 재생 상태를 변경하기 위해 수신자에게 remote-playback-modify-request 메시지를 보낼 수 있고, 원격 재생 상태의 변경에 따라 로컬 미디어 요소를 변경하기 위해 remote-playback-modify-responseremote-playback-state-event 메시지를 받을 수 있다.

5.2.7절이 "장치에서 원격 연결 해제를 요청한다. 이 단계의 구현은 사용자 에이전트에 특화된다"라고 말할 때, 컨트롤러는 remote-playback-termination-request 메시지를 수신자에게 보낼 수 있다.

8. 스트리밍 프로토콜

이 절은 미디어 발신자에서 미디어 수신자로 미디어를 스트리밍하기 위해 오픈 스크린 프로토콜을 사용하는 방식을 정의한다.

오픈 스크린 프로토콜 에이전트가 미디어 발신자인 경우, send-streaming 기능을 광고해야 한다. OSP 에이전트가 미디어 수신자인 경우, receive-streaming 기능을 광고해야 한다. 동일한 에이전트가 미디어 발신자이면서 미디어 수신자일 수 있다.

8.1. 스트리밍 프로토콜 기능

광고자가 이미 인증된 경우, 요청자는 streaming-capabilities-request 메시지를 보내 추가 정보를 요청하고, 다음 필드를 가진 streaming-capabilities-response 메시지를 되돌려 받을 수 있다:
receive-audio (required)

오디오 수신 기능 목록. 필드에 대한 설명은 아래를 참조하라.

receive-video (required)

비디오 수신 기능 목록. 필드에 대한 설명은 아래를 참조하라.

format 타입은 오디오 및 비디오 기능의 기반으로 사용된다. format은 다음 필드로 구성된다:

codec-name (required)

[WEBCODECS-CODEC-REGISTRY]에 나열된 정규화된 코덱 문자열이며, 해당 레지스트리에서 참조하는 코덱별 등록에 의해 추가로 지정된다.

codec-name에 대해, 오픈 스크린 에이전트는 [WEBCODECS-CODEC-REGISTRY]에 나열되지 않은 코덱에 대해 [RFC6381]에 설명된 단일 코덱 codec parameter도 허용할 수 있다.

오디오 기능은 위의 format 타입에 다음 추가 필드를 더해 구성된다:

max-audio-channels (optional)

미디어 수신자가 지원할 수 있는 최대 오디오 채널 수를 나타내는 선택적 필드이다. 기본값은 "2"이며, 스테레오 스피커 채널 구성을 의미한다.

min-bit-rate (optional)

미디어 수신자가 처리할 수 있는 최소 오디오 비트레이트를 킬로비트/초 단위로 나타내는 선택적 필드이다. 기본값은 최소값 없음이다.

비디오 기능도 위의 format 타입에 다음 추가 필드를 더해 유사하게 구성된다:

max-resolution (optional)

미디어 수신자가 처리할 수 있는 최대 비디오 해상도(너비, 높이)를 나타내는 선택적 필드이다. 기본값은 최대값 없음이다.

max-frames-per-second (optional)

미디어 수신자가 처리할 수 있는 최대 초당 프레임 수를 나타내는 선택적 필드이다. 기본값은 최대값 없음이다.

max-pixels-per-second (optional)

미디어 수신자가 처리할 수 있는 최대 초당 픽셀 수를 픽셀/초 단위로 나타내는 선택적 필드이다. 기본값은 최대값 없음이다.

min-video-bit-rate (optional)

장치가 처리할 수 있는 최소 비디오 비트레이트를 킬로비트/초 단위로 나타내는 선택적 필드이다. 기본값은 최소값 없음이다.

aspect-ratio (optional)

이상적인 종횡비를 나타내는 선택적 필드이다. 예를 들어 16:10 디스플레이는 선호하는 콘텐츠 스케일링을 나타내기 위해 이 값을 1.6으로 반환할 수 있다. 기본값은 없음이다.

color-gamut (optional)

미디어 수신자가 디코딩하고 렌더링할 수 있는 가장 넓은 색 공간을 나타내는 선택적 필드이다. 미디어 발신자는 이 값을 사용하여 비디오를 인코딩하는 방식을 결정할 수 있으며, 더 좁은 모든 색 공간은 지원된다고 가정하는 것이 좋다. 유효한 값은 ColorGamut에 대응하며, 이는 Media Capabilities API에 정의되어 있다. 기본값은 "srgb"이다.

NOTE: "p3" 지원은 "srgb" 지원을 의미하며, "rec2020" 지원은 "p3" 및 "srgb" 지원을 의미한다.

hdr-formats (optional)

미디어 수신자가 디코딩하고 렌더링할 수 있는 HDR 전달 함수 및 메타데이터 형식을 나타내는 선택적 필드이다. 각 video-hdr-formattransfer-functionhdr-metadata 두 필드로 구성된다.

transfer-function 필드는 유효한 TransferFunction이어야 하며, hdr-metadata 필드는 유효한 HdrMetadataType이어야 한다. 둘 다 Media Capabilities API에 정의되어 있다.

video-hdr-formattransfer-function과 함께 제공되지만 hdr-metadata가 없으면, 미디어 수신자는 관련 메타데이터 없이 transfer-function을 렌더링할 수 있다. (예를 들어 "hlg" transfer-function이 이 경우에 해당한다.)

미디어 수신자는 hdr-formats의 중복 항목을 무시하는 것이 좋다. hdr-formats가 나열되지 않으면, 미디어 수신자는 어떤 HDR 형식도 디코딩할 수 없다.

native-resolutions (optional)

미디어 수신자가 지원하고 "native"라고 간주하는 비디오 해상도를 나타내는 선택적 필드이며, 이는 스케일링이 필요하지 않음을 의미한다. 기본값은 없음이다.

supports-scaling (optional)

미디어 수신자가 native-resolutions 목록(제공된 경우)에 나열되지 않은 비디오 해상도 또는 다른 종횡비로 제공된 콘텐츠를 스케일링할 수 있는지 여부를 나타내는 선택적 불리언 필드이다. 기본값은 true이다.

supports-rotation (optional)

미디어 수신자가 rotation 필드가 설정된 비디오 프레임을 수신할 수 있는지 여부를 나타내는 선택적 불리언 필드이다. 기본값은 true이다.

8.2. 세션

스트리밍 세션을 시작하기 위해, 발신자는 다음 필드를 가진 streaming-session-start-request 메시지를 보낼 수 있다:

streaming-session-id

스트리밍 세션을 식별한다. (발신자, 수신자) 쌍에 대해 고유해야 한다. 나중에 스트리밍 세션을 수정하거나 종료하는 데 사용할 수 있다. 이러한 ID는 § 9 요청, 응답 및 감시에 지정된 것처럼 state-token과 관련하여 다른 ID와 동일하게 취급하는 것이 좋다.

desired-stats-interval

수신자가 발신자에게 stats 메시지를 보내야 하는 빈도를 나타낸다.

stream-offers

수신자가 발신자에게 요청할 수 있는 스트림을 나타낸다.

각 stream offer는 다음 필드를 포함한다:

media-stream-id

제공되는 미디어 스트림을 식별한다. 스트리밍 세션 내에서 고유해야 한다. 수신자가 미디어 세션을 요청하는 데 사용할 수 있다. 이러한 ID는 § 9 요청, 응답 및 감시에 지정된 것처럼 state-token과 관련하여 다른 ID와 동일하게 취급하는 것이 좋다.

display-name

사용자에게 표시되도록 의도된 선택적 이름이다. 이를 통해 수신자는 사용자가 어떤 미디어 스트림을 수신할지 선택할 수 있게 하거나, 수신자가 자동으로 수신하는 경우 미디어 스트림이 무엇인지에 대한 정보를 사용자에게 제공할 수 있다.

audio

제공되는 오디오 인코딩 목록이다. 오디오 인코딩은 일련의 인코딩된 오디오 프레임이다. 인코딩은 수신자가 인코딩을 디코딩하는 방법을 알기 위해 필요한 필드(예: 코덱)를 정의한다. 코덱 및 관련 필드에 따라 달라질 수 있지만, 동일한 오디오의 서로 다른 인코딩이어야 한다.

video

제공되는 비디오 인코딩 목록이다. 비디오 인코딩은 일련의 인코딩된 비디오 프레임이다. 인코딩은 수신자가 인코딩을 디코딩하는 방법을 알기 위해 필요한 필드(예: 코덱 및 기본 지속 시간)를 정의한다. 코덱 및 잠재적으로 다른 필드에 따라 달라질 수 있지만, 동일한 비디오의 서로 다른 인코딩이어야 한다.

data

제공되는 데이터 인코딩 목록이다. 데이터 인코딩은 일련의 데이터 프레임이다. 인코딩은 수신자가 인코딩을 해석하는 방법을 알기 위해 필요한 필드(예: 데이터 타입 및 기본 지속 시간)를 정의한다. 데이터 타입 및 잠재적으로 다른 필드에 따라 달라질 수 있지만, 동일한 데이터의 서로 다른 인코딩이어야 한다. (서로 다른 데이터의 인코딩에는 동일한 미디어 스트림의 서로 다른 인코딩이 아니라 별개의 미디어 스트림을 사용한다).

제공되는 각 오디오 인코딩은 다음 필드를 정의한다:

encoding-id

제공되는 오디오 인코딩을 식별한다. 미디어 스트림 내에서 고유해야 한다. 이러한 ID는 § 9 요청, 응답 및 감시에 지정된 것처럼 state-token과 관련하여 요청 ID와 동일하게 취급하는 것이 좋다.

codec-name

인코딩에서 사용하는 코덱의 이름이며, § 8.1 스트리밍 프로토콜 기능codec-name과 동일한 규칙을 따른다.

time-scale

모든 오디오 프레임에서 사용되는 time scale이다. 이를 통해 발신자는 각 audio-frame 메시지에 time scale을 포함하지 않아 audio-frame 메시지를 더 작게 만들 수 있다.

default-duration:

오디오 프레임의 지속 시간이다. 이를 통해 발신자는 기본 지속 시간을 가진 audio-frame 메시지에 지속 시간을 포함하지 않아 audio-frame 메시지를 더 작게 만들 수 있다.

제공되는 각 비디오 인코딩은 다음 필드를 정의한다:

encoding-id

제공되는 비디오 인코딩을 식별한다. 미디어 스트림 내에서 고유해야 한다. 이러한 ID는 § 9 요청, 응답 및 감시에 지정된 것처럼 state-token과 관련하여 요청 ID와 동일하게 취급하는 것이 좋다.

codec-name

인코딩에서 사용하는 코덱의 이름이며, § 8.1 스트리밍 프로토콜 기능codec-name과 동일한 규칙을 따른다.

time-scale

모든 비디오 프레임에서 사용되는 time scale이다. 이를 통해 발신자는 각 video-frame 메시지에 time scale을 포함하지 않아 video-frame 메시지를 더 작게 만들 수 있다.

default-duration:

비디오 프레임의 기본 지속 시간이다. 이를 통해 발신자는 기본 지속 시간을 가진 video-frame 메시지에 지속 시간을 포함하지 않아 video-frame 메시지를 더 작게 만들 수 있다.

default-rotation:

비디오 프레임의 기본 회전이다. 이를 통해 발신자는 기본 회전을 가진 video-frame 메시지에 회전을 포함하지 않아 video-frame 메시지를 더 작게 만들 수 있다.

제공되는 각 데이터 인코딩은 다음 필드를 정의한다:

encoding-id

제공되는 데이터 인코딩을 식별한다. 미디어 스트림 내에서 고유해야 한다. 이러한 ID는 § 9 요청, 응답 및 감시에 지정된 것처럼 state-token과 관련하여 요청 ID와 동일하게 취급하는 것이 좋다.

data-type-name

인코딩에서 사용되는 데이터 타입의 이름이다.

time-scale

모든 데이터 프레임에서 사용되는 time scale이다. 이를 통해 발신자는 각 data-frame 메시지에 time scale을 포함하지 않아 data-frame 메시지를 더 작게 만들 수 있다.

default-duration:

데이터 프레임의 지속 시간이다. 이를 통해 발신자는 기본 지속 시간을 가진 data-frame 메시지에 지속 시간을 포함하지 않아 data-frame 메시지를 더 작게 만들 수 있다.

streaming-session-start-request 메시지를 받은 후, 수신자는 다음 필드를 가진 streaming-session-start-response 메시지를 되돌려 보내는 것이 좋다:

desired-stats-interval

발신자가 수신자에게 stats 메시지를 보내야 하는 빈도를 나타낸다.

stream-requests

수신자가 발신자로부터 수신하고자 하는 미디어 스트림을 나타낸다.

각 stream request는 다음 필드를 포함한다:

media-stream-id

요청된 스트림의 ID.

audio (optional)

인코딩 ID로 지정된 요청된 오디오 인코딩

video (optional)

인코딩 ID로 지정된 요청된 비디오 인코딩이다. 이는 대상 해상도 및 최대 프레임 속도를 포함할 수 있다. 발신자는 최대 프레임 속도를 초과하지 않는 것이 좋으며, 대상 비트레이트로 전송하려고 시도하는 것이 좋다. 경우에 따라 약간 초과할 수 있다.

data (optional)

인코딩 ID로 지정된 요청된 데이터 인코딩

스트리밍 세션 중에, 수신자는 수정된 stream-requests 목록을 포함하는 streaming-session-modify-request를 보내 인코딩에 대해 자신이 한 요청을 수정할 수 있다. 발신자가 streaming-session-modify-request를 받으면, streaming-session-modify-response를 보내 streaming-session-modify-request의 새 요청 적용이 성공했는지 여부를 나타내는 것이 좋다.

NOTE: 발신자가 streaming-session-start-response 또는 streaming-session-modify-request에서 수신자가 선택한 것과 다른 인코딩을 보내려는 경우, 현재 세션을 종료하고 새 세션을 시작해야 한다.

마지막으로, 발신자는 streaming-session-terminate-request 명령을 보내 스트리밍 세션을 종료할 수 있다. 수신자가 streaming-session-terminate-request를 받으면, streaming-session-terminate-response를 되돌려 보내는 것이 좋다. 수신자는 언제든지 종료할 수 있으며, streaming-session-terminate-event 메시지를 보내 발신자에게 알릴 수 있다.

8.3. 오디오

미디어 발신자는 다음 키와 값을 가진 audio-frame 메시지(부록 A: 메시지 참조)를 보내 미디어 수신자에게 오디오를 보낼 수 있다. audio frame 메시지는 일정 시간 범위에 대한 인코딩된 오디오 샘플 집합을 포함한다. 코덱과 타임라인을 공유하는 일련의 인코딩된 오디오 프레임이 오디오 인코딩을 형성한다.

대부분의 오픈 스크린 프로토콜 메시지와 달리, 이 메시지는 struct 기반 그룹화가 아니라 배열 기반 그룹화를 사용한다. 필수 필드의 경우, 이는 wire 상의 바이트를 더 효율적으로 사용할 수 있게 하는데, 스트리밍 오디오에서는 페이로드가 보통 매우 작고 오버헤드의 모든 바이트가 상대적으로 크기 때문에 중요하다. 배열 기반 그룹화에서 선택적 값을 수용하기 위해, 배열의 하나의 선택적 필드가 struct 기반 그룹화의 모든 선택적 값을 보유하는 데 사용된다. 이는 효율성과 유연성 사이의 좋은 균형을 제공할 것으로 기대된다.

다음 내용을 QUIC 세부사항에 의존하지 않도록 다시 작성. [Issue #343]

오디오 프레임이 순서와 다르게 전송될 수 있도록, 별도의 QUIC 스트림에서 전송하는 것이 좋다.

encoding-id

이 오디오 프레임이 속한 미디어 인코딩을 식별한다. 이는 코덱, 코덱 속성, time scale 및 기본 지속 시간과 같은 인코딩의 필드(audio-encoding-offer 메시지에서)를 참조하는 데 사용할 수 있다. encoding id를 통해 인코딩 필드를 참조하면 모든 프레임에 중복 정보를 보내는 것을 피하는 데 도움이 된다.

start-time

오디오 프레임의 시간 범위 시작을 식별한다. 종료 시간은 시작 시간과 지속 시간에서 추론할 수 있다. time scaleencoding-id가 참조하는 audio-encoding-offer 메시지의 time-scale 필드 값과 같다.

duration

존재하는 경우, 오디오 프레임의 지속 시간이다. 존재하지 않는 경우, 지속 시간은 encoding-id가 참조하는 audio-encoding-offer 메시지의 default-duration 필드와 같다. time scaleencoding-id가 참조하는 audio-encoding-offer 메시지의 time-scale 필드 값과 같다.

sync-time

존재하는 경우, 이 오디오 프레임(따라서 이 인코딩)의 시작 시간을 다른 타임라인에 있는 다른 미디어 인코딩의 시작 시간과 동기화하는 데 사용되는 시간이다. 이는 wall clock time일 수 있지만 반드시 그럴 필요는 없으며, 미디어 발신자가 선택한 임의의 clock일 수 있다.

payload

인코딩된 오디오이다. 코덱은 encoding-id가 참조하는 audio-encoding-offer 메시지의 codec-name 필드와 같다.

8.4. 비디오

미디어 발신자는 다음 키와 값을 가진 video-frame 메시지(부록 A: 메시지 참조)를 보내 미디어 수신자에게 비디오를 보낼 수 있다. video frame 메시지는 특정 시점 또는 특정 시간 범위(지속 시간을 알 수 있는 경우)에 있는 인코딩된 비디오 프레임(인코딩된 이미지)을 포함한다. 코덱과 타임라인을 공유하는 일련의 인코딩된 비디오 프레임이 비디오 인코딩을 형성한다.

다음 내용을 QUIC 세부사항에 의존하지 않도록 다시 작성. [Issue #343]

비디오 프레임이 순서와 다르게 전송될 수 있도록, 별도의 QUIC 스트림에서 전송될 수 있다. 인코딩이 독립 프레임까지 이전 프레임에 의존하는 긴 인코딩된 비디오 프레임 체인인 경우, 독립 프레임에서 시작하여 마지막 의존 프레임에서 끝나는 하나의 QUIC 스트림으로 보내는 것이 타당할 수 있다.

encoding-id

이 비디오 프레임이 속한 미디어 인코딩을 식별한다. 이는 코덱, 코덱 속성, time scale 및 기본 회전과 같은 인코딩의 필드를 참조하는 데 사용할 수 있다. encoding id를 통해 인코딩 필드를 참조하면 모든 프레임에 중복 정보를 보내는 것을 피하는 데 도움이 된다.

sequence-number

인코딩 내의 프레임과 그 순서를 식별한다. 인코딩 내에서 더 큰 sequence number는 더 늦은 start time을 의미한다. 인코딩 내에서 sequence number의 간격은 프레임이 누락되었음을 의미한다.

depends-on

존재하는 경우, 이 프레임이 의존하는 프레임의 sequence number이다. sequence number가 음수이면 상대 sequence number로 취급되며, 이 프레임의 sequence number에 더하여 sequence number가 계산된다. 비어 있으면 이는 독립 프레임(키 프레임)이다. 존재하지 않으면 기본값은 [-1]이다.

start-time

비디오 프레임의 시간 범위 시작을 식별한다. 종료 시간은 시작 시간과 지속 시간에서 추론할 수 있다. time scaleencoding-id가 참조하는 video-encoding-offer 메시지의 time-scale 필드 값과 같다.

duration

존재하는 경우, 비디오 프레임의 지속 시간이다. 존재하지 않는 경우, 지속 시간이 알려지지 않았음을 의미한다. time scaleencoding-id가 참조하는 video-encoding-offer 메시지의 time-scale 필드 값과 같다.

sync-time

존재하는 경우, 이 프레임(따라서 이 인코딩)의 시작 시간을 다른 타임라인에 있는 다른 미디어 인코딩의 시작 시간과 동기화하는 데 사용되는 시간이다.

rotation

존재하는 경우, 프레임을 디코딩한 후 렌더링하기 전에 어떻게 회전해야 하는지를 나타낸다. 회전은 시계 방향이며 90도 단위이다. 기본값은 encoding-id가 참조하는 video-encoding-offer 메시지의 default-rotation 필드와 같다.

payload

인코딩된 비디오 프레임(인코딩된 이미지)이다. 코덱은 encoding-id가 참조하는 video-encoding-offer 메시지의 codec-name 필드와 같다.

8.5. 데이터

미디어 발신자는 다음 키와 값을 가진 data-frame 메시지 (부록 A: 메시지 참조)를 보내 미디어 수신자에게 timed data를 보낼 수 있다. data frame 메시지는 오디오 및 비디오와 동기화될 수 있는 임의의 페이로드를 포함한다. 데이터 타입과 타임라인을 공유하는 일련의 데이터 프레임이 데이터 인코딩을 형성한다.

다음 내용을 QUIC 세부사항에 의존하지 않도록 다시 작성. [Issue #343]

데이터 프레임이 순서와 다르게 전송될 수 있도록, 별도의 QUIC 스트림에서 전송될 수 있지만, 특정 데이터 타입에 대해 그것이 타당하다면 하나의 QUIC 스트림에서 둘 이상의 데이터 프레임을 보낼 수 있다.

encoding-id

이 데이터 프레임이 속한 데이터 인코딩을 식별한다. 이는 데이터 타입 및 time scale과 같은 인코딩의 필드를 참조하는 데 사용할 수 있다. encoding id를 통해 인코딩 필드를 참조하면 모든 프레임에 중복 정보를 보내는 것을 피하는 데 도움이 된다.

sequence-number

인코딩 내의 프레임과 그 순서를 식별한다. 인코딩 내에서 더 큰 sequence number는 더 늦은 start time을 의미한다. 인코딩 내에서 sequence number의 간격은 프레임이 누락되었음을 의미한다.

start-time

데이터 프레임의 시간 범위 시작을 식별한다. 종료 시간은 시작 시간과 지속 시간에서 추론할 수 있다. time scaleencoding-id가 참조하는 data-encoding-offer 메시지의 time-scale 필드 값과 같다.

duration

존재하는 경우, 데이터 프레임의 지속 시간이다. 존재하지 않는 경우, 지속 시간은 encoding-id가 참조하는 data-encoding-offer 메시지의 default-duration 필드와 같다. time scaleencoding-id가 참조하는 data-encoding-offer 메시지의 time-scale 필드 값과 같다.

sync-time

존재하는 경우, 이 데이터 프레임(따라서 이 인코딩)의 시작 시간을 다른 타임라인에 있는 다른 미디어 인코딩의 시작 시간과 동기화하는 데 사용되는 시간이다.

payload

데이터이다. 데이터 타입은 encoding-id가 참조하는 data-encoding-offer 메시지의 data-type-name 필드와 같다.

8.6. 피드백

미디어 수신자는 키 프레임 요청과 같은 피드백을 미디어 발신자에게 보낼 수 있다.

비디오 키 프레임은 다음 키와 값을 가진 video-request 메시지를 보내 요청된다.

다음 내용을 QUIC 세부사항에 의존하지 않도록 다시 작성. [Issue #343]

비디오 프레임이 순서와 다르게 전송될 수 있도록, 별도의 QUIC 스트림에서 전송될 수 있다.

encoding-id

미디어 발신자가 새 키 프레임을 보내야 하는 인코딩이다.

sequence-number

인코딩 내의 순서를 제공한다. 인코딩 내에서 더 큰 sequence number는 이전의 것들을 무효화한다. 미디어 발신자는 더 큰 sequence number가 처리된 후 더 작은 sequence number를 무시할 수 있다. 이는 순서가 뒤바뀐 요청이 필요한 것보다 더 많은 키 프레임을 생성하지 않도록 하기 위한 것이다.

highest-decoded-frame-sequence-number: uint

설정된 경우, 미디어 발신자는 마지막으로 디코딩된 프레임에 의존하는 비디오 프레임을 생성할 수 있다. 설정되지 않은 경우, 미디어 발신자는 독립(키) 프레임을 생성해야 한다.

8.7. 통계

스트리밍 세션 중에, 발신자는 수신자가 요청한 간격으로 streaming-session-sender-stats-event를 사용하여 stats를 보내는 것이 좋다. 자신이 보내는 모든 미디어 스트림에 대해 다음 stats를 모두 보내는 것이 좋다. streaming-session-sender-stats-event 메시지는 다음 필드를 포함한다:

streaming-session-id

이 stats가 적용되는 스트리밍 세션의 ID.

system-time

단조 시스템 clock을 사용하여 stats가 계산된 시간.

audio

오디오에 특화된 stats. 여러 인코딩에 대한 stats를 한 번에 보낼 수 있지만, stats가 변경되지 않았다면 인코딩을 포함할 필요는 없다. 아래를 참조하라.

video

비디오에 특화된 stats. 여러 인코딩에 대한 stats를 한 번에 보낼 수 있지만, stats가 변경되지 않았다면 인코딩을 포함할 필요는 없다. 아래를 참조하라.

오디오 인코딩 발신자 stats는 다음 필드를 포함한다:

encoding-id

stats가 적용되는 인코딩의 ID.

cumulative-sent-frames

전송된 총 프레임 수.

cumulative-encode-delay

전송된 프레임을 인코딩하는 데 소비된 시간의 합.

비디오 인코딩 발신자 stats는 다음 필드를 포함한다:

encoding-id

stats가 적용되는 인코딩의 ID.

cumulative-sent-duration

전송된 모든 오디오 프레임의 모든 지속 시간의 합.

cumulative-encode-delay

전송된 프레임을 인코딩하는 데 소비된 시간의 합.

cumulative-dropped frames

네트워크, CPU 또는 기타 제약으로 인해 전송되지 않은 총 프레임 수.

스트리밍 세션 중에, 수신자는 발신자가 요청한 간격으로 streaming-session-receiver-stats-event를 사용하여 stats를 보내는 것이 좋다. 자신이 수신하는 모든 미디어 스트림에 대해 다음 stats를 모두 보내는 것이 좋다.

수신자가 프레임을 재생하기 전에 보관하기 위해 버퍼를 사용하는 경우, remote-buffer-status 필드를 사용하여 해당 버퍼의 상태도 보내는 것이 좋다. 이는 세 가지 값 중 하나를 가질 수 있다:

insufficient-data 상태를 받은 발신자는 전송 속도를 높이거나, 이후 프레임에 대해 더 효율적인 인코딩으로 전환하는 것이 좋다. too-much-data 상태를 받은 발신자는 전송 속도를 낮추는 것이 좋다.

수신자가 버퍼링 없이 프레임을 즉시 재생하는 경우, 항상 enough-data 버퍼링 상태를 보고하는 것이 좋다.

streaming-session-receiver-stats-event 메시지는 다음 필드를 포함한다:

streaming-session-id

이 stats가 적용되는 스트리밍 세션의 ID.

system-time

단조 시스템 clock을 사용하여 stats가 계산된 시간.

audio

오디오에 특화된 stats. 여러 인코딩에 대한 stats를 한 번에 보낼 수 있지만, stats가 변경되지 않았다면 인코딩을 포함할 필요는 없다. 아래를 참조하라.

video

비디오에 특화된 stats. 여러 인코딩에 대한 stats를 한 번에 보낼 수 있지만, stats가 변경되지 않았다면 인코딩을 포함할 필요는 없다. 아래를 참조하라.

오디오 인코딩 수신자 stats는 다음 필드를 포함한다. 존재하지 않으면 마지막 값 이후 해당 값이 변경되지 않았음을 나타낸다.

encoding-id

stats가 적용되는 인코딩의 ID.

cumulative-decoded-frames

수신 및 디코딩된 총 오디오 프레임 수.

cumulative-received-duration

수신된 모든 오디오 프레임의 모든 지속 시간의 합.

cumulative-lost-duration

손실된 것으로 감지된 모든 오디오 프레임의 모든 지속 시간의 합.

cumulative-buffer-delay

수신과 재생 사이에 프레임이 버퍼링된 시간의 합.

cumulative-decode-delay

수신된 프레임을 디코딩하는 데 소비된 시간의 합.

remote-buffer-status : streaming-buffer-status

이 인코딩에 대한 원격 버퍼의 상태.

비디오 인코딩 수신자 stats는 다음 필드를 포함한다. 존재하지 않으면 마지막 값 이후 해당 값이 변경되지 않았음을 나타낸다.

encoding-id

stats가 적용되는 인코딩의 ID.

cumulative-decoded-frames

수신 및 디코딩된 총 비디오 프레임 수.

cumulative-lost-frames

손실된 것으로 감지된 총 비디오 프레임 수.

cumulative-buffer-delay

수신과 렌더링 사이에 프레임이 버퍼링된 시간의 합.

cumulative-decode-delay

수신된 프레임을 디코딩하는 데 소비된 시간의 합.

remote-buffer-status : streaming-buffer-status

이 인코딩에 대한 원격 버퍼의 상태.

9. 요청, 응답 및 감시

오픈 스크린 프로토콜의 여러 하위 프로토콜에는 요청, 응답, 감시 및 이벤트로 동작하는 메시지가 있다. 대부분의 요청은 request-id를 가지며, 요청을 받은 에이전트는 동일한 request-id를 가진 정확히 하나의 응답 메시지를 반환해야 한다. watch request는 watch-id를 가지며, 요청을 받은 에이전트는 watch request가 만료될 때까지 동일한 watch-id를 가진 임의의 수의 이벤트 메시지를 응답으로 보낼 수 있다.

request-idwatch-id 값은 각 에이전트가 유지하는 카운터에서 할당되는 부호 없는 정수 ID이며, 카운터는 1에서 시작하고 각 ID마다 1씩 증가한다. 에이전트가 자신의 state-token을 변경할 때마다 카운터를 1로 재설정해야 한다.

에이전트가 다른 에이전트가 새 state-token을 광고함으로써 상태를 재설정했음을 알게 되면, 해당 에이전트에 대한 모든 요청, 응답, 감시 및 이벤트를 폐기하는 것이 좋다.

한쪽이 상태를 잃으면 혼란을 일으킬 수 있어 고유해야 하는 다른 ID들, 예를 들어 streaming-session-id, media-session-idencoding-id도 동일하게 취급하는 것이 좋다.

다음 내용을 QUIC 세부사항에 의존하지 않도록 다시 작성. [Issue #343]

Note: request 및 watch ID는 에이전트 간의 특정 QUIC 연결에 묶이지 않는다. QUIC 연결이 닫혀도, 에이전트는 상대방과 관련된 요청, 응답, 감시 또는 이벤트를 폐기하지 않는 것이 좋다. 이를 통해 에이전트는 사용하지 않는 연결을 닫아 전력을 절약할 수 있다.

Note: request 및 watch ID는 에이전트 간에 고유하지 않다. 에이전트는 여러 에이전트에 걸쳐 요청을 추적하기 위해 request ID를 이를 보낸 에이전트의 고유 식별자(예: 인증서 지문)와 결합할 수 있다.

10. 프로토콜 확장

오픈 스크린 프로토콜 에이전트는 이 명세에서 정의하지 않은 확장 메시지를 교환할 수 있다. 이는 실험, 사용자 지정 또는 기타 목적에 사용될 수 있다.

새 확장 메시지를 추가하려면, 확장 작성자는 공개 레지스트리에 메시지 타입 키 범위와 함께 capability ID를 등록해야 한다. 그런 다음 에이전트는 자신의 agent-info 메시지의 capabilities 필드에 해당 capability ID를 포함하여 확장을 수락함을 나타낼 수 있다.

Capability ID 1-999는 오픈 스크린 프로토콜에서 사용하기 위해 예약된다. Capability ID 1000 이상은 확장에 사용할 수 있다. 확장 메시지 타입 키의 적법한 범위는 부록 B: 메시지 타입 키 범위를 참조하라.

Note: 공개 레지스트리의 목적은 여러 확장 작성자의 capability ID 및 메시지 타입 키 간 충돌을 방지하는 것이다.

에이전트는 해당 확장 capability ID를 광고하지 않은 다른 에이전트에게 확장 메시지를 보내서는 안 된다.

Note: 에이전트가 알 수 없는 메시지 타입 키를 처리하는 방법은 § 4 CBOR를 사용한 메시지 전달을 참조하라.

구현을 단순화하고 확장 프로토콜의 표준화로 이어지는 더 쉬운 경로를 제공하기 위해, 확장 메시지도 CBOR로 인코딩하는 것이 권장된다. 그러나 이는 필수는 아니다. 비 CBOR 확장을 지원하는 에이전트는 CBOR 메시지와 비 CBOR 확장 메시지가 혼합된 QUIC 스트림을 디코딩할 수 있어야 한다.

10.1. 프로토콜 확장 필드

에이전트가 오픈 스크린 프로토콜에서 정의한 모든 map-valued CBOR 메시지 타입에 추가 확장 필드를 더하는 것은 허용된다. 확장 필드는 선택적이어야 하며, 오픈 스크린 프로토콜 메시지는 필드가 설정되어 있든 없든 의미가 통해야 한다.

에이전트는 audio-frame 메시지에 확장 필드를 직접 추가해서는 안 된다. 대신, 그 중첩된 optional 값에 추가할 수 있다.

확장 필드는 오픈 스크린 프로토콜 메시지의 정수 키와 충돌을 피하기 위해 문자열 키를 사용하는 것이 좋다. 에이전트는 다른 에이전트가 자신의 agent-info에서 해당 확장 필드를 이해한다는 것을 나타내는 확장 capability ID를 광고하지 않는 한, 그 에이전트에게 확장 필드를 보내지 않는 것이 좋다.

11. 보안 및 개인정보 보호

오픈 스크린 애플리케이션 프로토콜은 두 OSP 에이전트가 사용자 및 애플리케이션 데이터를 교환할 수 있게 한다. 따라서 보안 및 개인정보 보호 고려사항은 면밀히 검토되어야 한다. 먼저 W3C 보안 및 개인정보 보호 설문지를 사용하여 프로토콜 자체를 평가한다. 그런 다음 Presentation APIRemote Playback API에서 권장하는 보안 및 개인정보 보호 지침이 충족되는지 검토한다. 마지막으로 이러한 보안 및 개인정보 보호 요구사항을 충족하기 위해 에이전트가 사용할 수 있는 권장 완화책을 논의한다.

11.1. 위협 모델

11.1.1. 동일 출처 정책 위반

Presentation API는 각 출처의 동의(API 사용을 통해)를 바탕으로 제어 페이지와 프레젠테이션 사이의 교차 출처 통신을 허용한다. 이는 targetOrigin*postMessage()를 통한 교차 출처 통신과 유사하다. 그러나 Presentation API는 각 메시지에 소스 출처 정보를 전달하지 않는다. 따라서 오픈 스크린 프로토콜은 에이전트 간에 출처 정보를 전달하지 않는다.

프레젠테이션 식별자는 제한 없는 교차 출처 접근에 대해 어느 정도 보호를 제공한다. 그러나 PresentationConnection으로 연결된 당사자에 대한 엄격한 인증은 애플리케이션 수준에서 수행되어야 한다.

11.2. 오픈 스크린 애플리케이션 프로토콜 보안 및 개인정보 보호 고려사항

11.2.1. 개인 식별 정보 및 고가치 데이터

프로토콜에서 교환되는 다음 데이터는 개인 식별 가능 데이터 및/또는 고가치 데이터일 수 있다:

  1. 프레젠테이션 URL 및 사용 가능성 결과

  2. 프레젠테이션 식별자

  3. 프레젠테이션 연결 ID

  4. 프레젠테이션 연결 메시지

  5. 원격 재생 URL

  6. 원격 재생 명령 및 상태 메시지

프레젠테이션 식별자는 프레젠테이션 URL과 함께 실행 중인 프레젠테이션에 연결하는 데 사용될 수 있으므로 고가치 데이터로 간주된다.

agent-info를 통해 제공되는 데이터는 합리적으로 기밀로 만들 수 없으며, 공개 데이터로 간주하는 것이 좋다:

이 데이터는 개인 식별 가능 데이터로 간주되지는 않지만, 공격자가 이를 변경하거나 다른 값으로 대체하는 것을 막기 위해 보호하는 것이 중요하다.

11.2.2. 교차 출처 상태 고려사항

이전 세션에서 시작된 프레젠테이션에 다시 연결함으로써, Presentation API를 통해 브라우징 세션 간 출처 상태에 접근할 수 있다. 이 시나리오는 Presentation API § 7.2 교차 출처 접근에서 다루어진다.

수신자 사용 가능성은 사용자의 네트워크 컨텍스트에 따라 교차 출처에서 사용할 수 있다. 이 데이터가 Web에 노출되는 문제도 Presentation API § 7.1 개인 식별 정보Remote Playback API § 6.1 개인 식별 정보에서 논의된다.

11.2.3. 다른 장치에 대한 출처 접근

설계상 오픈 스크린 프로토콜은 Web에서 수신자에 접근할 수 있게 한다. 이 프로토콜을 구현함으로써 이러한 장치는 자신을 Web에 의도적으로 노출하는 것이며, 그에 맞게 설계되는 것이 좋다.

아래에서는 이러한 장치의 악의적 사용을 방지하기 위한 완화 단계를 논의한다.

11.2.4. 비공개 브라우징 모드

오픈 스크린 프로토콜 자체는 사용자 에이전트의 일반 브라우징 모드와 비공개 브라우징 모드를 구분하지 않는다.

일반적인 전송 요구사항을 반영하도록 갱신. [Issue #342]

그러나 사용자 에이전트는 동일한 사용자 에이전트 인스턴스에서 일반 브라우징과 비공개 브라우징에 대해 별도의 인증 컨텍스트 및 QUIC 연결을 사용하는 것이 권장된다. 이는 OSP 에이전트가 동일한 사용자의 일반 브라우징과 비공개 브라우징에서 발생하는 활동을 서로 연결하기 어렵게 만든다.

11.2.5. 지속 상태

에이전트는 이전에 연결했던 에이전트의 신원을 agent-info 메시지 또는 다른 애플리케이션 메시지에서 지속적으로 저장할 가능성이 있다.

그러나 이 데이터는 일반적으로 Web에 노출되지 않으며, 디스플레이 선택 또는 디스플레이 인증 과정 중 사용자 에이전트의 네이티브 UI를 통해서만 노출된다. 사용자가 브라우징 데이터를 지울 때 사용자 에이전트가 이 데이터를 지울지 유지할지는 구현 선택일 수 있다.

11.2.6. 기타 고려사항

오픈 스크린 프로토콜은 Web에 다음에 대한 추가 접근 권한을 부여하지 않는다:

11.3. Presentation API 고려사항

Presentation API § 7 보안 및 개인정보 보호 고려사항은 오픈 스크린 프로토콜에 다음 요구사항을 둔다:

  1. 프레젠테이션 URL 및 프레젠테이션 식별자는 교차 출처 접근 지침에 따라 프레젠테이션에 연결할 수 있도록 허용된 당사자 사이에서 비공개로 유지되는 것이 좋다.

  2. 사용자 인터페이스 지침에 따라 여러 사용자 에이전트 프로필을 나타내는 연결이 프레젠테이션에 만들어졌을 때 컨트롤러와 수신자에게 알리는 것이 좋다.

  3. 프레젠테이션 연결 간 메시징 지침에 따라 컨트롤러와 수신자 사이의 메시징은 인증되고 기밀로 유지되는 것이 좋다.

일반적인 전송 요구사항을 반영하도록 갱신. [Issue #342]

오픈 스크린 프로토콜은 다음 방식으로 이러한 고려사항을 다룬다:

  1. 프레젠테이션 URL, ID 또는 메시지가 교환되기 전에 상호 인증과 TLS로 보호되는 QUIC 연결을 요구한다.

  2. 개별 PresentationConnections에 대해 명시적 메시지와 연결 ID를 추가하여, 에이전트가 활성 연결 수를 추적할 수 있게 한다.

11.4. Remote Playback API 고려사항

Remote Playback API § 6 보안 및 개인정보 보호 고려사항도 컨트롤러와 수신자 사이의 메시징이 인증되고 기밀로 유지되는 것이 좋다고 명시한다.

일반적인 전송 요구사항을 반영하도록 갱신. [Issue #342]

이 고려사항은 원격 재생 관련 메시지가 교환되기 전에 상호 인증과 TLS로 보호되는 QUIC 연결을 요구함으로써 처리된다.

11.5. 완화 전략

11.5.1. 악의적 입력

OSP 에이전트는 파싱 취약점을 악용하여 대상 장치를 손상시키려는 악의적 입력에 대해 견고한 것이 좋다.

CBOR는 JSON 및 XML 같은 대안에 비해 이러한 공격에 덜 취약하도록 의도되었다. 그래도 에이전트는 퍼즈 테스트와 같은 접근법을 사용해 철저히 테스트되는 것이 좋다.

가능한 경우, OSP 에이전트(콘텐츠 렌더링 구성요소 포함)는 취약점이 사용자 데이터에 접근하거나 지속적 악용으로 이어지는 것을 방지하기 위해 샌드박싱과 같은 심층 방어 기법을 사용하는 것이 좋다.

11.6. 사용자 인터페이스 고려사항

이 명세는 OSP 에이전트의 보안 관련 사용자 인터페이스에 대해 특정 요구사항을 두지 않는다. 그러나 에이전트가 다른 에이전트를 인증하기 전에는, 해당 에이전트의 agent-info 또는 기타 데이터가 인증을 통해 검증되지 않았음을 사용자 인터페이스가 명확히 하는 것이 좋다.

11.6.1. 인스턴스 및 표시 이름

일반적인 발견 요구사항을 반영하도록 갱신. [Issue #342]

DNS-SD Instance Names는 인증 전에 사용자가 보는 주된 정보이므로, 이러한 이름을 신중하게 표시해야 한다.

에이전트는 Instance Names를 검증되지 않은 정보로 취급해야 하며, 성공적인 QUIC 연결 후 agent-info 메시지를 통해 받은 표시 이름의 접두사인지 확인하는 것이 좋다. 에이전트가 이 확인을 수행하면, 그 이름을 검증된 표시 이름으로 표시할 수 있다.

에이전트는 DNS-SD의 잘린 표시 이름 대신, 완전한 표시 이름만 사용자에게 표시하는 것이 좋다. 잘린 표시 이름은 전체 이름으로 검증된 표시 이름으로 표시되기 전에 위와 같이 검증되는 것이 좋다.

이는 에이전트가 처리할 수 있어야 하는 표시 이름의 범주가 세 가지임을 의미한다:
  1. 잘렸고 검증되지 않은 DNS-SD Instance Names. 사용자에게 표시하지 않는 것이 좋다.
  2. 완전하지만 검증되지 않은 DNS-SD Instance Names. 인증 전에 검증되지 않은 것으로 표시할 수 있다.
  3. 검증된 표시 이름.

부록 A: 메시지

다음 메시지는 Concise Data Definition Language 문법을 사용하여 정의된다. 정수 키가 사용되는 경우, 필드의 이름을 나타내기 위해 해당 줄에 주석이 추가된다. 이 명세의 객체 정의는 wire 상의 바이트 수를 줄이면서 각 키에 대해 사람이 읽을 수 있는 이름을 유지하기 위해 이와 같은 특이한 문법을 가진다. 선택적 필드의 쉬운 인덱싱을 허용하기 위해 객체 배열 대신 정수 키가 사용된다.

각 루트 메시지(다른 메시지에 포함되지 않고 QUIC 스트림에 넣을 수 있는 메시지)는 메시지 타입 키를 나타내는 주석을 가진다.

더 작은 숫자는 더 자주 전송되거나 매우 작거나 둘 다인 메시지에 예약하는 것이 좋고, 더 큰 숫자는 드물게 전송되거나 크거나 둘 다인 메시지에 예약하는 것이 좋다. 더 작은 타입 키는 wire 상에서 더 작게 인코딩되기 때문이다.

; type key 10
agent-info-request = {
  request
}

; type key 11
agent-info-response = {
  response
  1: agent-info ; agent-info
}

; type key 120
agent-info-event = {
  0: agent-info ; agent-info
}

agent-capability = &(
  receive-audio: 1
  receive-video: 2
  receive-presentation: 3
  control-presentation: 4
  receive-remote-playback: 5
  control-remote-playback: 6
  receive-streaming: 7
  send-streaming: 8
)

agent-info = {
  0: text ; display-name
  1: text ; model-name
  2: [* agent-capability] ; capabilities
  3: text ; state-token
  4: [* text] ; locales
}

; type key 12
agent-status-request = {
  request
  ? 1: status ; status
}

; type key 13
agent-status-response = {
  response
  ? 1: status ; status
}

status = {
  0: text ; status
}

request = (
  0: request-id ; request-id
)

response = (
  0: request-id ; request-id
)

request-id = uint

microseconds = uint

epoch-time = int

media-timeline = float64

media-timeline-range = [
  start: media-timeline
  end: media-timeline
]

watch-id = uint

; type key 14
presentation-url-availability-request = {
  request
  1: [1* text] ; urls
  2: microseconds ; watch-duration
  3: watch-id ; watch-id
}

; type key 15
presentation-url-availability-response = {
  response
  1: [1* url-availability] ; url-availabilities
}

; type key 103
presentation-url-availability-event = {
  0: watch-id ; watch-id
  1: [1* url-availability] ; url-availabilities
}

; idea: use HTTP response codes?
url-availability = &(
  available: 0
  unavailable: 1
  invalid: 10
)

; type key 104
presentation-start-request = {
  request
  1: text ; presentation-id
  2: text ; url
  3: [* http-header] ; headers
}

http-header = [
  key: text
  value: text
]

; type key 105
presentation-start-response = {
  response
  1: &result ; result
  2: uint ; connection-id
  ? 3: uint ; http-response-code
}

presentation-termination-source = &(
  controller: 1
  receiver: 2
  unknown: 255
)

presentation-termination-reason = &(
  application-request: 1
  user-request: 2
  receiver-replaced-presentation: 20
  receiver-idle-too-long: 30
  receiver-attempted-to-navigate: 31
  receiver-powering-down: 100
  receiver-error: 101
  unknown: 255
)

; type key 106
presentation-termination-request = {
  request
  1: text ; presentation-id
  2: presentation-termination-reason ; reason
}

; type key 107
presentation-termination-response = {
  response
  1: &result ; result
}

; type key 108
presentation-termination-event = {
  0: text ; presentation-id
  1: presentation-termination-source ; source
  2: presentation-termination-reason ; reason
}

; type key 109
presentation-connection-open-request = {
  request
  1: text ; presentation-id
  2: text ; url
}

; type key 110
presentation-connection-open-response = {
  response
  1: &result ; result
  2: uint ; connection-id
  3: uint ; connection-count
}

; type key 113
presentation-connection-close-event = {
  0: uint ; connection-id
  1: &(
    close-method-called: 1
    connection-object-discarded: 10
    unrecoverable-error-while-sending-or-receiving-message: 100
  ) ; reason
  ? 2: text ; error-message
  3: uint ; connection-count
}

; type key 121
presentation-change-event = {
  0: text ; presentation-id
  1: uint ; connection-count
}

; type key 16
presentation-connection-message = {
  0: uint ; connection-id
  1: bytes / text ; message
}

result = (
  success: 1
  invalid-url: 10
  invalid-presentation-id: 11
  timeout: 100
  transient-error: 101
  permanent-error: 102
  terminating: 103
  unknown-error: 199
)

; type key 17
remote-playback-availability-request = {
  request
  1: [* remote-playback-source] ; sources
  2: microseconds ; watch-duration
  3: watch-id ; watch-id
}

; type key 18
remote-playback-availability-response = {
  response
  1: [* url-availability] ; url-availabilities
}

; type key 114
remote-playback-availability-event = {
  0: watch-id ; watch-id
  1: [* url-availability] ; url-availabilities
}

; type key 115
remote-playback-start-request = {
  request
  1: remote-playback-id ; remote-playback-id
  ? 2: [* remote-playback-source] ; sources
  ? 3: [* text] ; text-track-urls
  ? 4: [* http-header] ; headers
  ? 5: remote-playback-controls ; controls
  ? 6: {streaming-session-start-request-params} ; remoting
}

remote-playback-source = {
  0: text; url
  1: text; extended-mime-type
}

; type key 116
remote-playback-start-response = {
  response
  ? 1: remote-playback-state ; state
  ? 2: {streaming-session-start-response-params} ; remoting
}

; type key 117
remote-playback-termination-request = {
  request
  1: remote-playback-id ; remote-playback-id
  2: &(
    user-terminated-via-controller: 11
    unknown: 255
  ) ; reason
}

; type key 118
remote-playback-termination-response = {
  response
  1: &result ; result
}

; type key 119
remote-playback-termination-event = {
  0: remote-playback-id ; remote-playback-id
  1: &(
    receiver-called-terminate: 1
    user-terminated-via-receiver: 2
    receiver-idle-too-long: 30
    receiver-powering-down: 100
    receiver-crashed: 101
    unknown: 255
  ) ; reason
}

; type key 19
remote-playback-modify-request = {
  request
  1: remote-playback-id ; remote-playback-id
  2: remote-playback-controls ; controls
}

; type key 20
remote-playback-modify-response = {
  response
  1: &result ; result
  ? 2: remote-playback-state ; state
}

; type key 21
remote-playback-state-event = {
  0: remote-playback-id ; remote-playback-id
  1: remote-playback-state ; state
}

remote-playback-id = uint

remote-playback-controls = {
  ? 0: remote-playback-source ; source
  ? 1: &(
    none: 0
    metadata: 1
    auto: 2
  ) ; preload
  ? 2: bool ; loop
  ? 3: bool ; paused
  ? 4: bool ; muted
  ? 5: float64 ; volume
  ? 6: media-timeline ; seek
  ? 7: media-timeline ; fast-seek
  ? 8: float64 ; playback-rate
  ? 9: text ; poster
  ? 10: [* text] ; enabled-audio-track-ids
  ? 11: text ; selected-video-track-id
  ? 12: [* added-text-track] ; added-text-tracks
  ? 13: [* changed-text-track] ; changed-text-tracks
}

remote-playback-state = {
  ? 0: {
    0: bool ; rate
    1: bool ; preload
    2: bool ; poster
    3: bool ; added-text-track
    4: bool ; added-cues
  } ; supports
  ? 1: remote-playback-source ; source
  ? 2: &(
    empty: 0
    idle: 1
    loading: 2
    no-source: 3
  ) ; loading
  ? 3: &(
    nothing: 0
    metadata: 1
    current: 2
    future: 3
    enough: 4
  ) ; loaded
  ? 4: media-error ; error
  ? 5: epoch-time / null ; epoch
  ? 6: media-timeline / null ; duration
  ? 7: [* media-timeline-range] ; buffered-time-ranges
  ? 8: [* media-timeline-range] ; seekable-time-ranges
  ? 9: [* media-timeline-range] ; played-time-ranges
  ? 10: media-timeline ; position
  ? 11: float64 ; playbackRate
  ? 12: bool ; paused
  ? 13: bool ; seeking
  ? 14: bool ; stalled
  ? 15: bool ; ended
  ? 16: float64 ; volume
  ? 17: bool ; muted
  ? 18: video-resolution / null ; resolution
  ? 19: [* audio-track-state] ; audio-tracks
  ? 20: [* video-track-state] ; video-tracks
  ? 21: [* text-track-state] ; text-tracks
}

added-text-track = {
  0: &(
    subtitles: 1
    captions: 2
    descriptions: 3
    chapters: 4
    metadata: 5
  ) ; kind
  ? 1: text ; label
  ? 2: text ; language
}

changed-text-track = {
  0: text ; id
  1: text-track-mode ; mode
  ? 2: [* text-track-cue] ; added-cues
  ? 3: [* text] ; removed-cue-ids
}

text-track-mode = &(
  disabled: 1
  showing: 2
  hidden: 3
)

text-track-cue = {
  0: text ; id
  1: media-timeline-range ; range
  2: text ; text
}

media-sync-time = [
  value: uint
  scale: uint
]

media-error = [
  code: &(
    user-aborted: 1
    network-error: 2
    decode-error: 3
    source-not-supported: 4
    unknown-error: 5
  )
  message: text
]

track-state = (
  0: text ; id
  1: text ; label
  2: text ; language
)

audio-track-state = {
  track-state
  3: bool ; enabled
}

video-track-state = {
  track-state
  3: bool ; selected
}

text-track-state = {
  track-state
  3: text-track-mode ; mode
}

; type key 22
audio-frame = [
  encoding-id: uint
  start-time: uint
  payload: bytes
  ? optional: {
    ? 0: uint ; duration
    ? 1: media-sync-time ; sync-time
  }
]

; type key 23
video-frame = {
  0: uint ; encoding-id
  1: uint ; sequence-number
  ? 2: [* int] ; depends-on
  3: uint ; start-time
  ? 4: uint ; duration
  5: bytes ; payload
  ? 6: uint ; video-rotation
  ? 7: media-sync-time ; sync-time
}

; type key 24
data-frame = {
  0: uint ; encoding-id
  ? 1: uint ; sequence-number
  ? 2: uint ; start-time
  ? 3: uint ; duration
  4: bytes ; payload
  ? 5: media-sync-time ; sync-time
}

ratio = [
  antecedent: uint
  consequent: uint
]

; type key 122
streaming-capabilities-request = {
  request
}

; type key 123
streaming-capabilities-response = {
  response
  1: streaming-capabilities ; streaming-capabilities
}

streaming-capabilities = {
  0: [* receive-audio-capability] ; receive-audio
  1: [* receive-video-capability] ; receive-video
  2: [* receive-data-capability] ; receive-data
}

format = {
  0: text ; codec-name
}

receive-audio-capability = {
  0: format ; codec
  ? 1: uint ; max-audio-channels
  ? 2: uint ; min-bit-rate
}

video-resolution = {
  0: uint ; height
  1: uint ; width
}

video-hdr-format = {
  0: text; transfer-function
  ? 1: text; hdr-metadata
}

receive-video-capability = {
  0: format ; codec
  ? 1: video-resolution ; max-resolution
  ? 2: ratio ; max-frames-per-second
  ? 3: uint ; max-pixels-per-second
  ? 4: uint ; min-bit-rate
  ? 5: ratio ; aspect-ratio
  ? 6: text ; color-gamut
  ? 7: [* video-resolution] ; native-resolutions
  ? 8: bool ; supports-scaling
  ? 9: bool ; supports-rotation
  ? 10: [* video-hdr-format] ; hdr-formats
}

receive-data-capability = {
  0: format ; data-type
}

; type key 124
streaming-session-start-request = {
  request
  streaming-session-start-request-params
}

; type key 125
streaming-session-start-response = {
  response
  streaming-session-start-response-params
}

; A separate group so it can be used in remote-playback-start-request
streaming-session-start-request-params = (
  1: uint ; streaming-session-id
  2: [* media-stream-offer] ;  stream-offers
  3: microseconds ; desired-stats-interval
)

; type key 126
streaming-session-modify-request = {
  request
  streaming-session-modify-request-params
}

; A separate group so it can be used in remote-playback-start-response
streaming-session-start-response-params = (
  1: &result ; result
  2: [* media-stream-request] ; stream-requests
  3: microseconds ; desired-stats-interval  
)

streaming-session-modify-request-params = (
  1: uint ; streaming-session-id
  2: [* media-stream-request] ; stream-requests
)

; type key 127
streaming-session-modify-response = {
  response
  1: &result ; result
}

; type key 128
streaming-session-terminate-request = {
  request
  1: uint ; streaming-session-id
}

; type key 129
streaming-session-terminate-response = {
  response
}

; type key 130
streaming-session-terminate-event = {
  0: uint ; streaming-session-id
}

media-stream-offer = {
  0: uint ; media-stream-id
  ? 1: text ; display-name
  ? 2: [1* audio-encoding-offer] ; audio
  ? 3: [1* video-encoding-offer] ; video
  ? 4: [1* data-encoding-offer] ; data
}

media-stream-request = {
  0: uint ; media-stream-id
  ? 1: audio-encoding-request ; audio
  ? 2: video-encoding-request ; video
  ? 3: data-encoding-request ; data
}

audio-encoding-offer = {
  0: uint ; encoding-id
  1: text ; codec-name
  2: uint ; time-scale
  ? 3: uint ; default-duration
}

video-encoding-offer = {
  0: uint ; encoding-id
  1: text ; codec-name
  2: uint ; time-scale
  ? 3: uint ; default-duration
  ? 4: video-rotation ; default-rotation
}

data-encoding-offer = {
  0: uint ; encoding-id
  1: text ; data-type-name
  2: uint ; time-scale
  ? 3: uint ; default-duration
}

audio-encoding-request = {
  0: uint ; encoding-id
}

video-encoding-request = {
  0: uint ; encoding-id
  ? 1: video-resolution ; target-resolution
  ? 2: ratio ; max-frames-per-second
}

data-encoding-request = {
  0: uint ; encoding-id
}

video-rotation = &(
  ; Degrees clockwise
  video-rotation-0: 0
  video-rotation-90: 1
  video-rotation-180: 2
  video-rotation-270: 3
)

sender-stats-audio = {
  0: uint ; encoding-id
  ? 1: uint ; cumulative-sent-frames
  ? 2: microseconds ; cumulative-encode-delay
}

sender-stats-video = {
  0: uint ; encoding-id
  ? 1: microseconds ; cumulative-sent-duration
  ? 2: microseconds ; cumulative-encode-delay
  ? 3: uint ; cumulative-dropped-frames
}

; type key 131
streaming-session-sender-stats-event = {
  0: uint; streaming-session-id
  1: microseconds ; system-time
  ? 2: [1* sender-stats-audio] ; audio
  ? 3: [1* sender-stats-video] ; video
}

streaming-buffer-status = &(
  enough-data: 0
  insufficient-data: 1
  too-much-data: 2
)

receiver-stats-audio = {
  0: uint ; encoding-id
  ? 1: microseconds ; cumulative-received-duration
  ? 2: microseconds ; cumulative-lost-duration
  ? 3: microseconds ; cumulative-buffer-delay
  ? 4: microseconds ; cumulative-decode-delay
  ? 5: streaming-buffer-status ; remote-buffer-status
}

receiver-stats-video = {
  0: uint ; encoding-id
  ? 1: uint ; cumulative-decoded-frames
  ? 2: uint ; cumulative-lost-frames
  ? 3: microseconds ; cumulative-buffer-delay
  ? 4: microseconds ; cumulative-decode-delay
  ? 5: streaming-buffer-status ; remote-buffer-status
}

; type key 132
streaming-session-receiver-stats-event = {
  0: uint; streaming-session-id
  1: microseconds ; system-time
  ? 2: [1* receiver-stats-audio] ; audio
  ? 3: [1* receiver-stats-video] ; video
}

부록 B: 메시지 타입 키 범위

다음 부록은 메시지 타입 키의 범위가 어떻게 나뉘는지 설명한다. 유효한 값은 1부터 264까지이다.

각 타입 키는 wire에서 1, 2, 4 또는 8바이트의 가변 길이 정수로 인코딩된다. 각 wire 바이트 크기마다, 키의 1/4에서 1/2까지가 확장에 사용할 수 있다.

바이트 범위 목적
1 1 - 48 오픈 스크린 프로토콜
1 49 - 63 확장에 사용 가능
2 64 - 8,192 오픈 스크린 프로토콜
2 8,193 - 16,383 확장에 사용 가능
4 16,384 - 229 향후 사용을 위해 예약됨
4 229+1 - 230-1 확장에 사용 가능
8 >= 230 향후 사용을 위해 예약됨

부록 C: 미디어 시간 변환

주어진 오디오 또는 비디오 프레임의 미디어 동기화 타임스탬프와 미디어 타임라인 값 사이를 변환하려면, 다음 공식을 사용할 수 있다:

media-timeline-value = media-zero-time + (value / scale)

여기서:

media-timeline-value에서 오버플로가 발생하는 경우, 표현 가능한 최댓값을 사용하는 것이 좋다.

적합성

문서 규약

적합성 요구사항은 설명적 주장과 RFC 2119 용어의 조합으로 표현된다. 이 문서의 규범적 부분에서 사용되는 핵심 단어 “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY” 및 “OPTIONAL”은 RFC 2119에 설명된 대로 해석되어야 한다. 그러나 가독성을 위해, 이 명세에서는 이러한 단어가 모두 대문자로 표시되지는 않는다.

이 명세의 모든 텍스트는 명시적으로 비규범으로 표시된 절, 예제 및 노트를 제외하고 규범적이다. [RFC2119]

이 명세의 예제는 “for example”이라는 단어로 도입되거나, 다음과 같이 class="example"을 사용하여 규범적 텍스트와 구분된다:

이는 정보성 예제의 예이다.

정보성 노트는 “Note”라는 단어로 시작하며, 다음과 같이 class="note"를 사용하여 규범적 텍스트와 구분된다:

Note, 이는 정보성 노트이다.

적합한 알고리즘

알고리즘의 일부로 명령형으로 표현된 요구사항 (예: "선행 공백 문자를 모두 제거한다" 또는 "false를 반환하고 이 단계를 중단한다")은 알고리즘을 도입할 때 사용된 핵심 단어 ("must", "should", "may" 등)의 의미로 해석되어야 한다.

알고리즘 또는 특정 단계로 표현된 적합성 요구사항은 최종 결과가 동등하기만 하면 어떤 방식으로든 구현될 수 있다. 특히, 이 명세에서 정의한 알고리즘은 이해하기 쉽도록 의도된 것이며 성능을 의도한 것은 아니다. 구현자는 최적화하는 것이 권장된다.

색인

이 명세가 정의하는 용어

참조로 정의된 용어

참조

규범적 참조

[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[MEDIA-CAPABILITIES]
Jean-Yves Avenard; Mark Foltz. Media Capabilities. 2026년 2월 10일. WD. URL: https://www.w3.org/TR/media-capabilities/
[PRESENTATION-API]
Mark Foltz. Presentation API. 2025년 2월 12일. CRD. URL: https://www.w3.org/TR/presentation-api/
[REMOTE-PLAYBACK]
Mark Foltz. Remote Playback API. 2024년 4월 30일. CRD. URL: https://www.w3.org/TR/remote-playback/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. 1997년 3월. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[RFC5646]
A. Phillips, Ed.; M. Davis, Ed.. Tags for Identifying Languages. 2009년 9월. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc5646
[RFC6381]
R. Gellens; D. Singer; P. Frojdh. The 'Codecs' and 'Profiles' Parameters for "Bucket" Media Types. 2011년 8월. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc6381
[RFC8610]
H. Birkholz; C. Vigano; C. Bormann. Concise Data Definition Language (CDDL): A Notational Convention to Express Concise Binary Object Representation (CBOR) and JSON Data Structures. 2019년 6월. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc8610
[RFC8949]
C. Bormann; P. Hoffman. Concise Binary Object Representation (CBOR). 2020년 12월. Internet Standard. URL: https://www.rfc-editor.org/rfc/rfc8949
[RFC9000]
J. Iyengar, Ed.; M. Thomson, Ed.. QUIC: A UDP-Based Multiplexed and Secure Transport. 2021년 5월. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc9000

정보성 참조

[IEEE-754]
IEEE Standard for Floating-Point Arithmetic. 2019년 7월 22일. URL: https://ieeexplore.ieee.org/document/8766229
[ITU-R-BT.1359-1]
ITU-R BT.1359-1, Relative Timing of Sound and Vision for Broadcasting. Recommendation. URL: https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.1359-1-199811-I!!PDF-E.pdf
[RFC4122]
P. Leach; M. Mealling; R. Salz. A Universally Unique IDentifier (UUID) URN Namespace. 2005년 7월. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc4122
[SECURITY-PRIVACY-QUESTIONNAIRE]
Theresa O'Connor; Peter Snyder; Simone Onofri. Self-Review Questionnaire: Security and Privacy. 2025년 4월 18일. NOTE. URL: https://www.w3.org/TR/security-privacy-questionnaire/
[WEBCODECS-CODEC-REGISTRY]
Paul Adenot; Bernard Aboba. WebCodecs Codec Registry. 2024년 9월 9일. DRY. URL: https://www.w3.org/TR/webcodecs-codec-registry/

이슈 색인

발견 요구사항 정의 [Issue #342]
전송 계층 요구사항 정의 [Issue #342]
QUIC에 의존하지 않도록 다시 작성하거나 agent-status messges를 네트워크 명세로 이동 [Issue #343]
QUIC에 의존하지 않도록 다시 작성 [Issue #343]
절전을 전송 요구사항으로 추가하고 다음 내용을 제거. [Issue #342]
다음 NOTE를 모든 메시지 전송에 대한 전송 요구사항으로 다시 작성. [Issue #342]
절전을 전송 요구사항으로 추가하고 다음 내용을 제거. [Issue #342]
다음 내용을 QUIC 세부사항에 의존하지 않도록 다시 작성. [Issue #343]
다음 내용을 QUIC 세부사항에 의존하지 않도록 다시 작성. [Issue #343]
다음 내용을 QUIC 세부사항에 의존하지 않도록 다시 작성. [Issue #343]
다음 내용을 QUIC 세부사항에 의존하지 않도록 다시 작성. [Issue #343]
다음 내용을 QUIC 세부사항에 의존하지 않도록 다시 작성. [Issue #343]
일반적인 전송 요구사항을 반영하도록 갱신. [Issue #342]
일반적인 전송 요구사항을 반영하도록 갱신. [Issue #342]
일반적인 전송 요구사항을 반영하도록 갱신. [Issue #342]
일반적인 발견 요구사항을 반영하도록 갱신. [Issue #342]