Source: ui/airplay_button.js

  1. /*! @license
  2. * Shaka Player
  3. * Copyright 2016 Google LLC
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. goog.provide('shaka.ui.AirPlayButton');
  7. goog.require('goog.asserts');
  8. goog.require('shaka.Player');
  9. goog.require('shaka.ui.Controls');
  10. goog.require('shaka.ui.Element');
  11. goog.require('shaka.ui.Enums');
  12. goog.require('shaka.ui.Locales');
  13. goog.require('shaka.ui.Localization');
  14. goog.require('shaka.ui.OverflowMenu');
  15. goog.require('shaka.ui.Utils');
  16. goog.require('shaka.util.Dom');
  17. goog.requireType('shaka.ui.Controls');
  18. /**
  19. * @extends {shaka.ui.Element}
  20. * @final
  21. * @export
  22. */
  23. shaka.ui.AirPlayButton = class extends shaka.ui.Element {
  24. /**
  25. * @param {!HTMLElement} parent
  26. * @param {!shaka.ui.Controls} controls
  27. */
  28. constructor(parent, controls) {
  29. super(parent, controls);
  30. /** @private {!HTMLButtonElement} */
  31. this.airplayButton_ = shaka.util.Dom.createButton();
  32. this.airplayButton_.classList.add('shaka-airplay-button');
  33. this.airplayButton_.classList.add('shaka-tooltip');
  34. this.airplayButton_.ariaPressed = 'false';
  35. /** @private {!HTMLElement} */
  36. this.airplayIcon_ = shaka.util.Dom.createHTMLElement('i');
  37. this.airplayIcon_.classList.add('material-icons-round');
  38. this.airplayIcon_.textContent = shaka.ui.Enums.MaterialDesignIcons.AIRPLAY;
  39. this.airplayButton_.appendChild(this.airplayIcon_);
  40. // Don't show the button if AirPlay is not supported.
  41. if (!window.WebKitPlaybackTargetAvailabilityEvent) {
  42. this.airplayButton_.classList.add('shaka-hidden');
  43. }
  44. const label = shaka.util.Dom.createHTMLElement('label');
  45. label.classList.add('shaka-overflow-button-label');
  46. label.classList.add('shaka-overflow-menu-only');
  47. this.airplayNameSpan_ = shaka.util.Dom.createHTMLElement('span');
  48. label.appendChild(this.airplayNameSpan_);
  49. this.airplayCurrentSelectionSpan_ =
  50. shaka.util.Dom.createHTMLElement('span');
  51. this.airplayCurrentSelectionSpan_.classList.add(
  52. 'shaka-current-selection-span');
  53. label.appendChild(this.airplayCurrentSelectionSpan_);
  54. this.airplayButton_.appendChild(label);
  55. this.parent.appendChild(this.airplayButton_);
  56. // Setup strings in the correct language
  57. this.updateLocalizedStrings_();
  58. // Setup button display and state according to the current airplay status
  59. this.onAirPlayStatusChange_();
  60. this.eventManager.listen(
  61. this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => {
  62. this.updateLocalizedStrings_();
  63. });
  64. this.eventManager.listen(
  65. this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => {
  66. this.updateLocalizedStrings_();
  67. });
  68. this.eventManager.listen(this.airplayButton_, 'click', () => {
  69. if (!this.controls.isOpaque()) {
  70. return;
  71. }
  72. this.onAirPlayClick_();
  73. });
  74. const video = this.controls.getVideo();
  75. goog.asserts.assert(video != null, 'Should have a video!');
  76. this.eventManager.listen(video,
  77. 'webkitplaybacktargetavailabilitychanged', (e) => {
  78. const event = /** @type {!AirPlayEvent} */ (e);
  79. this.onAirPlayAvailabilityChange_(event);
  80. });
  81. this.eventManager.listen(video,
  82. 'webkitcurrentplaybacktargetiswirelesschanged', () => {
  83. this.onAirPlayStatusChange_();
  84. });
  85. }
  86. /**
  87. * @private
  88. */
  89. onAirPlayClick_() {
  90. const video = this.controls.getVideo();
  91. goog.asserts.assert(video != null, 'Should have a video!');
  92. video.webkitShowPlaybackTargetPicker();
  93. }
  94. /**
  95. * @param {!AirPlayEvent} e
  96. * @private
  97. */
  98. onAirPlayAvailabilityChange_(e) {
  99. const canCast = e.availability == 'available';
  100. const loadMode = this.player.getLoadMode();
  101. const srcMode = loadMode == shaka.Player.LoadMode.SRC_EQUALS;
  102. shaka.ui.Utils.setDisplay(this.airplayButton_, canCast && srcMode);
  103. }
  104. /**
  105. * @private
  106. */
  107. onAirPlayStatusChange_() {
  108. const video = this.controls.getVideo();
  109. goog.asserts.assert(video != null, 'Should have a video!');
  110. const isCasting = video && video.webkitCurrentPlaybackTargetIsWireless;
  111. // Aria-pressed set to true when casting, set to false otherwise.
  112. if (isCasting) {
  113. this.airplayButton_.ariaPressed = 'true';
  114. } else {
  115. this.airplayButton_.ariaPressed = 'false';
  116. }
  117. }
  118. /**
  119. * @private
  120. */
  121. updateLocalizedStrings_() {
  122. const LocIds = shaka.ui.Locales.Ids;
  123. this.airplayButton_.ariaLabel = this.localization.resolve(LocIds.AIRPLAY);
  124. this.airplayNameSpan_.textContent =
  125. this.localization.resolve(LocIds.AIRPLAY);
  126. }
  127. };
  128. /**
  129. * @implements {shaka.extern.IUIElement.Factory}
  130. * @final
  131. */
  132. shaka.ui.AirPlayButton.Factory = class {
  133. /** @override */
  134. create(rootElement, controls) {
  135. return new shaka.ui.AirPlayButton(rootElement, controls);
  136. }
  137. };
  138. shaka.ui.OverflowMenu.registerElement(
  139. 'airplay', new shaka.ui.AirPlayButton.Factory());
  140. shaka.ui.Controls.registerElement(
  141. 'airplay', new shaka.ui.AirPlayButton.Factory());