shaka-player 4.4.3 → 4.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
- package/.github/workflows/release-please.yaml +2 -27
- package/AUTHORS +2 -0
- package/CHANGELOG.md +156 -39
- package/CODE_OF_CONDUCT.md +1 -1
- package/CONTRIBUTORS +2 -0
- package/README.md +54 -42
- package/demo/asset_card.js +18 -21
- package/demo/cast_receiver/index.html +0 -1
- package/demo/close_button.js +0 -3
- package/demo/common/asset.js +33 -22
- package/demo/common/assets.js +249 -60
- package/demo/config.js +219 -253
- package/demo/custom.js +88 -133
- package/demo/front.js +7 -10
- package/demo/index.html +19 -22
- package/demo/input.js +6 -11
- package/demo/input_container.js +8 -9
- package/demo/main.js +62 -126
- package/demo/search.js +29 -34
- package/demo/service_worker.js +0 -3
- package/demo/tooltip.js +3 -5
- package/demo/visualizer.js +3 -5
- package/demo/visualizer_button.js +1 -20
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +211 -228
- package/dist/demo.compiled.debug.map +4 -4
- package/dist/demo.compiled.js +211 -228
- package/dist/demo.compiled.map +4 -4
- package/dist/deps.js +42 -37
- package/dist/locales.js +34 -30
- package/dist/receiver.compiled.debug.js +64 -77
- package/dist/receiver.compiled.debug.map +4 -4
- package/dist/receiver.compiled.js +64 -77
- package/dist/receiver.compiled.map +4 -4
- package/dist/shaka-player.compiled.d.ts +343 -151
- package/dist/shaka-player.compiled.debug.d.ts +343 -151
- package/dist/shaka-player.compiled.debug.externs.js +356 -117
- package/dist/shaka-player.compiled.debug.js +952 -811
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +356 -117
- package/dist/shaka-player.compiled.js +1165 -1078
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +359 -153
- package/dist/shaka-player.ui.debug.d.ts +359 -153
- package/dist/shaka-player.ui.debug.externs.js +382 -117
- package/dist/shaka-player.ui.debug.js +1084 -918
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +382 -117
- package/dist/shaka-player.ui.js +1377 -1274
- package/dist/shaka-player.ui.map +4 -4
- package/docs/design/lcevc-integration.md +14 -14
- package/docs/tutorials/ad_monetization.md +54 -0
- package/docs/tutorials/basic-usage.md +2 -1
- package/docs/tutorials/errors.md +2 -1
- package/docs/tutorials/faq.md +27 -55
- package/docs/tutorials/index.json +2 -1
- package/docs/tutorials/lcevc.md +118 -0
- package/docs/tutorials/offline.md +10 -8
- package/docs/tutorials/plugins.md +5 -0
- package/docs/tutorials/ui-customization.md +17 -0
- package/docs/tutorials/ui.md +2 -1
- package/docs/tutorials/upgrade.md +3 -0
- package/externs/css_style_declaration.js +19 -0
- package/externs/lcevc.js +37 -13
- package/externs/managedmediasource.js +24 -0
- package/externs/media_remote.js +68 -0
- package/externs/mediatailor.js +193 -0
- package/externs/pictureinpicture.js +11 -0
- package/externs/shaka/abr_manager.js +6 -2
- package/externs/shaka/ads.js +27 -0
- package/externs/shaka/cea.js +7 -0
- package/externs/shaka/codecs.js +5 -3
- package/externs/shaka/manifest.js +31 -10
- package/externs/shaka/manifest_parser.js +24 -1
- package/externs/shaka/net.js +2 -2
- package/externs/shaka/offline.js +13 -2
- package/externs/shaka/player.js +65 -8
- package/externs/shaka/text.js +3 -1
- package/externs/shaka/transmuxer.js +1 -1
- package/karma.conf.js +7 -3
- package/lib/abr/simple_abr_manager.js +66 -9
- package/lib/ads/ad_manager.js +104 -50
- package/lib/ads/media_tailor_ad.js +297 -0
- package/lib/ads/media_tailor_ad_manager.js +839 -0
- package/lib/cast/cast_receiver.js +1 -1
- package/lib/cea/cea_decoder.js +28 -0
- package/lib/cea/dummy_caption_decoder.js +5 -0
- package/lib/cea/ts_cea_parser.js +15 -2
- package/lib/config/codec_switching_strategy.js +24 -0
- package/lib/dash/content_protection.js +120 -2
- package/lib/dash/dash_parser.js +322 -93
- package/lib/dash/mpd_utils.js +62 -37
- package/lib/dash/segment_base.js +17 -10
- package/lib/dash/segment_list.js +18 -9
- package/lib/dash/segment_template.js +122 -107
- package/lib/dependencies/all.js +8 -7
- package/lib/hls/hls_classes.js +28 -43
- package/lib/hls/hls_parser.js +798 -658
- package/lib/hls/hls_utils.js +64 -5
- package/lib/hls/manifest_text_parser.js +7 -11
- package/lib/lcevc/lcevc_dec.js +220 -0
- package/lib/media/adaptation_set.js +32 -14
- package/lib/media/adaptation_set_criteria.js +86 -16
- package/lib/media/closed_caption_parser.js +13 -0
- package/lib/media/content_workarounds.js +6 -0
- package/lib/media/drm_engine.js +8 -13
- package/lib/media/manifest_parser.js +8 -113
- package/lib/media/media_source_capabilities.js +10 -3
- package/lib/media/media_source_engine.js +286 -44
- package/lib/media/play_rate_controller.js +8 -38
- package/lib/media/presentation_timeline.js +7 -1
- package/lib/media/quality_observer.js +1 -1
- package/lib/media/segment_index.js +6 -6
- package/lib/media/segment_prefetch.js +92 -24
- package/lib/media/segment_reference.js +73 -7
- package/lib/media/segment_utils.js +343 -0
- package/lib/media/stall_detector.js +0 -3
- package/lib/media/streaming_engine.js +73 -38
- package/lib/mss/mss_parser.js +19 -2
- package/lib/net/networking_engine.js +67 -12
- package/lib/net/networking_utils.js +95 -0
- package/lib/offline/indexeddb/v1_storage_cell.js +3 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +3 -0
- package/lib/offline/manifest_converter.js +3 -0
- package/lib/offline/offline_manifest_parser.js +10 -0
- package/lib/offline/storage.js +14 -7
- package/lib/player.js +1098 -1537
- package/lib/polyfill/mediasource.js +22 -1
- package/lib/text/cue.js +15 -0
- package/lib/text/mp4_ttml_parser.js +2 -2
- package/lib/text/srt_text_parser.js +2 -2
- package/lib/text/stub_text_displayer.js +51 -0
- package/lib/text/text_engine.js +3 -2
- package/lib/text/ttml_text_parser.js +45 -5
- package/lib/text/ui_text_displayer.js +8 -0
- package/lib/text/vtt_text_parser.js +40 -22
- package/lib/transmuxer/aac_transmuxer.js +1 -1
- package/lib/transmuxer/ac3_transmuxer.js +1 -1
- package/lib/transmuxer/ec3_transmuxer.js +1 -1
- package/lib/transmuxer/h264.js +5 -4
- package/lib/transmuxer/h265.js +863 -0
- package/lib/transmuxer/mp3_transmuxer.js +1 -1
- package/lib/transmuxer/mpeg_ts_transmuxer.js +4 -3
- package/lib/transmuxer/mss_transmuxer.js +1 -1
- package/lib/transmuxer/ts_transmuxer.js +187 -22
- package/lib/util/buffer_utils.js +26 -4
- package/lib/util/content_steering_manager.js +358 -0
- package/lib/util/error.js +30 -15
- package/lib/util/exp_golomb.js +30 -2
- package/lib/util/fairplay_utils.js +1 -1
- package/lib/util/fake_event.js +8 -1
- package/lib/util/id3_utils.js +50 -1
- package/lib/util/manifest_parser_utils.js +12 -8
- package/lib/util/mp4_generator.js +6 -8
- package/lib/util/mutex.js +59 -0
- package/lib/util/object_utils.js +1 -1
- package/lib/util/periods.js +156 -179
- package/lib/util/platform.js +44 -3
- package/lib/util/player_configuration.js +43 -6
- package/lib/util/state_history.js +6 -2
- package/lib/util/stream_utils.js +206 -283
- package/lib/util/ts_parser.js +335 -98
- package/lib/util/uint8array_utils.js +5 -1
- package/lib/util/xml_utils.js +5 -0
- package/maintained-branches.md +3 -2
- package/package.json +4 -6
- package/roadmap.md +25 -5
- package/shaka-player.uncompiled.js +2 -2
- package/support.html +0 -1
- package/test/abr/simple_abr_manager_unit.js +33 -33
- package/test/ads/ad_manager_unit.js +3 -2
- package/test/cast/cast_receiver_integration.js +50 -4
- package/test/cast/cast_utils_unit.js +2 -0
- package/test/cea/cea_decoder_unit.js +7 -0
- package/test/codec_switching/codec_switching_integration.js +182 -0
- package/test/dash/dash_parser_content_protection_unit.js +2 -0
- package/test/dash/dash_parser_integration.js +74 -0
- package/test/dash/dash_parser_live_unit.js +2 -19
- package/test/dash/dash_parser_manifest_unit.js +536 -2
- package/test/dash/dash_parser_segment_base_unit.js +2 -0
- package/test/dash/dash_parser_segment_list_unit.js +2 -0
- package/test/dash/dash_parser_segment_template_unit.js +2 -0
- package/test/dash/mpd_utils_unit.js +61 -30
- package/test/demo/demo_unit.js +0 -16
- package/test/hls/hls_live_unit.js +14 -3
- package/test/hls/hls_parser_unit.js +385 -33
- package/test/hls/manifest_text_parser_unit.js +32 -99
- package/test/media/adaptation_set_criteria_unit.js +284 -15
- package/test/media/adaptation_set_unit.js +2 -0
- package/test/media/content_workarounds_unit.js +1 -1
- package/test/media/drm_engine_unit.js +3 -3
- package/test/media/media_source_engine_unit.js +166 -2
- package/test/media/play_rate_controller_unit.js +0 -48
- package/test/media/segment_index_unit.js +5 -4
- package/test/media/segment_prefetch_unit.js +1 -1
- package/test/media/streaming_engine_unit.js +17 -17
- package/test/mss/mss_parser_unit.js +2 -0
- package/test/mss/mss_player_integration.js +3 -2
- package/test/net/networking_engine_unit.js +3 -3
- package/test/{media/manifest_parser_unit.js → net/networking_utils_unit.js} +2 -2
- package/test/offline/manifest_convert_unit.js +14 -0
- package/test/offline/offline_integration.js +2 -1
- package/test/offline/storage_integration.js +22 -13
- package/test/player_external.js +4 -2
- package/test/player_integration.js +15 -4
- package/test/player_load_graph_integration.js +47 -151
- package/test/player_src_equals_external.js +1 -0
- package/test/player_src_equals_integration.js +71 -4
- package/test/player_unit.js +182 -158
- package/test/test/assets/dash-aes-128/Fragments(video=0,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=20000000,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=40000000,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=60000000,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=i,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/dash.mpd +18 -0
- package/test/test/assets/dash-aes-128/license +1 -0
- package/test/test/assets/dash-multi-codec/audio_en_2c_128k_aac.mp4 +0 -0
- package/test/test/assets/dash-multi-codec/audio_es_2c_64k_opus.webm +0 -0
- package/test/test/assets/dash-multi-codec/dash.mpd +32 -0
- package/test/test/assets/dash-multi-codec/video_144p_108k_h264.mp4 +0 -0
- package/test/test/assets/hls-ts-h265/0.ts +0 -0
- package/test/test/assets/hls-ts-h265/hevc.m3u8 +6 -0
- package/test/test/assets/hls-ts-h265/index.m3u8 +7 -0
- package/test/test/assets/hls-ts-muxed-aac-h265/0.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h265/1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 +9 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/media.m3u8 +24 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00000.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00001.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00002.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00003.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00004.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00005.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0000.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0001.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0002.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0003.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/prog_index.m3u8 +14 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/index.m3u8 +23 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-1-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-2-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-3-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-4-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-5-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-6-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-7-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-8-v1-a1.ts +0 -0
- package/test/test/util/dash_parser_util.js +4 -0
- package/test/test/util/fake_ad_manager.js +20 -0
- package/test/test/util/fake_media_source_engine.js +13 -2
- package/test/test/util/fake_networking_engine.js +9 -1
- package/test/test/util/fake_segment_prefetch.js +3 -0
- package/test/test/util/manifest_generator.js +11 -3
- package/test/test/util/manifest_parser_util.js +14 -2
- package/test/test/util/mss_parser_util.js +4 -0
- package/test/test/util/offline_utils.js +2 -0
- package/test/test/util/simple_fakes.js +2 -2
- package/test/test/util/streaming_engine_util.js +10 -4
- package/test/test/util/test_scheme.js +6 -0
- package/test/test/util/ui_utils.js +4 -3
- package/test/text/mp4_ttml_parser_unit.js +4 -4
- package/test/text/srt_text_parser_unit.js +1 -1
- package/test/text/text_displayer_layout_unit.js +1 -1
- package/test/text/text_engine_unit.js +6 -0
- package/test/text/ttml_text_parser_unit.js +85 -2
- package/test/text/vtt_text_parser_unit.js +103 -31
- package/test/transmuxer/transmuxer_engine_integration.js +9 -0
- package/test/transmuxer/transmuxer_integration.js +150 -3
- package/test/ui/ad_ui_unit.js +2 -2
- package/test/ui/ui_customization_unit.js +17 -16
- package/test/ui/ui_integration.js +30 -20
- package/test/ui/ui_unit.js +28 -29
- package/test/util/buffer_utils_unit.js +1 -1
- package/test/util/content_steering_manager_unit.js +427 -0
- package/test/util/id3_utils_unit.js +52 -0
- package/test/util/stream_utils_unit.js +207 -169
- package/test/util/ts_parser_unit.js +3 -3
- package/third_party/closure-uri/uri.js +13 -1
- package/ui/audio_language_selection.js +9 -2
- package/ui/controls.js +125 -0
- package/ui/externs/ui.js +24 -2
- package/ui/language_utils.js +43 -8
- package/ui/less/range_elements.less +33 -0
- package/ui/locales/en.json +1 -0
- package/ui/locales/es-419.json +1 -0
- package/ui/locales/es.json +1 -0
- package/ui/locales/source.json +4 -0
- package/ui/localization.js +10 -0
- package/ui/pip_button.js +22 -120
- package/ui/remote_button.js +203 -0
- package/ui/resolution_selection.js +47 -10
- package/ui/seek_bar.js +296 -3
- package/ui/text_selection.js +2 -1
- package/ui/ui.js +11 -4
- package/demo/common/message_ids.js +0 -309
- package/demo/locales/en.json +0 -288
- package/demo/locales/source.json +0 -1146
- package/externs/mux.js +0 -69
- package/lib/lcevc/lcevc_dil.js +0 -152
- package/lib/routing/node.js +0 -23
- package/lib/routing/payload.js +0 -43
- package/lib/routing/walker.js +0 -587
- package/lib/transmuxer/muxjs_transmuxer.js +0 -242
- package/test/routing/walker_unit.js +0 -504
- package/test/transmuxer/muxjs_transmuxer_integration.js +0 -177
package/ui/controls.js
CHANGED
|
@@ -643,6 +643,131 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
|
|
|
643
643
|
}
|
|
644
644
|
}
|
|
645
645
|
|
|
646
|
+
/**
|
|
647
|
+
* @return {boolean}
|
|
648
|
+
* @export
|
|
649
|
+
*/
|
|
650
|
+
isPiPAllowed() {
|
|
651
|
+
if ('documentPictureInPicture' in window &&
|
|
652
|
+
this.config_.preferDocumentPictureInPicture) {
|
|
653
|
+
return true;
|
|
654
|
+
}
|
|
655
|
+
if (document.pictureInPictureEnabled) {
|
|
656
|
+
const video = /** @type {HTMLVideoElement} */(this.localVideo_);
|
|
657
|
+
return !video.disablePictureInPicture;
|
|
658
|
+
}
|
|
659
|
+
return false;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* @return {boolean}
|
|
664
|
+
* @export
|
|
665
|
+
*/
|
|
666
|
+
isPiPEnabled() {
|
|
667
|
+
if ('documentPictureInPicture' in window &&
|
|
668
|
+
this.config_.preferDocumentPictureInPicture) {
|
|
669
|
+
return !!window.documentPictureInPicture.window;
|
|
670
|
+
} else {
|
|
671
|
+
return !!document.pictureInPictureElement;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
/** @export */
|
|
676
|
+
async togglePiP() {
|
|
677
|
+
try {
|
|
678
|
+
if ('documentPictureInPicture' in window &&
|
|
679
|
+
this.config_.preferDocumentPictureInPicture) {
|
|
680
|
+
await this.toggleDocumentPictureInPicture_();
|
|
681
|
+
} else if (!document.pictureInPictureElement) {
|
|
682
|
+
// If you were fullscreen, leave fullscreen first.
|
|
683
|
+
if (document.fullscreenElement) {
|
|
684
|
+
document.exitFullscreen();
|
|
685
|
+
}
|
|
686
|
+
const video = /** @type {HTMLVideoElement} */(this.localVideo_);
|
|
687
|
+
await video.requestPictureInPicture();
|
|
688
|
+
} else {
|
|
689
|
+
await document.exitPictureInPicture();
|
|
690
|
+
}
|
|
691
|
+
} catch (error) {
|
|
692
|
+
this.dispatchEvent(new shaka.util.FakeEvent(
|
|
693
|
+
'error', (new Map()).set('detail', error)));
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* The Document Picture-in-Picture API makes it possible to open an
|
|
699
|
+
* always-on-top window that can be populated with arbitrary HTML content.
|
|
700
|
+
* https://developer.chrome.com/docs/web-platform/document-picture-in-picture
|
|
701
|
+
* @private
|
|
702
|
+
*/
|
|
703
|
+
async toggleDocumentPictureInPicture_() {
|
|
704
|
+
// Close Picture-in-Picture window if any.
|
|
705
|
+
if (window.documentPictureInPicture.window) {
|
|
706
|
+
window.documentPictureInPicture.window.close();
|
|
707
|
+
return;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// Open a Picture-in-Picture window.
|
|
711
|
+
const pipPlayer = this.videoContainer_;
|
|
712
|
+
const rectPipPlayer = pipPlayer.getBoundingClientRect();
|
|
713
|
+
const pipWindow = await window.documentPictureInPicture.requestWindow({
|
|
714
|
+
width: rectPipPlayer.width,
|
|
715
|
+
height: rectPipPlayer.height,
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
// Copy style sheets to the Picture-in-Picture window.
|
|
719
|
+
this.copyStyleSheetsToWindow_(pipWindow);
|
|
720
|
+
|
|
721
|
+
// Add placeholder for the player.
|
|
722
|
+
const parentPlayer = pipPlayer.parentNode || document.body;
|
|
723
|
+
const placeholder = this.videoContainer_.cloneNode(true);
|
|
724
|
+
placeholder.style.visibility = 'hidden';
|
|
725
|
+
placeholder.style.height = getComputedStyle(pipPlayer).height;
|
|
726
|
+
parentPlayer.appendChild(placeholder);
|
|
727
|
+
|
|
728
|
+
// Make sure player fits in the Picture-in-Picture window.
|
|
729
|
+
const styles = document.createElement('style');
|
|
730
|
+
styles.append(`[data-shaka-player-container] {
|
|
731
|
+
width: 100% !important; max-height: 100%}`);
|
|
732
|
+
pipWindow.document.head.append(styles);
|
|
733
|
+
|
|
734
|
+
// Move player to the Picture-in-Picture window.
|
|
735
|
+
pipWindow.document.body.append(pipPlayer);
|
|
736
|
+
|
|
737
|
+
// Listen for the PiP closing event to move the player back.
|
|
738
|
+
this.eventManager_.listenOnce(pipWindow, 'pagehide', () => {
|
|
739
|
+
placeholder.replaceWith(/** @type {!Node} */(pipPlayer));
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
/** @private */
|
|
744
|
+
copyStyleSheetsToWindow_(win) {
|
|
745
|
+
const styleSheets = /** @type {!Iterable<*>} */(document.styleSheets);
|
|
746
|
+
const allCSS = [...styleSheets]
|
|
747
|
+
.map((sheet) => {
|
|
748
|
+
try {
|
|
749
|
+
return [...sheet.cssRules].map((rule) => rule.cssText).join('');
|
|
750
|
+
} catch (e) {
|
|
751
|
+
const link = /** @type {!HTMLLinkElement} */(
|
|
752
|
+
document.createElement('link'));
|
|
753
|
+
|
|
754
|
+
link.rel = 'stylesheet';
|
|
755
|
+
link.type = sheet.type;
|
|
756
|
+
link.media = sheet.media;
|
|
757
|
+
link.href = sheet.href;
|
|
758
|
+
win.document.head.appendChild(link);
|
|
759
|
+
}
|
|
760
|
+
return '';
|
|
761
|
+
})
|
|
762
|
+
.filter(Boolean)
|
|
763
|
+
.join('\n');
|
|
764
|
+
const style = document.createElement('style');
|
|
765
|
+
|
|
766
|
+
style.textContent = allCSS;
|
|
767
|
+
win.document.head.appendChild(style);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
|
|
646
771
|
/** @export */
|
|
647
772
|
showAdUI() {
|
|
648
773
|
shaka.ui.Utils.setDisplay(this.adPanel_, true);
|
package/ui/externs/ui.js
CHANGED
|
@@ -21,7 +21,9 @@ shaka.extern = {};
|
|
|
21
21
|
* base: string,
|
|
22
22
|
* buffered: string,
|
|
23
23
|
* played: string,
|
|
24
|
-
* adBreaks: string
|
|
24
|
+
* adBreaks: string,
|
|
25
|
+
* chapterMarks: string,
|
|
26
|
+
* chapterLabels: string
|
|
25
27
|
* }}
|
|
26
28
|
*
|
|
27
29
|
* @property {string} base
|
|
@@ -36,6 +38,13 @@ shaka.extern = {};
|
|
|
36
38
|
* @property {string} adBreaks
|
|
37
39
|
* The CSS background color applied to the portion of the seek bar showing
|
|
38
40
|
* when the ad breaks are scheduled to occur on the timeline.
|
|
41
|
+
* @property {string} chapterMarks
|
|
42
|
+
* The CSS border color applied to sections of the seek bar showing
|
|
43
|
+
* when the chapters start and end on the timeline.
|
|
44
|
+
* Defaults to dark grey rgb(27, 27, 27).
|
|
45
|
+
* @property {string} chapterLabels
|
|
46
|
+
* The CSS text color applied to the chapter labels that appear above the
|
|
47
|
+
* seek bar on hover. Defaults to white rgb(255, 255, 255).
|
|
39
48
|
* @exportDoc
|
|
40
49
|
*/
|
|
41
50
|
shaka.extern.UISeekBarColors;
|
|
@@ -87,7 +96,9 @@ shaka.extern.UIVolumeBarColors;
|
|
|
87
96
|
* enableTooltips: boolean,
|
|
88
97
|
* keyboardSeekDistance: number,
|
|
89
98
|
* keyboardLargeSeekDistance: number,
|
|
90
|
-
* fullScreenElement: HTMLElement
|
|
99
|
+
* fullScreenElement: HTMLElement,
|
|
100
|
+
* preferDocumentPictureInPicture: boolean,
|
|
101
|
+
* showAudioChannelCountVariants: boolean
|
|
91
102
|
* }}
|
|
92
103
|
*
|
|
93
104
|
* @property {!Array.<string>} controlPanelElements
|
|
@@ -193,6 +204,17 @@ shaka.extern.UIVolumeBarColors;
|
|
|
193
204
|
* @property {HTMLElement} fullScreenElement
|
|
194
205
|
* DOM element on which fullscreen will be done.
|
|
195
206
|
* Defaults to Shaka Player Container.
|
|
207
|
+
* @property {boolean} preferDocumentPictureInPicture
|
|
208
|
+
* Indicates whether the Document Picture in Picture API is preferred or the
|
|
209
|
+
* Video Element Picture in Picture API is preferred.
|
|
210
|
+
* Changing this property in mid-playback may produce undesired behavior if
|
|
211
|
+
* you are already in PiP.
|
|
212
|
+
* Defaults to true.
|
|
213
|
+
* @property {boolean} showAudioChannelCountVariants
|
|
214
|
+
* Indicates whether the combination of language and channel count should be
|
|
215
|
+
* displayed or if, on the contrary, only the language should be displayed
|
|
216
|
+
* regardless of the channel count.
|
|
217
|
+
* Defaults to true.
|
|
196
218
|
* @exportDoc
|
|
197
219
|
*/
|
|
198
220
|
shaka.extern.UIConfiguration;
|
package/ui/language_utils.js
CHANGED
|
@@ -26,9 +26,13 @@ shaka.ui.LanguageUtils = class {
|
|
|
26
26
|
* @param {!HTMLElement} currentSelectionElement
|
|
27
27
|
* @param {shaka.ui.Localization} localization
|
|
28
28
|
* @param {shaka.ui.Overlay.TrackLabelFormat} trackLabelFormat
|
|
29
|
+
* @param {boolean} showAudioChannelCountVariants
|
|
29
30
|
*/
|
|
30
31
|
static updateTracks(tracks, langMenu, onTrackSelected, updateChosen,
|
|
31
|
-
currentSelectionElement, localization, trackLabelFormat
|
|
32
|
+
currentSelectionElement, localization, trackLabelFormat,
|
|
33
|
+
showAudioChannelCountVariants) {
|
|
34
|
+
const LocIds = shaka.ui.Locales.Ids;
|
|
35
|
+
|
|
32
36
|
// TODO: Do the benefits of having this common code in a method still
|
|
33
37
|
// outweigh the complexity of the parameter list?
|
|
34
38
|
const selectedTrack = tracks.find((track) => {
|
|
@@ -55,8 +59,27 @@ shaka.ui.LanguageUtils = class {
|
|
|
55
59
|
}
|
|
56
60
|
};
|
|
57
61
|
|
|
58
|
-
const getCombination = (language, rolesString) => {
|
|
59
|
-
|
|
62
|
+
const getCombination = (language, rolesString, label, channelsCount) => {
|
|
63
|
+
const keys = [
|
|
64
|
+
language,
|
|
65
|
+
rolesString,
|
|
66
|
+
];
|
|
67
|
+
if (showAudioChannelCountVariants && channelsCount != null) {
|
|
68
|
+
keys.push(channelsCount);
|
|
69
|
+
}
|
|
70
|
+
if (label &&
|
|
71
|
+
trackLabelFormat == shaka.ui.Overlay.TrackLabelFormat.LABEL) {
|
|
72
|
+
keys.push(label);
|
|
73
|
+
}
|
|
74
|
+
return keys.join(': ');
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const getChannelsCountName = (channelsCount) => {
|
|
78
|
+
let name = '';
|
|
79
|
+
if (channelsCount >= 5) {
|
|
80
|
+
name = ' ' + localization.resolve(LocIds.SURROUND);
|
|
81
|
+
}
|
|
82
|
+
return name;
|
|
60
83
|
};
|
|
61
84
|
|
|
62
85
|
/** @type {!Map.<string, !Set.<string>>} */
|
|
@@ -72,15 +95,18 @@ shaka.ui.LanguageUtils = class {
|
|
|
72
95
|
/** @type {!Set.<string>} */
|
|
73
96
|
const combinationsMade = new Set();
|
|
74
97
|
const selectedCombination = selectedTrack ? getCombination(
|
|
75
|
-
selectedTrack.language, getRolesString(selectedTrack)
|
|
98
|
+
selectedTrack.language, getRolesString(selectedTrack),
|
|
99
|
+
selectedTrack.label, selectedTrack.channelsCount) : '';
|
|
76
100
|
|
|
77
101
|
for (const track of tracks) {
|
|
78
102
|
const language = track.language;
|
|
79
103
|
const forced = track.forced;
|
|
80
|
-
const LocIds = shaka.ui.Locales.Ids;
|
|
81
104
|
const forcedString = localization.resolve(LocIds.SUBTITLE_FORCED);
|
|
82
105
|
const rolesString = getRolesString(track);
|
|
83
|
-
const
|
|
106
|
+
const label = track.label;
|
|
107
|
+
const channelsCount = track.channelsCount;
|
|
108
|
+
const combinationName =
|
|
109
|
+
getCombination(language, rolesString, label, channelsCount);
|
|
84
110
|
if (combinationsMade.has(combinationName)) {
|
|
85
111
|
continue;
|
|
86
112
|
}
|
|
@@ -98,11 +124,17 @@ shaka.ui.LanguageUtils = class {
|
|
|
98
124
|
shaka.ui.LanguageUtils.getLanguageName(language, localization);
|
|
99
125
|
switch (trackLabelFormat) {
|
|
100
126
|
case shaka.ui.Overlay.TrackLabelFormat.LANGUAGE:
|
|
127
|
+
if (showAudioChannelCountVariants) {
|
|
128
|
+
span.textContent += getChannelsCountName(channelsCount);
|
|
129
|
+
}
|
|
101
130
|
if (forced) {
|
|
102
131
|
span.textContent += ' (' + forcedString + ')';
|
|
103
132
|
}
|
|
104
133
|
break;
|
|
105
134
|
case shaka.ui.Overlay.TrackLabelFormat.ROLE:
|
|
135
|
+
if (showAudioChannelCountVariants) {
|
|
136
|
+
span.textContent += getChannelsCountName(channelsCount);
|
|
137
|
+
}
|
|
106
138
|
if (!rolesString) {
|
|
107
139
|
// Fallback behavior. This probably shouldn't happen.
|
|
108
140
|
shaka.log.alwaysWarn('Track #' + track.id + ' does not have a ' +
|
|
@@ -116,6 +148,9 @@ shaka.ui.LanguageUtils = class {
|
|
|
116
148
|
}
|
|
117
149
|
break;
|
|
118
150
|
case shaka.ui.Overlay.TrackLabelFormat.LANGUAGE_ROLE:
|
|
151
|
+
if (showAudioChannelCountVariants) {
|
|
152
|
+
span.textContent += getChannelsCountName(channelsCount);
|
|
153
|
+
}
|
|
119
154
|
if (rolesString) {
|
|
120
155
|
span.textContent += ': ' + rolesString;
|
|
121
156
|
}
|
|
@@ -124,8 +159,8 @@ shaka.ui.LanguageUtils = class {
|
|
|
124
159
|
}
|
|
125
160
|
break;
|
|
126
161
|
case shaka.ui.Overlay.TrackLabelFormat.LABEL:
|
|
127
|
-
if (
|
|
128
|
-
span.textContent =
|
|
162
|
+
if (label) {
|
|
163
|
+
span.textContent = label;
|
|
129
164
|
} else {
|
|
130
165
|
// Fallback behavior. This probably shouldn't happen.
|
|
131
166
|
shaka.log.alwaysWarn('Track #' + track.id + ' does not have a ' +
|
|
@@ -154,3 +154,36 @@
|
|
|
154
154
|
.shaka-ad-markers {
|
|
155
155
|
.overlay-child();
|
|
156
156
|
}
|
|
157
|
+
|
|
158
|
+
#shaka-player-ui-chapters-container {
|
|
159
|
+
width: 100%;
|
|
160
|
+
height: 100%;
|
|
161
|
+
display: flex;
|
|
162
|
+
flex-direction: row;
|
|
163
|
+
z-index: 0;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.shaka-chapter {
|
|
167
|
+
height: 100%;
|
|
168
|
+
position: relative;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.shaka-chapter-label {
|
|
172
|
+
position: relative;
|
|
173
|
+
top: -2.5em;
|
|
174
|
+
width: 100%;
|
|
175
|
+
text-align: center;
|
|
176
|
+
text-shadow: 1px 1px gray;
|
|
177
|
+
line-height: normal;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.shaka-chapter > div:first-child {
|
|
181
|
+
width: 100%;
|
|
182
|
+
height: 100%;
|
|
183
|
+
border-right: 1px solid;
|
|
184
|
+
position: absolute;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.shaka-chapter:last-child > div:first-child {
|
|
188
|
+
border-right: none;
|
|
189
|
+
}
|
package/ui/locales/en.json
CHANGED
package/ui/locales/es-419.json
CHANGED
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"SKIP_AD": "Omitir anuncio",
|
|
33
33
|
"SKIP_TO_LIVE": "Adelantar hasta la transmisión en vivo",
|
|
34
34
|
"SUBTITLE_FORCED": "Forzado",
|
|
35
|
+
"SURROUND": "Envolvente",
|
|
35
36
|
"UNDETERMINED_LANGUAGE": "Sin especificar",
|
|
36
37
|
"UNMUTE": "Dejar de silenciar",
|
|
37
38
|
"UNRECOGNIZED_LANGUAGE": "No reconocida",
|
package/ui/locales/es.json
CHANGED
package/ui/locales/source.json
CHANGED
|
@@ -151,6 +151,10 @@
|
|
|
151
151
|
"description": "Label used to identify a subtitle track that is forced to be shown.",
|
|
152
152
|
"message": "Forced"
|
|
153
153
|
},
|
|
154
|
+
"SURROUND": {
|
|
155
|
+
"description": "Label used to identify a audio track that has surround audio.",
|
|
156
|
+
"message": "Surround"
|
|
157
|
+
},
|
|
154
158
|
"UNDETERMINED_LANGUAGE": {
|
|
155
159
|
"description": "Label for a button used to select an audio track whose language is undetermined or unknown.",
|
|
156
160
|
"message": "Undetermined"
|
package/ui/localization.js
CHANGED
|
@@ -230,6 +230,16 @@ shaka.ui.Localization = class extends shaka.util.FakeEventTarget {
|
|
|
230
230
|
return '';
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
+
/**
|
|
234
|
+
* The locales currently used. An empty set means "no preference".
|
|
235
|
+
*
|
|
236
|
+
* @return {!Set.<string>}
|
|
237
|
+
* @export
|
|
238
|
+
*/
|
|
239
|
+
getCurrentLocales() {
|
|
240
|
+
return this.currentLocales_;
|
|
241
|
+
}
|
|
242
|
+
|
|
233
243
|
/**
|
|
234
244
|
* @private
|
|
235
245
|
*/
|
package/ui/pip_button.js
CHANGED
|
@@ -16,7 +16,6 @@ goog.require('shaka.ui.Localization');
|
|
|
16
16
|
goog.require('shaka.ui.OverflowMenu');
|
|
17
17
|
goog.require('shaka.ui.Utils');
|
|
18
18
|
goog.require('shaka.util.Dom');
|
|
19
|
-
goog.require('shaka.util.FakeEvent');
|
|
20
19
|
goog.requireType('shaka.ui.Controls');
|
|
21
20
|
|
|
22
21
|
|
|
@@ -73,7 +72,7 @@ shaka.ui.PipButton = class extends shaka.ui.Element {
|
|
|
73
72
|
// Don't display the button if PiP is not supported or not allowed.
|
|
74
73
|
// TODO: Can this ever change? Is it worth creating the button if the below
|
|
75
74
|
// condition is true?
|
|
76
|
-
if (!this.
|
|
75
|
+
if (!this.controls.isPiPAllowed()) {
|
|
77
76
|
shaka.ui.Utils.setDisplay(this.pipButton_, false);
|
|
78
77
|
}
|
|
79
78
|
|
|
@@ -88,7 +87,7 @@ shaka.ui.PipButton = class extends shaka.ui.Element {
|
|
|
88
87
|
});
|
|
89
88
|
|
|
90
89
|
this.eventManager.listen(this.pipButton_, 'click', () => {
|
|
91
|
-
this.
|
|
90
|
+
this.controls.togglePiP();
|
|
92
91
|
});
|
|
93
92
|
|
|
94
93
|
this.eventManager.listen(this.localVideo_, 'enterpictureinpicture', () => {
|
|
@@ -106,119 +105,21 @@ shaka.ui.PipButton = class extends shaka.ui.Element {
|
|
|
106
105
|
this.eventManager.listen(this.player, 'trackschanged', () => {
|
|
107
106
|
this.onTracksChanged_();
|
|
108
107
|
});
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* @return {boolean}
|
|
114
|
-
* @private
|
|
115
|
-
*/
|
|
116
|
-
isPipAllowed_() {
|
|
117
|
-
return ('documentPictureInPicture' in window) ||
|
|
118
|
-
(document.pictureInPictureEnabled && !this.video.disablePictureInPicture);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
108
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
// If you were fullscreen, leave fullscreen first.
|
|
134
|
-
if (document.fullscreenElement) {
|
|
135
|
-
document.exitFullscreen();
|
|
136
|
-
}
|
|
137
|
-
await this.video.requestPictureInPicture();
|
|
138
|
-
} else {
|
|
139
|
-
await document.exitPictureInPicture();
|
|
140
|
-
}
|
|
141
|
-
} catch (error) {
|
|
142
|
-
this.controls.dispatchEvent(new shaka.util.FakeEvent(
|
|
143
|
-
'error', (new Map()).set('detail', error)));
|
|
109
|
+
if ('documentPictureInPicture' in window) {
|
|
110
|
+
this.eventManager.listen(window.documentPictureInPicture, 'enter',
|
|
111
|
+
(e) => {
|
|
112
|
+
this.onEnterPictureInPicture_();
|
|
113
|
+
|
|
114
|
+
const event = /** @type {DocumentPictureInPictureEvent} */(e);
|
|
115
|
+
const pipWindow = event.window;
|
|
116
|
+
this.eventManager.listenOnce(pipWindow, 'pagehide', () => {
|
|
117
|
+
this.onLeavePictureInPicture_();
|
|
118
|
+
});
|
|
119
|
+
});
|
|
144
120
|
}
|
|
145
121
|
}
|
|
146
122
|
|
|
147
|
-
/**
|
|
148
|
-
* The Document Picture-in-Picture API makes it possible to open an
|
|
149
|
-
* always-on-top window that can be populated with arbitrary HTML content.
|
|
150
|
-
* https://developer.chrome.com/docs/web-platform/document-picture-in-picture
|
|
151
|
-
* @private
|
|
152
|
-
*/
|
|
153
|
-
async toggleDocumentPictureInPicture_() {
|
|
154
|
-
// Close Picture-in-Picture window if any.
|
|
155
|
-
if (window.documentPictureInPicture.window) {
|
|
156
|
-
window.documentPictureInPicture.window.close();
|
|
157
|
-
this.onLeavePictureInPicture_();
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Open a Picture-in-Picture window.
|
|
162
|
-
const pipPlayer = this.videoContainer_;
|
|
163
|
-
const rectPipPlayer = pipPlayer.getBoundingClientRect();
|
|
164
|
-
const pipWindow = await window.documentPictureInPicture.requestWindow({
|
|
165
|
-
width: rectPipPlayer.width,
|
|
166
|
-
height: rectPipPlayer.height,
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
// Copy style sheets to the Picture-in-Picture window.
|
|
170
|
-
this.copyStyleSheetsToWindow_(pipWindow);
|
|
171
|
-
|
|
172
|
-
// Add placeholder for the player.
|
|
173
|
-
const parentPlayer = pipPlayer.parentNode || document.body;
|
|
174
|
-
const placeholder = this.videoContainer_.cloneNode(true);
|
|
175
|
-
placeholder.style.visibility = 'hidden';
|
|
176
|
-
placeholder.style.height = getComputedStyle(pipPlayer).height;
|
|
177
|
-
parentPlayer.appendChild(placeholder);
|
|
178
|
-
|
|
179
|
-
// Make sure player fits in the Picture-in-Picture window.
|
|
180
|
-
const styles = document.createElement('style');
|
|
181
|
-
styles.append(`[data-shaka-player-container] {
|
|
182
|
-
width: 100% !important; max-height: 100%}`);
|
|
183
|
-
pipWindow.document.head.append(styles);
|
|
184
|
-
|
|
185
|
-
// Move player to the Picture-in-Picture window.
|
|
186
|
-
pipWindow.document.body.append(pipPlayer);
|
|
187
|
-
this.onEnterPictureInPicture_();
|
|
188
|
-
|
|
189
|
-
// Listen for the PiP closing event to move the player back.
|
|
190
|
-
this.eventManager.listenOnce(pipWindow, 'pagehide', () => {
|
|
191
|
-
placeholder.replaceWith(/** @type {!Node} */(pipPlayer));
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/** @private */
|
|
196
|
-
copyStyleSheetsToWindow_(win) {
|
|
197
|
-
const styleSheets = /** @type {!Iterable<*>} */(document.styleSheets);
|
|
198
|
-
const allCSS = [...styleSheets]
|
|
199
|
-
.map((sheet) => {
|
|
200
|
-
try {
|
|
201
|
-
return [...sheet.cssRules].map((rule) => rule.cssText).join('');
|
|
202
|
-
} catch (e) {
|
|
203
|
-
const link = /** @type {!HTMLLinkElement} */(
|
|
204
|
-
document.createElement('link'));
|
|
205
|
-
|
|
206
|
-
link.rel = 'stylesheet';
|
|
207
|
-
link.type = sheet.type;
|
|
208
|
-
link.media = sheet.media;
|
|
209
|
-
link.href = sheet.href;
|
|
210
|
-
win.document.head.appendChild(link);
|
|
211
|
-
}
|
|
212
|
-
return '';
|
|
213
|
-
})
|
|
214
|
-
.filter(Boolean)
|
|
215
|
-
.join('\n');
|
|
216
|
-
const style = document.createElement('style');
|
|
217
|
-
|
|
218
|
-
style.textContent = allCSS;
|
|
219
|
-
win.document.head.appendChild(style);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
123
|
/** @private */
|
|
223
124
|
onEnterPictureInPicture_() {
|
|
224
125
|
const LocIds = shaka.ui.Locales.Ids;
|
|
@@ -250,13 +151,14 @@ shaka.ui.PipButton = class extends shaka.ui.Element {
|
|
|
250
151
|
this.pipNameSpan_.textContent =
|
|
251
152
|
this.localization.resolve(LocIds.PICTURE_IN_PICTURE);
|
|
252
153
|
|
|
253
|
-
const
|
|
154
|
+
const enabled = this.controls.isPiPEnabled();
|
|
155
|
+
|
|
156
|
+
const ariaLabel = enabled ?
|
|
254
157
|
LocIds.EXIT_PICTURE_IN_PICTURE :
|
|
255
158
|
LocIds.ENTER_PICTURE_IN_PICTURE;
|
|
256
159
|
this.pipButton_.ariaLabel = this.localization.resolve(ariaLabel);
|
|
257
160
|
|
|
258
|
-
const currentPipState =
|
|
259
|
-
LocIds.ON : LocIds.OFF;
|
|
161
|
+
const currentPipState = enabled ? LocIds.ON : LocIds.OFF;
|
|
260
162
|
|
|
261
163
|
this.currentPipState_.textContent =
|
|
262
164
|
this.localization.resolve(currentPipState);
|
|
@@ -271,11 +173,11 @@ shaka.ui.PipButton = class extends shaka.ui.Element {
|
|
|
271
173
|
|
|
272
174
|
if (isCasting) {
|
|
273
175
|
// Picture-in-picture is not applicable if we're casting
|
|
274
|
-
if (this.
|
|
176
|
+
if (this.controls.isPiPAllowed()) {
|
|
275
177
|
shaka.ui.Utils.setDisplay(this.pipButton_, false);
|
|
276
178
|
}
|
|
277
179
|
} else {
|
|
278
|
-
if (this.
|
|
180
|
+
if (this.controls.isPiPAllowed()) {
|
|
279
181
|
shaka.ui.Utils.setDisplay(this.pipButton_, true);
|
|
280
182
|
}
|
|
281
183
|
}
|
|
@@ -290,12 +192,12 @@ shaka.ui.PipButton = class extends shaka.ui.Element {
|
|
|
290
192
|
* @private
|
|
291
193
|
*/
|
|
292
194
|
async onTracksChanged_() {
|
|
293
|
-
if (!this.
|
|
195
|
+
if (!this.controls.isPiPAllowed()) {
|
|
294
196
|
shaka.ui.Utils.setDisplay(this.pipButton_, false);
|
|
295
197
|
} else if (this.player && this.player.isAudioOnly()) {
|
|
296
198
|
shaka.ui.Utils.setDisplay(this.pipButton_, false);
|
|
297
|
-
if (
|
|
298
|
-
await
|
|
199
|
+
if (this.controls.isPiPEnabled()) {
|
|
200
|
+
await this.controls.togglePiP();
|
|
299
201
|
}
|
|
300
202
|
} else {
|
|
301
203
|
shaka.ui.Utils.setDisplay(this.pipButton_, true);
|