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 요구사항
-
컨트롤러는 수신자가 특정 프레젠테이션 요청 URL을 렌더링할 수 있는 합리적인 능력이 있는지 확인할 수 있어야 한다.
-
컨트롤러는 프레젠테이션 요청 URL과 프레젠테이션 식별자가 주어졌을 때, 수신자에서 새로운 프레젠테이션을 시작할 수 있어야 한다.
-
컨트롤러는 수신자에 있는 기존 프레젠테이션에 대해, 그 프레젠테이션 요청 URL과 프레젠테이션 식별자가 주어졌을 때, 새로운
PresentationConnection을 만들 수 있어야 한다. -
컨트롤러와 프레젠테이션 사이의
PresentationConnection을 닫고, 연결이 닫힌 이유를 양쪽에 신호로 알릴 수 있어야 한다. -
여러 컨트롤러가 하나의 프레젠테이션에 동시에 연결할 수 있어야 한다.
-
컨트롤러가 보낸 메시지는 신뢰할 수 있고 순서가 보장되는 방식으로 프레젠테이션에 전달되어야 한다(또는 그 반대 방향도 마찬가지이다).
-
메시지를 전달할 수 없는 경우, 컨트롤러는 연결을
error이유로 닫아야 함을 수신자에게 신호로 알릴 수 있어야 한다 (또는 그 반대 방향도 마찬가지이다). -
컨트롤러와 프레젠테이션은
DOMString메시지 (ECMAScript에서string타입으로 표현됨)를 보내고 받을 수 있어야 한다. -
컨트롤러와 프레젠테이션은 바이너리 메시지 (HTML5의
Blob객체 또는 ECMAScript의ArrayBuffer나ArrayBufferView타입으로 표현됨)를 보내고 받을 수 있어야 한다. -
컨트롤러는 프레젠테이션 요청 URL과 프레젠테이션 식별자가 주어졌을 때, 수신자에게 프레젠테이션을 종료하도록 신호를 보낼 수 있어야 한다.
-
수신자는 프레젠테이션이 종료될 때 연결된 모든 컨트롤러에게 신호를 보낼 수 있어야 한다.
2.4. Remote Playback API 요구사항
-
컨트롤러는 주어진
HTMLMediaElement에 대해 호환 가능한 수신자가 하나 이상 있는지를 즉시 및 지속적으로 확인할 수 있어야 한다. -
컨트롤러는
HTMLMediaElement의 원격 재생을 시작하여 호환 가능한 수신자로 보낼 수 있어야 한다. -
컨트롤러는
HTMLMediaElement에서 미디어 소스를 URL로, 그리고 텍스트 트랙을 호환 가능한 수신자로 보낼 수 있어야 한다. -
컨트롤러는
HTMLMediaElement에서 미디어 데이터를 호환 가능한 수신자로 보낼 수 있어야 한다. -
원격 재생 중에, 컨트롤러와 원격 재생 장치는
HTMLMediaElement의 미디어 요소 상태를 동기화할 수 있어야 한다. -
원격 재생 중에, 컨트롤러 또는 수신자 중 어느 한쪽은 상대방과의 연결을 끊을 수 있어야 한다.
-
컨트롤러는 원격 재생 중 텍스트 렌더링을 돕기 위해 로케일 및 텍스트 방향 정보를 수신자에게 전달할 수 있는 것이 좋다.
2.5. 비기능 요구사항
-
저가형 스마트폰, 스마트 TV 또는 스트리밍 장치에서 볼 수 있는 것과 유사한 제한된 하드웨어 요구사항으로 OSP 에이전트를 구현할 수 있어야 한다. 에이전트 하드웨어 사양은 장치 사양 문서를 참조하라.
-
프로토콜 작업이 실패할 때 에이전트는 사용자에게 합리적인 정보를 제공하는 것이 좋다. 예를 들어, 컨트롤러가 프레젠테이션을 시작할 수 없는 경우, 그것이 네트워크 오류인지, 인증 오류인지, 또는 프레젠테이션 콘텐츠 로드 실패인지 컨트롤러 인터페이스에서 보고할 수 있어야 한다.
-
에이전트 간 메시지 지연은 상호작용적 사용을 허용하도록 최소화하는 것이 좋다. 예를 들어, 한 에이전트의 폼에 입력한 텍스트가 실시간으로 프레젠테이션에 표시되는 것이 편안해야 한다. 게임이나 마우스 사용을 위한 실시간 지연은 이상적이지만 요구사항은 아니다.
-
프레젠테이션 또는 원격 재생을 시작하는 컨트롤러는 수신자가 해당 로케일로 콘텐츠를 렌더링할 수 있도록 선호 로케일을 수신자에게 전달하는 것이 좋다.
-
기본 API의 실험과 향상을 촉진하기 위해, 명세에서 명시적으로 정의하지 않은 선택적 기능으로 애플리케이션 프로토콜을 확장할 수 있어야 한다.
3. 메타데이터 발견
추가 메타데이터를 알아내기 위해, 에이전트는 agent-info-request 메시지를 보내고 agent-info-response 메시지를 되돌려 받을 수 있다. 어떤 에이전트든 다른 장치의 상태와 기능을 알아내기 위해 언제든지 이 요청을 보낼 수 있으며, 이러한 상태와 기능은 agent-info-response의 agent-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-info와 agent-status-response 메시지는 § 10.1 프로토콜 확장 필드에 설명된 것처럼 이 명세에서 정의하지 않은 추가 정보를 포함하도록 확장될 수 있다.
4. CBOR를 사용한 메시지 전달
QUIC에 의존하지 않도록 다시 작성 [Issue #343]
메시지는 CBOR를 사용하여 직렬화된다. 메시지 그룹을 순서대로 보내려면, 해당 메시지 그룹은 하나의 QUIC 스트림에서 보내야 한다. 독립적인 메시지 그룹(그룹 간 순서 의존성이 없는 경우)은 서로 다른 QUIC 스트림에서 보내는 것이 좋다. 여러 CBOR 직렬화 메시지를 같은 QUIC 스트림에 넣기 위해 다음이 사용된다.
각 메시지에 대해, OSP 에이전트는 단방향 QUIC 스트림에 다음을 써야 한다:
에이전트가 인식하지 못하는 타입 키의 메시지를 수신하면, 해당 에이전트는 애플리케이션 오류 코드 404로 QUIC 연결을 닫아야 하며, CONNECTION_CLOSE 프레임의 이유 구문에 알 수 없는 타입 키를 포함하는 것이 좋다.
가변 길이 정수는 Variable-Length Integer Encoding으로 인코딩되며, 이는 QUIC에서 사용된다.
많은 메시지는 요청과 응답이므로, 이를 위한 공통 형식이 정의된다. 요청과 응답은 요청자가 선택한 부호 없는 정수인 요청 ID를 포함한다. 응답은 자신이 연결된 요청의 요청 ID를 포함해야 한다.
4.1. 타입 키 하위 호환성
메시지가 시간이 지나면서 수정되거나 확장됨에 따라, 오래된 버전의 메시지를 이해하는 에이전트와의 하위 호환성을 유지하기 위해 특정 규칙을 따라야 한다.
-
필수 필드가 메시지에 추가되거나 제거되는 경우(메시지에 직접 또는 필드의 필드를 통해 간접적으로), 해당 메시지에는 새 타입 키가 할당되어야 한다. 이는 사실상 새 메시지이며, 수신 에이전트가 새 타입 키를 이해한다는 것이 알려져 있지 않다면 보내서는 안 된다.
-
선택적 필드가 메시지에 추가되는 경우(메시지에 직접 또는 필드의 필드를 통해 간접적으로), 추가된 필드를 이해하지 못하는 이전 수신 에이전트의 동작이 해당 필드를 포함하는 새로운 송신 에이전트와 호환된다면 타입 키는 그대로 유지될 수 있다. 그렇지 않으면 새 타입 키가 할당되어야 한다.
-
선택적 필드가 메시지에서 제거되는 경우(메시지에서 직접 또는 필드의 필드를 통해 간접적으로), 제거된 필드를 이해하지 못하는 새로운 수신 에이전트의 동작이 해당 필드를 포함하는 이전 송신 에이전트와 호환된다면 타입 키는 그대로 유지될 수 있다. 그렇지 않으면 새 타입 키가 할당되어야 한다.
-
필수 필드는 audio-frame과 같은 배열 기반 메시지에 추가되거나 제거될 수 없다.
5. 프레젠테이션 프로토콜
이 절은 Presentation API에서 정의한 프레젠테이션을 시작, 종료 및 제어하기 위해 오픈 스크린 프로토콜을 사용하는 방식을 정의한다. § 5.1 Presentation API는 Presentation 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-request의reason에 대한 유일한 유효 값이다.)
수신자가 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-request 및 presentation-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절이
"구현별 메커니즘을 사용하여 프레젠테이션에 대한 종료 요청을 그 수신 사용자 에이전트에게
보낸다"라고 말할 때, 컨트롤러는 reason을
application-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 API는 Remote 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-request 및 video-frame 같은 스트리밍 메시지를, 마치 스트리밍 세션이 streaming-session-start-request와 streaming-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-request의
urls
| 필수 |
| 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.videoWidth및HTMLVideoElement.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-response의
state 안의 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-request 및 remote-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-response 및 remote-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-format은transfer-function및hdr-metadata두 필드로 구성된다.transfer-function필드는 유효한 TransferFunction이어야 하며,hdr-metadata필드는 유효한 HdrMetadataType이어야 한다. 둘 다 Media Capabilities API에 정의되어 있다.video-hdr-format이transfer-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 scale은
encoding-id가 참조하는 audio-encoding-offer 메시지의time-scale필드 값과 같다. - duration
-
존재하는 경우, 오디오 프레임의 지속 시간이다. 존재하지 않는 경우, 지속 시간은
encoding-id가 참조하는 audio-encoding-offer 메시지의default-duration필드와 같다. time scale은encoding-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 scale은
encoding-id가 참조하는 video-encoding-offer 메시지의time-scale필드 값과 같다. - duration
-
존재하는 경우, 비디오 프레임의 지속 시간이다. 존재하지 않는 경우, 지속 시간이 알려지지 않았음을 의미한다. time scale은
encoding-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 scale은
encoding-id가 참조하는 data-encoding-offer 메시지의time-scale필드 값과 같다. - duration
-
존재하는 경우, 데이터 프레임의 지속 시간이다. 존재하지 않는 경우, 지속 시간은
encoding-id가 참조하는 data-encoding-offer 메시지의default-duration필드와 같다. time scale은encoding-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 필드를 사용하여 해당 버퍼의 상태도 보내는 것이 좋다.
이는 세 가지 값 중 하나를 가질 수 있다:
-
enough-data: 버퍼에 데이터가 너무 많지도 않고 부족하지도 않다. -
insufficient-data: 버퍼가 언더런되어, 예정된 재생 시점에 충분한 프레임 데이터를 갖지 못할 것이다. -
too-much-data: 현재 전송 속도에서는 버퍼가 오버런되어, 이후의 프레임 데이터가 재생되기 전에 버려질 것이다.
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-id 및 watch-id 값은 각 에이전트가 유지하는 카운터에서
할당되는 부호 없는 정수 ID이며, 카운터는 1에서 시작하고 각 ID마다 1씩 증가한다.
에이전트가 자신의 state-token을 변경할 때마다 카운터를 1로 재설정해야 한다.
에이전트가 다른 에이전트가 새 state-token을 광고함으로써 상태를
재설정했음을 알게 되면, 해당 에이전트에 대한 모든 요청, 응답,
감시 및 이벤트를 폐기하는 것이 좋다.
한쪽이 상태를 잃으면 혼란을 일으킬 수 있어 고유해야 하는 다른 ID들,
예를 들어 streaming-session-id, media-session-id 및
encoding-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 API 및 Remote Playback API에서 권장하는 보안 및 개인정보 보호 지침이 충족되는지 검토한다. 마지막으로 이러한 보안 및 개인정보 보호 요구사항을 충족하기 위해 에이전트가 사용할 수 있는 권장 완화책을 논의한다.
11.1. 위협 모델
11.1.1. 동일 출처 정책 위반
Presentation API는 각 출처의 동의(API 사용을 통해)를 바탕으로
제어 페이지와 프레젠테이션 사이의 교차 출처 통신을 허용한다.
이는 targetOrigin이 *인
postMessage()를
통한 교차 출처 통신과 유사하다. 그러나 Presentation API는 각 메시지에
소스 출처 정보를 전달하지 않는다. 따라서 오픈 스크린 프로토콜은
에이전트 간에 출처 정보를 전달하지 않는다.
프레젠테이션 식별자는
제한 없는 교차 출처 접근에 대해 어느 정도 보호를 제공한다. 그러나
PresentationConnection으로
연결된 당사자에 대한 엄격한 인증은 애플리케이션 수준에서 수행되어야 한다.
11.2. 오픈 스크린 애플리케이션 프로토콜 보안 및 개인정보 보호 고려사항
11.2.1. 개인 식별 정보 및 고가치 데이터
프로토콜에서 교환되는 다음 데이터는 개인 식별 가능 데이터 및/또는 고가치 데이터일 수 있다:
-
프레젠테이션 URL 및 사용 가능성 결과
-
프레젠테이션 식별자
-
프레젠테이션 연결 ID
-
프레젠테이션 연결 메시지
-
원격 재생 URL
-
원격 재생 명령 및 상태 메시지
프레젠테이션 식별자는 프레젠테이션 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에 다음에 대한 추가 접근 권한을 부여하지 않는다:
-
새로운 스크립트 로딩 메커니즘
-
사용자의 위치에 대한 접근
-
장치 센서에 대한 접근
-
사용자의 로컬 컴퓨팅 환경에 대한 접근
-
사용자 에이전트의 네이티브 UI에 대한 제어
-
사용자 에이전트의 보안 특성
11.3. Presentation API 고려사항
Presentation API § 7 보안 및 개인정보 보호 고려사항은 오픈 스크린 프로토콜에 다음 요구사항을 둔다:
-
프레젠테이션 URL 및 프레젠테이션 식별자는 교차 출처 접근 지침에 따라 프레젠테이션에 연결할 수 있도록 허용된 당사자 사이에서 비공개로 유지되는 것이 좋다.
-
사용자 인터페이스 지침에 따라 여러 사용자 에이전트 프로필을 나타내는 연결이 프레젠테이션에 만들어졌을 때 컨트롤러와 수신자에게 알리는 것이 좋다.
-
프레젠테이션 연결 간 메시징 지침에 따라 컨트롤러와 수신자 사이의 메시징은 인증되고 기밀로 유지되는 것이 좋다.
일반적인 전송 요구사항을 반영하도록 갱신. [Issue #342]
오픈 스크린 프로토콜은 다음 방식으로 이러한 고려사항을 다룬다:
-
프레젠테이션 URL, ID 또는 메시지가 교환되기 전에 상호 인증과 TLS로 보호되는 QUIC 연결을 요구한다.
-
개별
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의 잘린 표시 이름 대신, 완전한 표시 이름만 사용자에게 표시하는 것이 좋다. 잘린 표시 이름은 전체 이름으로 검증된 표시 이름으로 표시되기 전에 위와 같이 검증되는 것이 좋다.
- 잘렸고 검증되지 않은 DNS-SD Instance Names. 사용자에게 표시하지 않는 것이 좋다.
- 완전하지만 검증되지 않은 DNS-SD Instance Names. 인증 전에 검증되지 않은 것으로 표시할 수 있다.
- 검증된 표시 이름.
부록 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-zero-time은 HTML에 정의된 미디어 타임라인의 원점이며, IEEE-754 배정밀도 부동소수점 수 [IEEE-754]로 변환된다. -
value및scale은 해당 audio-frame 또는 video-frame의sync-time필드에 전달된 값이다. -
value / scale은 배정밀도 부동소수점 정밀도로 계산하는 것이 좋다. -
media-timeline-value는 IEEE-754 배정밀도 부동소수점 수 [IEEE-754]이다.
media-timeline-value에서 오버플로가 발생하는 경우, 표현 가능한
최댓값을 사용하는 것이 좋다.