-
Notifications
You must be signed in to change notification settings - Fork 20
/
index.html
1585 lines (1573 loc) · 68.5 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title>
Remote Playback API
</title>
<script src="https://www.w3.org/Tools/respec/respec-w3c" async
class="remove">
</script>
<script class="remove">
var respecConfig = {
specStatus: 'ED',
edDraftURI: 'https://w3c.github.io/remote-playback/',
shortName: 'remote-playback',
group: 'secondscreen',
editors: [
{
w3cid: 68454,
name: 'Mark Foltz',
company: 'Google',
},
],
formerEditors: [
{
w3cid: 45389,
name: 'Mounir Lamouri',
company: 'Google',
},
{
w3cid: 68811,
name: 'Anton Vayvod',
company: 'Google',
},
],
sotdAfterWGinfo: true,
license: "w3c-software-doc",
// previousMaturity: 'WD',
// previousPublishDate: '2015-11-02',
otherLinks: [
{
key: 'Test suite',
data: [
{
value: 'GitHub web-platform-tests/remote-playback',
href: 'https://github.com/web-platform-tests/wpt/tree/master/remote-playback'
},
{
value: 'w3c-test.org/remote-playback/',
href: 'https://w3c-test.org/remote-playback/'
}
]
}
],
group: 'secondscreen',
github: 'https://github.com/w3c/remote-playback',
crEnd: '2017-11-30',
implementationReportURI: 'https://www.w3.org/wiki/Second_Screen/Implementation_Status#Remote_Playback_API'
};
</script>
<style>
/* Note formatting taken from Presentation API spec for consistency in the
Second Screen WG */
.note { border-left-style: solid; border-left-width: 0.25em; background: none repeat scroll 0 0 #E9FBE9; border-color: #52E052; }
.note em, .warning em, .note i, .warning i { font-style: normal; }
p.note, div.note { padding: 0.5em 2em; }
span.note { padding: 0 2em; }
.note p:first-child { margin-top: 0; }
.note p:last-child { margin-bottom: 0; }
p.note:before { content: 'NOTE: '; }
.non-normative { border-left-style: solid; border-left-width: 0.25em; background: none repeat scroll 0 0 #E9FBE9; border-color: #52E052; }
p.non-normative:before { content: 'Non-normative: '; font-weight: bolder;}
p.non-normative, div.non-normative { padding: 0.5em 2em; }
.algorithm li {
margin-bottom: 0.5em;
}
.interface dd, .parameters dt {
margin-bottom: 0.5em;
}
code { color: orangered; }
table { border-collapse: collapse; border-style: hidden hidden none hidden; }
table thead, table tbody { border-bottom: solid; }
table td, table th { border-left: solid; border-right: solid; border-bottom: solid thin; vertical-align: top; padding: 0.2em; }
dfn { font-weight: bolder; font-style: normal; }
.copyright { font-size: small; }
.issue[id^='issue-'] > *:not([role='heading']) { display: none; }
</style>
</head>
<body data-cite="HTML DOM URL SECURE-CONTEXTS">
<section id="abstract">
<p>
This specification defines an API extending the {{HTMLMediaElement}}
that enables controlling remote playback of media from a web page.
</p>
</section>
<section id="sotd">
<p>
This document builds on the group's experience on presenting web
content on external presentation-type displays, and re-uses patterns
and design considerations from the Presentation API specification
whenever appropriate [[PRESENTATION-API]].
</p>
<p>
Although this document is still a <strong>work in progress</strong> and
is subject to change, the Working Group believes that the API surface is
stable. Most of the remaining issues listed on the <a href=
"https://github.com/w3c/remote-playback/issues/">issue tracker</a> are
considered minor at this stage except for
Issue <a href="https://github.com/w3c/remote-playback/issues/41">#41</a>.
</p>
<p>
Issue <a href="https://github.com/w3c/remote-playback/issues/41">#41</a>
discusses the set of media playback features that remote playback
devices are expected to support. The group will seek further developer
feedback and implementation experience to identify any interoperability
issues around these features when used during remote playback, and will
further clarify the specification based on feedback received.
</p>
<p>
For other issues or concerns, it is possible to <a href=
'https://github.com/w3c/remote-playback/issues/new'>file a bug</a> or
send an email to the <a href=
'https://lists.w3.org/Archives/Public/public-secondscreen/'>mailing
list</a>. For small editorial changes like typos, sending a pull request
is appreciated.
</p>
<p>
The Working Group invites everyone to review this document, and will
work with relevant groups at W3C to conduct horizontal reviews on
accessibility, internationalization, privacy, security and technical
architecture principles.
</p>
<p>
No feature has been identified as being <strong>at risk</strong>.
</p>
<p>
The Second Screen Working Group will develop a test suite for the
Remote Playback API during the Candidate Recommendation period and
prepare an implementation report. For this specification to advance to
Proposed Recommendation, two independent, interoperable implementations
of each feature must be demonstrated, as detailed in the <a href=
"#candidate-recommendation-exit-criteria">Candidate Recommendation exit
criteria</a> section.
</p>
</section>
<section id='conformance'>
<p>
This specification defines conformance criteria that apply to a single
product: the user agent that implements the interfaces that
it contains.
</p>
<p>
Implementations that use ECMAScript to expose the APIs defined in this
specification MUST implement them in a manner consistent with the
ECMAScript Bindings defined in the Web IDL specification [[!WEBIDL]].
</p>
</section>
<section class="informative">
<h2>
Introduction
</h2>
<p>
This specification aims to make <a>remote playback devices</a> such as
connected TVs, projectors or audio-only speakers, available to the Web
and takes into account playback devices that are attached using wired
(HDMI, DVI, or similar) and wireless technologies (Miracast,
Chromecast, DLNA, AirPlay, or similar).
</p>
<p>
Devices with limited screen size or quiet speakers lack the ability to
playback media content to a larger audience, for example, a group of
colleagues in a conference room, or friends and family at home. Playing
media content on an external larger and/or louder <a>remote playback
device</a> helps to improve the perceived quality and impact of the
played media.
</p>
<p>
At its core, this specification enables a page that acts as the
<a>browsing context</a> to initiate and control remote playback of a
particular media element on a selected <a>remote playback device</a>.
How the remoting is initiated and controlled is left to the UA in order
to allow the use of <a>remote playback devices</a> that can be attached
in a wide variety of ways. For example, when a <a>remote playback
device</a> is attached using HDMI or Miracast, the same UA that acts as
the <a>browsing context</a> renders the remote media. Instead of
playing the media on the same device, however, it can use whatever
means the operating system provides for using the external <a>remote
playback device</a>. In such a case, both the <a>browsing context</a>
and the media player run on the same UA and the operating system is
used to route the player output to the <a>remote playback device</a>.
This is commonly referred to as the <dfn>media
mirroring</dfn> case. This specification imposes no requirements on
the <a>remote playback devices</a> connected in such a manner.
</p>
<p>
If the <a>remote playback device</a> is able to play the media and
communicate with the <a>browsing context</a> but is unable to fetch the
media, the <a>browsing context</a> needs to fetch the media data and
pass it on to the <a>remote playback device</a> for rendering. This is
commonly referred to as <dfn>media remoting</dfn> case.
</p>
<p>
If the <a>remote playback device</a> is able to fetch and play the media
and communicate with the <a>browsing context</a>, the <a>browsing
context</a> does not need to fetch or render the remoted media. In this
case, the UA acts as a proxy that requests the <a>remote playback
device</a> to play the media itself by passing the necessary data like
the media source. This is commonly referred to as the <dfn>media
flinging</dfn> case. This way of attaching to displays could be
enhanced in the future by defining a standard protocol for delivering
these types of messages that remote playback devices could choose to
implement.
</p>
<p>
The API defined here is intended to be used with UAs that attach to
<a>remote playback device</a> devices through any of the above means.
</p>
</section>
<section class='informative'>
<h2>
Use cases and requirements
</h2>
<p>
The use cases and requirements of this specification are captured in a
separate document available <a href=
'https://github.com/w3c/remote-playback/blob/gh-pages/use-cases.md'>here</a>.
</p>
</section>
<section>
<h2>
Examples
</h2>
<p>
This section shows code examples that highlight the usage of the main
features of the Remote Playback API. In these examples,
`player.html` implements the player page controlling the
remote playback and `media.ext` is the media file to be
played remotely. Both the page and the media are served from the domain
`https://example.org`. Please refer to the comments in the
code examples for further details.
</p>
<section>
<h3>
Monitor availability of remote playback devices example
</h3>
<pre class="example">
<!-- player.html -->
<!-- The video element with custom controls that supports remote playback. -->
<video id="videoElement" src="https://example.org/media.ext" />
<button id="deviceBtn" style="display: none;">Pick device</button>
<script>
// The "Pick device" button is visible if at least one remote playback device is available.
const deviceBtn = document.getElementById("deviceBtn");
const videoElem = document.getElementById("videoElement");
function availabilityCallback(available) {
// Show or hide the device picker button depending on device availability.
deviceBtn.style.display = available ? "inline" : "none";
}
videoElem.remote.watchAvailability(availabilityCallback).catch(() => {
// Availability monitoring is not supported by the platform, so discovery of
// remote playback devices will happen only after remote.prompt() is called.
// Pretend the devices are available for simplicity; or, one could implement
// a third state for the button.
deviceBtn.style.display = "inline";
});
</script>
</pre>
</section>
<section>
<h3>
Starting remote playback of a video example
</h3>
<pre class="example">
<!-- player.html -->
<script>
deviceBtn.onclick = () => {
// Request the user to select a remote playback device.
videoElem.remote.prompt()
// Update the UI and monitor the connected state.
.then(updateRemotePlaybackState);
// Otherwise, the user cancelled the selection UI or no screens were found.
};
<script>
</pre>
</section>
<section>
<h3>
Monitoring remote playback state changes
</h3>
<pre class="example">
<!-- player.html -->
<script>
// The remote playback may be initiated by the user agent,
// so check the initial state to sync the UI with it.
if (videoElem.remote.state == "disconnected")
switchToLocalUI();
else
switchToRemoteUI();
videoElem.remote.onconnecting = switchToRemoteUI;
videoElem.remote.onconnect = switchToRemoteUI;
videoElem.remote.ondisconnect = switchToLocalUI;
// Handles both 'connecting' and 'connected' state. Calling more than once
// is a no-op.
function switchToRemoteUI() {
// Indicate that the state is 'connecting' or 'connected' to the user.
// For example, hide the video element as only controls are needed.
videoElem.style.display = "none";
// Stop monitoring the availability of remote playback devices.
videoElem.remote.cancelWatchAvailability();
};
function switchToLocalUI() {
// Show the video element.
videoElem.style.display = "inline";
// Start watching the device availability again.
videoElem.remote.watchAvailability(availabilityCallback);
};
<script>
</pre>
</section>
</section>
<section>
<h2>
API
</h2>
<section>
<h3>
Common idioms
</h3>
<p>
A <dfn>local playback device</dfn> is the device the <a>browsing
context</a> is running on along with the default video/audio outputs
the device has.
</p>
<div class="note">
A <a>local playback device</a> might have extra outputs, like an
external display or speakers/headphones. As long as the switch of
what output to use happens outside of the user agent on the
system level, the playback is considered to happen on a <a>local
playback device</a> for the purpose of this spec.
</div>
<p>
A <dfn data-lt="remote playback devices">remote playback device</dfn>
is any other device but the <a>local playback device</a> that the
<a>browsing context</a> can use to play media on.
</p>
<p>
A <dfn>media element state</dfn> is the set of all single
<dfn data-cite="HTML#media-element">media element</dfn>
properties observable by the page and/or the user via the
user agent implementation. The new properties introduced by
this spec are not considered part of the <a>media element state</a>
for convenience.
</p>
<div class="example">
For example, the `paused` attribute or the pause/resume
button reflecting that state on the default controls of the media
element would be a part of <a>media element state</a>.
</div>
<p>
A <dfn>local playback state</dfn> is the user agent implementation of
<a>media element state</a> for the particular <a>media element</a>
for playback on the <a>local playback device</a>.
</p>
<p>
A <dfn>remote playback state</dfn> is the user agent implementation
of <a>media element state</a> for the particular <a>media element</a>
for playback on the certain <a>remote playback device</a>.
</p>
<p class="note">
For a good user experience it is important that the <a>media element
state</a> doesn't change unexpectedly when the
{{RemotePlayback/state}} changes. It is also important that <a>remote
playback state</a> is in sync with the <a>media element state</a> so
when the media is paused on the
<a>remote playback device</a> it looks paused to both the user and
the page.
</p>
<p>
The <a>task source</a> for the tasks mentioned in this specification
is the <a data-cite="HTML#media-element-event-task-source">
media element event task source</a>.
</p>
</section>
<section>
<h3>
<dfn>RemotePlayback</dfn> interface
</h3>
<pre class='idl'>
[Exposed=Window]
interface RemotePlayback : EventTarget {
Promise<long> watchAvailability(RemotePlaybackAvailabilityCallback callback);
Promise<undefined> cancelWatchAvailability(optional long id);
readonly attribute RemotePlaybackState state;
attribute EventHandler onconnecting;
attribute EventHandler onconnect;
attribute EventHandler ondisconnect;
Promise<undefined> prompt();
};
enum RemotePlaybackState {
"connecting",
"connected",
"disconnected"
};
callback RemotePlaybackAvailabilityCallback = undefined(boolean available);
</pre>
<p>
A {{RemotePlayback}} object allows the page to detect availability
of, connect to and control playback on <a>remote playback devices</a>.
</p>
<p>
The <dfn>RemotePlaybackState</dfn> enum represents possible connection
states to a <a>remote playback device</a>.
</p>
<p>
The <dfn>RemotePlaybackAvailabilityCallback</dfn> returns the current
<a>remote playback device availability</a>.
</p>
<section data-link-for="RemotePlayback">
<h4>
Observing remote playback device availability
</h4>
<p>
A {{RemotePlaybackAvailabilityCallback}} is the way for the page to
obtain the <dfn>remote playback device availability</dfn> for the
corresponding <a>media element</a>. If the user agent can <a>monitor
the list of available remote playback devices</a> in the background
(without a pending request to {{RemotePlayback/prompt()}}), the
{{RemotePlaybackAvailabilityCallback}} behavior defined below MUST
be implemented by the user agent. Otherwise, the promise returned by
{{RemotePlayback/watchAvailability()}} MUST be rejected with
{{NotSupportedError}}.
</p>
<section>
<h5>
The set of availability callbacks
</h5>
<p>
The user agent MUST keep track of the <dfn>set of availability
callbacks</dfn> registered with each <a>media element</a> through
the <dfn data-dfn-for="RemotePlayback">watchAvailability()</dfn>
method. The <a>set of availability callbacks</a> for each
{{RemotePlayback}} object is represented as a set of tuples
<em>(|callbackId:long|, |callback:RemotePlaybackAvailabilityCallback|)</em>,
initially empty, where:
</p>
<ol>
<li>
|callbackId| is a positive integer unique among all ids
returned by {{RemotePlayback/watchAvailability()}} in a
given <a>browsing context</a>;
</li>
<li>
|callback| is a {{RemotePlaybackAvailabilityCallback}} object.
</li>
</ol>
<p>
Since there's one and only one {{RemotePlayback}} object per
each <a>media element</a>, <a>set of availability callbacks</a>
of a <a>media element</a> is the same set as the <a>set of
availability callbacks</a> of the {{RemotePlayback}} object
referred to by the element's <a data-link-for=
"HTMLMediaElement">remote</a> property.
</p>
<p>
The combined set of all <a data-lt=
"set of availability callbacks">sets of availability
callbacks</a> of all {{RemotePlayback}} objects known to the
<a>browsing context</a> is referred to as <dfn>global set of
availability callbacks</dfn>.
</p>
</section>
<section>
<h5>
The list of available remote playback devices
</h5>
<p>
The user agent MUST keep a <dfn>list of available remote
playback devices</dfn>. This list contains <a>remote playback
devices</a> and is populated based on an implementation specific
discovery mechanism. It is set to the most recent result of the
algorithm to <a>monitor the list of available remote playback
devices</a> or an empty list if the algorithm hasn't been run
yet.
</p>
<p>
The user agent MAY not support running the algorithm to
<a>monitor the list of available remote playback devices</a>
continuously, for example, because of platform or power
consumption restrictions. In this case the promise returned by
{{RemotePlayback/watchAvailability()}} MUST be rejected with
{{NotSupportedError}}, the <a>global set of availability
callbacks</a> will be empty and the algorithm to <a>monitor the
list of available remote playback devices</a> will only run as
part of the <a>initiate remote playback</a> algorithm.
</p>
<p>
When the <a>global set of availability callbacks</a> is not
empty, the user agent MUST <a>monitor the list of
available remote playback devices</a> continuously, so that pages
can keep track of the last value received via the registered
callbacks to offer remote playback only when there are available
devices.
</p>
<p class="note">
The user agent is expected not to <a>monitor the list of available
remote playback devices</a> when possible, to satisfy the <a href=
"https://github.com/w3c/remote-playback/blob/gh-pages/use-cases.md#power-saving-friendly">
power saving non-functional requirement</a>. For example, the
user agent might choose not to run the monitoring
algorithm when the <a>global set of availability callbacks</a> is
empty, when every page that has <a>media elements</a> with non-empty
<a>set of availability callbacks</a> is in the background.
</p>
<p>
Some <a>remote playback devices</a> may only be able to play a
subset of <a data-cite="HTML#media-resource">media resources</a>
because of functional, security or hardware limitations. Examples
are set-top boxes, smart TVs or networked speakers capable of
rendering only certain formats of video and/or audio. We say that
such a device is a <dfn>compatible remote playback device</dfn>
for a <a data-cite="HTML#media-resource">media resource</a>
if the user agent can reasonably guarantee that the
remote playback of the media specified by the resource will
succeed on that device.
</p>
<p class="note">
The user agent can use the {{HTMLTrackElement/srclang}}
attribute of the <code>[^track^]</code> element as a hint of
the language of the text track data to help identify a
<a>compatible remote playback device</a>.
</p>
<p>
The <a data-cite="HTML#media-resource">media resources</a>
of a <a>media element</a>, that were considered by the user agent
to find a <a>compatible remote playback device</a>, are called the
<dfn>availability sources set</dfn>.
</p>
<p>
The <a data-cite="HTML#media-resource">media resource</a> of
a <a>media element</a> that is used to <a>initiate remote
playback</a> on the selected <a>remote playback device</a> is
called the <dfn>remote playback source</dfn>. A remote playback
source MUST belong to the media element's <a>availability sources
set</a>.
</p>
<p>
The mechanism to choose the <a>remote playback source</a> from
the <a>availability sources set</a> is implementation-specific,
but the user agent SHOULD consider every resource in
the <a>availability sources set</a> as a potential <a>remote
playback source</a>.
</p>
<div class="note">
The algorithm to select the <a>remote playback source</a> for a
selected device depends on the user agent and supported <a>remote
playback device</a> types. For example, in case of <a>media
mirroring</a> the user agent can simply follow the
{{HTMLMediaElement}}'s <a data-cite="HTML#concept-media-load-algorithm">
resource selection algorithm</a>. However, if <a>media
remoting</a> or <a>media flinging</a> is used, the best media
source can depend on the selected <a>remote playback device</a>
fetch and playback capabilities.
</div>
<p>
If the user agent cannot determine a <a>remote playback source</a>
appropriate for the <a>remote playback device</a>, it is
RECOMMENDED that the user agent send metadata (for example,
the <a data-cite="HTML#attr-source-type">extended MIME type</a>)
about all resources in the <a>availability sources set</a> to
the <a>remote playback device</a> so it can run its own
<a data-cite="HTML#concept-media-load-algorithm">resource
selection algorithm</a> and choose the <a>remote playback
source</a>.
</p>
<p>
Remote playback is <dfn>unavailable</dfn> for the
<a>media element</a> if the <a>list of available remote playback
devices</a> is empty or none of them is compatible with any source
from <a>availability sources set</a> for the <a>media
element</a>. Otherwise, remote playback is
<dfn>available</dfn>. A `boolean` set to `false` if the remote
playback is <a>unavailable</a> for the <a>media element</a> or
`true` if it is <a>available</a> is called
<dfn>availability</dfn> for the <a>media element</a>.
</p>
<p>
If the user agent stops
<a data-lt="monitor the list of available remote playback devices">
monitoring the list of available remote playback devices</a>
(for example by a user control or for power saving), it SHOULD
invoke all callbacks in the <a>global set of availability
callbacks</a> with `false` so that pages can update
their user experience appropriately. It SHOULD also set
the <a>availability</a> value for all <a>media elements</a>
to `false` so that availability information can
be propagated correctly if the user agent later resumes
<a data-lt="monitor the list of available remote playback devices">
monitoring the list of available remote playback devices</a>.
</p>
</section>
<section>
<h5>
Getting the <a>remote playback devices</a> availability
information
</h5>
<p>
When the {{RemotePlayback/watchAvailability()}} method is
called, the user agent MUST run the following steps:
</p>
<dl>
<dt>
Input
</dt>
<dd>
|callback:RemotePlaybackAvailabilityCallback|, the callback that
will get fired with availability information.
</dd>
<dt>
Output
</dt>
<dd>
|promise:Promise|, a {{Promise}}.
</dd>
</dl>
<ol>
<li>
Let |promise| be a new {{Promise}}.
</li>
<li>
Return |promise|, and run the following steps below:
</li>
<li>
If the <a data-link-for="HTMLMediaElement">disableRemotePlayback</a>
attribute is present for the <a>media element</a>, reject the |promise|
with {{InvalidStateError}} and abort all the remaining steps.
</li>
<li>
If the user agent is unable to <a>monitor the list of
available remote playback devices</a> for the entire lifetime of
the <a>browsing context</a> (for instance, because the user has
disabled this feature), then run the following steps <a>in parallel</a>:
<ol>
<li>
Fulfill |promise|.
</li>
<li>
<a>Queue a task</a> to invoke the |callback| with
`false` as its argument.
</li>
<li>
Abort all remaining steps.
</li>
</ol>
</li>
<li>
If the user agent is unable to continuously <a>monitor the
list of available remote playback devices</a> but can do it for a
short period of time when <a data-lt="initiate remote playback">
initiating remote playback</a>, then:
<ol>
<li>
Reject |promise| with a {{NotSupportedError}} exception.
</li>
<li>
Abort all remaining steps.
</li>
</ol>
</li>
<li>
Let |callbackId:long| be a positive integer unique among
all the |callbackIds| previously returned by these
steps in the <a>browsing context</a> of the <a>media
element</a>.
</li>
<li>
Create a tuple <em>(|callbackId|, |callback|)</em> and
add it to the <a>set of availability callbacks</a>
for this <a>media element</a>.
</li>
<li>
Fulfill |promise| with the |callbackId| and
run the following steps <a>in parallel</a>:
<ol>
<li>
<a>Queue a task</a> to invoke the |callback| with
the current <a>availability</a> for the <a>media
element</a>.
</li>
<li>If the user agent is not <a data-lt=
"monitor the list of available remote playback devices">monitoring
the list of available remote playback devices</a>, run the
algorithm to <a>monitor the list of available remote playback
devices</a>.
</li>
</ol>
</li>
</ol>
<p class="note">
A simple algorithm for assigning |callbackId| values is
to keep a counter for each <a>browsing context</a> and
incrementing it in step 6.
</p>
<div class="note">
To avoid leaking information that could fingerprint the user, the
user agent is expected not to assign a |callbackId| that
uses any persistent information from the browser profile or a
<a>remote playback device</a>.
</div>
</section>
<section>
<h5>
Monitoring the list of available remote playback devices
</h5>
<p>
If the <a>set of availability callbacks</a> is non-empty, or
there is a pending request to <a data-lt="prompt">
initiate remote playback</a>, the user agent
MUST <dfn>monitor the list of available remote playback
devices</dfn> by running the following steps:
</p>
<ol>
<li>
Retrieve available remote playback devices (using an
implementation specific mechanism) and let |newDevices:list|
be this list.
</li>
<li>
For each <a>media element</a> known to the <a>browsing
context</a>:
<ol>
<li>
If the <a data-link-for="HTMLMediaElement">disableRemotePlayback</a>
attribute is present for |mediaElement:HTMLMediaElement|, abort all
the remaining steps for this tuple and continue to the next one.
</li>
<li>
Set |newAvailabilityValue:boolean| to the value of
<a>availability</a> for the <a>media element</a> calculated
using the |newDevices| list instead of the <a>list
of available remote playback devices</a>.
</li>
<li>
If the current <a>availability</a> is not equal to
|newAvailabilityValue|, then for each <em>(|callbackId:long|,
|callback:RemotePlaybackAvailabilityCallback|)</em>
of the element's <a>set of availability callbacks</a>:
<ol>
<li>
<a>Queue a task</a> to invoke |callback| with
|newAvailabilityValue| as its argument.
</li>
</ol>
</li>
</ol>
</li>
<li>
Set the <a>list of available remote playback devices</a> to
the value of |newDevices|.
</li>
</ol>
</section>
<section>
<h5>
Stop observing remote playback devices availability
</h5>
<p>
When a <dfn data-dfn-for="RemotePlayback">cancelWatchAvailability()</dfn>
method is called, the user agent MUST run the following steps:
</p>
<dl>
<dt>
Input
</dt>
<dd>
|id:long|, the callback identifier.
</dd>
<dt>
Output
</dt>
<dd>
|promise:Promise|, a {{Promise}}.
</dd>
</dl>
<ol>
<li>
Let |promise| be a new {{Promise}}.
</li>
<li>
Return |promise|, and run the following steps below:
</li>
<li>
If the <a data-link-for=
"HTMLMediaElement">disableRemotePlayback</a> attribute is present
for the <a>media element</a>, reject |promise| with
{{InvalidStateError}} and abort all the remaining steps.
</li>
<li>
If the parameter |id| is `undefined`,
clear the <a>set of availability callbacks</a>.
</li>
<li>
Otherwise, if |id| matches the |callbackId:long|
for any entry in the <a>set of availability callbacks</a>, remove
the entry from the set.
</li>
<li>
Otherwise, reject |promise| with
{{NotFoundError}} and abort all the remaining steps.
</li>
<li>
If the <a>set of availability callbacks</a> is now empty and
there is no pending request to
<a data-lt="prompt">initiate remote playback</a>, cancel any
pending task to <a>monitor the list of available remote
playback devices</a> for power saving purposes.
</li>
<li>
Fulfill |promise|.
</li>
</ol>
<div class="note">
The mechanism used to monitor <a>remote playback devices</a>
availability and determine the compatibility of a <a>remote
playback device</a> with the selected <a>availability sources
set</a> is left to the user agent.
</div>
</section>
</section>
<section data-link-for="RemotePlayback">
<h4>
Prompt user for changing remote playback state
</h4>
<p>
When the <dfn data-dfn-for="RemotePlayback">prompt()</dfn> method is
called, the user agent MUST run the following steps:
</p>
<dl>
<dt>
Input
</dt>
<dd>
None, but the algorithm references the <a>media element</a>, its
<a data-lt="RemotePlayback">remote</a> property and its
<a>availability sources set</a>.
</dd>
<dt>
Output
</dt>
<dd>
A {{Promise}}.
</dd>
</dl>
<ol>
<li>
Let |promise:Promise| be a new {{Promise}}.
</li>
<li>
Return |promise| and continue running these steps
<a>in parallel</a>.
</li>
<li>
If the <a data-link-for=
"HTMLMediaElement">disableRemotePlayback</a> attribute is present
for the <a>media element</a>, reject the |promise| with
{{InvalidStateError}} and abort all the remaining steps.
</li>
<li>
If there is already an unsettled promise from a previous call to
{{RemotePlayback/prompt()}} for the same <a>media element</a> or
even for the same <a>browsing context</a>, the user agent MAY reject
|promise| with an {{OperationError}} exception and abort all
remaining steps.
<div class="note">
The rationale here is that the user agent might show a dialog
that's modal to either the <a>media element</a> or the
<a>browsing context</a>. In such a case, the second call to
{{RemotePlayback/prompt()}} would not be able to show any UI.
</div>
</li>
<li>
If the document's [=navigable/active window=] does not have
[=transient activation=], reject |promise| with an
{{InvalidAccessError}} exception and abort these steps.
</li>
<li>
OPTIONALLY, if the user agent knows a priori that remote playback
of this particular <a>media element</a> is not feasible (independent
of the current <a>`state`</a> or the <a>list of available remote
playback devices</a>), reject |promise| with a {{NotSupportedError}}
and abort all remaining steps.
<div class="note">
An example of this situation is when the user agent only
supports <a>media flinging</a>, and the media element's source
is not a {{URL}} that can be passed to a
<a>remote playback device</a>.
</div>
</li>
<li>
If the user agent needs to show the <a>list of available remote
playback devices</a> and is not <a data-lt= "monitor the list of
available remote playback devices">monitoring the list of
available remote playback devices</a>, run the steps to
<a>monitor the list of available remote playback devices</a> <a>in
parallel</a>.
</li>
<li>
If remote playback is <a>unavailable</a> and will remain so
before the request for user permission is complete,
reject |promise| with a {{NotFoundError}} exception and
abort all remaining steps.
</li>
<li>
Request user permission to <dfn>change remote playback
state</dfn>.
<div class="note">
An example UI to request permission would allow the user to
pick a new <a>remote playback device</a>, switch between local
or remote playback devices, or <a>disconnect from a remote
playback device</a>.
</div>
<div class="note">
The user may have already selected a <a>remote playback
device</a> for a related purpose, for example, to mirror the
contents of the display or the current page. In that case, the
user agent may choose to skip the UI to select a device and
proceed immediately to the next step.
</div>
</li>
<li>
If the user picked a <a>remote playback device</a> |device:remote
playback device| to <dfn>initiate remote playback</dfn> with, the
user agent MUST run the following steps:
<ol>
<li>
Set the <a>state</a> of the |remote:RemotePlayback| object
to <a data-link-for="RemotePlaybackState">connecting</a>.
</li>
<li>
Fulfill |promise|.
</li>
<li>
<a>Queue a task</a> to <a>fire an event</a> named
<a>connecting</a> at the <a data-lt=
"RemotePlayback">remote</a> property of the <a>media
element</a>. The event must not bubble, must not be
cancelable, and has no default action.
</li>
<li>
<a>Establish a connection with the remote playback device</a>
|device| for the <a>media element</a>.
</li>
</ol>
<p class="note">
By picking a <a>remote playback device</a> the user <em>grants
permission</em> to use the device.
</p>
</li>
<li>
Otherwise, if the user chose to disconnect from the <a>remote
playback device</a> |device|, the user agent MUST run the
following steps:
<ol>
<li>
Fulfill |promise|.
</li>
<li>
Run the <a>disconnect from a remote playback device</a>
algorithm for the |device|.
</li>
</ol>
</li>
<li>
Otherwise, the user is considered to <em>deny permission</em> to
use the device, so reject |promise| with {{NotAllowedError}}
exception and hide the UI shown by the user agent.
</li>
</ol>
<div class="note">
The details of implementing the UI and device selection are left to
the user agent; for example it can show the user a dialog and allow
the user to select an available device (<em>granting
permission</em>), or cancel the selection (<em>denying
permission</em>). In most cases, available devices will advertise
a user friendly name along with locale and text direction
information for that name. The user agent is encouraged to render
this user friendly name, using its locale and text direction when
they are known.
</div>
</section>