Source: lib/device/default_browser.js

  1. /*! @license
  2. * Shaka Player
  3. * Copyright 2025 Google LLC
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. goog.provide('shaka.device.DefaultBrowser');
  7. goog.require('shaka.debug.RunningInLab');
  8. goog.require('shaka.device.AbstractDevice');
  9. goog.require('shaka.device.DeviceFactory');
  10. goog.require('shaka.device.IDevice');
  11. goog.require('shaka.drm.DrmUtils');
  12. goog.require('shaka.util.Lazy');
  13. /**
  14. * @final
  15. */
  16. shaka.device.DefaultBrowser = class extends shaka.device.AbstractDevice {
  17. constructor() {
  18. super();
  19. /** @private {!shaka.util.Lazy<?number>} */
  20. this.version_ = new shaka.util.Lazy(() => {
  21. // Looking for something like "Chrome/106.0.0.0" or Firefox/135.0
  22. const match = navigator.userAgent.match(/(Chrome|Firefox)\/(\d+)/);
  23. if (match) {
  24. return parseInt(match[2], /* base= */ 10);
  25. }
  26. return null;
  27. });
  28. /** @private {!shaka.util.Lazy<string>} */
  29. this.deviceName_ = new shaka.util.Lazy(() => {
  30. // Legacy Edge contains "Edge/version".
  31. // Chromium-based Edge contains "Edg/version" (no "e").
  32. if (navigator.userAgent.match(/Edge?\//)) {
  33. return 'Edge';
  34. } else if (navigator.userAgent.includes('Chrome')) {
  35. return 'Chrome';
  36. } else if (navigator.userAgent.includes('Firefox')) {
  37. return 'Firefox';
  38. }
  39. return 'Unknown';
  40. });
  41. /** @private {!shaka.util.Lazy<boolean>} */
  42. this.isWindows_ = new shaka.util.Lazy(() => {
  43. // Try the newer standard first.
  44. if (navigator.userAgentData && navigator.userAgentData.platform) {
  45. return navigator.userAgentData.platform.toLowerCase() == 'windows';
  46. }
  47. // Fall back to the old API, with less strict matching.
  48. if (!navigator.platform) {
  49. return false;
  50. }
  51. return navigator.platform.toLowerCase().includes('win32');
  52. });
  53. /** @private {!shaka.util.Lazy<boolean>} */
  54. this.supportsSmoothCodecSwitching_ = new shaka.util.Lazy(() => {
  55. if (!navigator.userAgent.match(/Edge?\//)) {
  56. return true;
  57. }
  58. return !this.isWindows_.value();
  59. });
  60. /** @private {!shaka.util.Lazy<boolean>} */
  61. this.isSonyTV_ = new shaka.util.Lazy(() => {
  62. return navigator.userAgent.includes('sony.hbbtv.tv.G5');
  63. });
  64. }
  65. /**
  66. * @override
  67. */
  68. getVersion() {
  69. return this.version_.value();
  70. }
  71. /**
  72. * @override
  73. */
  74. getDeviceName() {
  75. return this.deviceName_.value();
  76. }
  77. /**
  78. * @override
  79. */
  80. requiresEncryptionInfoInAllInitSegments(keySystem) {
  81. if (shaka.drm.DrmUtils.isPlayReadyKeySystem(keySystem)) {
  82. return this.deviceName_.value() === 'Edge' && this.isWindows_.value();
  83. }
  84. return false;
  85. }
  86. /**
  87. * @override
  88. */
  89. requiresClearAndEncryptedInitSegments() {
  90. return this.deviceName_.value() === 'Edge' && this.isWindows_.value();
  91. }
  92. /**
  93. * @override
  94. */
  95. insertEncryptionDataBeforeClear() {
  96. return this.deviceName_.value() === 'Edge' && this.isWindows_.value(); ;
  97. }
  98. /**
  99. * @override
  100. */
  101. supportsSmoothCodecSwitching() {
  102. return this.supportsSmoothCodecSwitching_.value();
  103. }
  104. /**
  105. * @override
  106. */
  107. adjustConfig(config) {
  108. super.adjustConfig(config);
  109. if (this.isWindows_.value()) {
  110. // Other browsers different than Edge only supports PlayReady with the
  111. // recommendation keysystem on Windows, so we do a direct mapping here.
  112. // Firefox supports PlayReady 2000 (SW) and 3000 (HW).
  113. // Chromium support PlayReady 3000 (HW) only.
  114. switch (this.deviceName_.value()) {
  115. case 'Firefox':
  116. config.drm.keySystemsMapping = {
  117. 'com.microsoft.playready':
  118. 'com.microsoft.playready.recommendation',
  119. };
  120. break;
  121. case 'Chrome':
  122. config.drm.keySystemsMapping = {
  123. 'com.microsoft.playready':
  124. 'com.microsoft.playready.recommendation.3000',
  125. 'com.microsoft.playready.recommendation':
  126. 'com.microsoft.playready.recommendation.3000',
  127. };
  128. break;
  129. }
  130. }
  131. return config;
  132. }
  133. /**
  134. * @override
  135. */
  136. returnLittleEndianUsingPlayReady() {
  137. return this.deviceName_.value() === 'Edge' || this.isSonyTV_.value();
  138. }
  139. /**
  140. * @override
  141. */
  142. createMediaKeysWhenCheckingSupport() {
  143. if (goog.DEBUG && shaka.debug.RunningInLab && this.isWindows_.value() &&
  144. this.getBrowserEngine() === shaka.device.IDevice.BrowserEngine.GECKO) {
  145. return false;
  146. }
  147. return true;
  148. }
  149. /**
  150. * @override
  151. */
  152. disableHEVCSupport() {
  153. // It seems that HEVC on Firefox Windows is incomplete.
  154. return this.isWindows_.value() &&
  155. this.getBrowserEngine() === shaka.device.IDevice.BrowserEngine.GECKO;
  156. }
  157. };
  158. shaka.device.DeviceFactory.registerDefaultDeviceFactory(
  159. () => new shaka.device.DefaultBrowser());