@bvdmitri/gyroview 0.0.0-stage → 0.9.0-cutaway.2

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.
Files changed (302) hide show
  1. package/CHANGELOG.md +402 -0
  2. package/LICENSE +21 -0
  3. package/README.md +313 -2
  4. package/dist/define.d.ts +3 -0
  5. package/dist/define.js +4 -0
  6. package/dist/index.d.ts +1204 -0
  7. package/dist/index.js +12 -0
  8. package/dist/packages/adapters/blob/src/BlobRandomAccessSource.js +36 -0
  9. package/dist/packages/adapters/fetch/src/HttpByteStream.js +173 -0
  10. package/dist/packages/adapters/fetch/src/HttpRangeSource.js +37 -0
  11. package/dist/packages/adapters/fetch/src/HttpResource.js +227 -0
  12. package/dist/packages/adapters/fetch/src/HttpResourceLocator.js +35 -0
  13. package/dist/packages/adapters/fetch/src/contentRange.js +15 -0
  14. package/dist/packages/adapters/fetch/src/httpRequest.js +136 -0
  15. package/dist/packages/adapters/fetch/src/passingFailures.js +23 -0
  16. package/dist/packages/adapters/fetch/src/rangeFailures.js +16 -0
  17. package/dist/packages/adapters/fetch/src/recordingVersion.js +37 -0
  18. package/dist/packages/adapters/mediabunny/src/MediabunnyAudioPackager.js +162 -0
  19. package/dist/packages/adapters/mediabunny/src/MediabunnyCodecReader.js +93 -0
  20. package/dist/packages/adapters/mediabunny/src/SegmentChannel.js +135 -0
  21. package/dist/packages/adapters/mediabunny/src/bufferSources.js +12 -0
  22. package/dist/packages/adapters/mediabunny/src/decoderConfigurations.js +43 -0
  23. package/dist/packages/adapters/mediabunny/src/trackColour.js +20 -0
  24. package/dist/packages/adapters/mse-audio/src/MediaSourceAudioClock.js +138 -0
  25. package/dist/packages/adapters/mse-audio/src/SourceBufferFeeder.js +263 -0
  26. package/dist/packages/adapters/mse-audio/src/events.js +26 -0
  27. package/dist/packages/adapters/mse-audio/src/mediaSourceSupport.js +81 -0
  28. package/dist/packages/adapters/three/src/ThreeFrameRenderer.js +215 -0
  29. package/dist/packages/adapters/three/src/compileAndProve.js +14 -0
  30. package/dist/packages/adapters/three/src/conversionUniforms.js +60 -0
  31. package/dist/packages/adapters/three/src/drawSchedules.js +13 -0
  32. package/dist/packages/adapters/three/src/fullscreenPass.js +52 -0
  33. package/dist/packages/adapters/three/src/glslLiterals.js +10 -0
  34. package/dist/packages/adapters/three/src/lensTextures.js +34 -0
  35. package/dist/packages/adapters/three/src/matrixCorrections.js +34 -0
  36. package/dist/packages/adapters/three/src/pictureMaterials.js +44 -0
  37. package/dist/packages/adapters/three/src/renderInto.js +15 -0
  38. package/dist/packages/adapters/three/src/rendererParts.js +108 -0
  39. package/dist/packages/adapters/three/src/rendererUniforms.js +176 -0
  40. package/dist/packages/adapters/three/src/samplingStrategies.js +26 -0
  41. package/dist/packages/adapters/three/src/scissorBox.js +20 -0
  42. package/dist/packages/adapters/three/src/seamMeter/SeamMeterPass.js +85 -0
  43. package/dist/packages/adapters/three/src/seamMeter/rowMeans.js +42 -0
  44. package/dist/packages/adapters/three/src/shaderPrograms.js +68 -0
  45. package/dist/packages/adapters/three/src/shaders/analysis.frag.js +4 -0
  46. package/dist/packages/adapters/three/src/shaders/displayConversion.js +4 -0
  47. package/dist/packages/adapters/three/src/shaders/equirectangularRays.js +4 -0
  48. package/dist/packages/adapters/three/src/shaders/fixedJoin.js +4 -0
  49. package/dist/packages/adapters/three/src/shaders/fullscreen.vert.js +4 -0
  50. package/dist/packages/adapters/three/src/shaders/header.js +4 -0
  51. package/dist/packages/adapters/three/src/shaders/lensModels.js +4 -0
  52. package/dist/packages/adapters/three/src/shaders/lensSampling.js +4 -0
  53. package/dist/packages/adapters/three/src/shaders/lensTextures.js +4 -0
  54. package/dist/packages/adapters/three/src/shaders/rawLenses.frag.js +4 -0
  55. package/dist/packages/adapters/three/src/shaders/rectilinearRays.js +4 -0
  56. package/dist/packages/adapters/three/src/shaders/screenAreas.js +4 -0
  57. package/dist/packages/adapters/three/src/shaders/stitch.frag.js +4 -0
  58. package/dist/packages/adapters/three/src/threeMatrix.js +10 -0
  59. package/dist/packages/adapters/three/src/webglRenderer.js +37 -0
  60. package/dist/packages/adapters/webcodecs/src/WebCodecsVideoDecoderPort.js +152 -0
  61. package/dist/packages/adapters/webcodecs/src/colorSpaceOf.js +32 -0
  62. package/dist/packages/core/src/application/download/BlockStore.js +97 -0
  63. package/dist/packages/core/src/application/download/DownloadedAudioSamples.js +50 -0
  64. package/dist/packages/core/src/application/download/DownloadedVideoTrack.js +122 -0
  65. package/dist/packages/core/src/application/download/FileDownload.js +208 -0
  66. package/dist/packages/core/src/application/download/RecordingBuffer.js +22 -0
  67. package/dist/packages/core/src/application/download/SampleCursor.js +89 -0
  68. package/dist/packages/core/src/application/download/SourceByteStream.js +46 -0
  69. package/dist/packages/core/src/application/download/Transfers.js +82 -0
  70. package/dist/packages/core/src/application/download/startFileDownload.js +37 -0
  71. package/dist/packages/core/src/application/gainMatching/GainMatching.js +76 -0
  72. package/dist/packages/core/src/application/gainMatching/GainMatchingFrameSink.js +80 -0
  73. package/dist/packages/core/src/application/gainMatching/referenceLensOf.js +18 -0
  74. package/dist/packages/core/src/application/playback/Buffering.js +54 -0
  75. package/dist/packages/core/src/application/playback/ClockStart.js +55 -0
  76. package/dist/packages/core/src/application/playback/ClockWatch.js +76 -0
  77. package/dist/packages/core/src/application/playback/DecodePipeline.js +234 -0
  78. package/dist/packages/core/src/application/playback/DecodeRun.js +108 -0
  79. package/dist/packages/core/src/application/playback/FramePairQueue.js +93 -0
  80. package/dist/packages/core/src/application/playback/FramePairer.js +77 -0
  81. package/dist/packages/core/src/application/playback/PictureOnScreen.js +56 -0
  82. package/dist/packages/core/src/application/playback/PlaybackSession.js +410 -0
  83. package/dist/packages/core/src/application/playback/SeekOrder.js +35 -0
  84. package/dist/packages/core/src/application/playback/SessionLifecycle.js +42 -0
  85. package/dist/packages/core/src/application/playback/StartGate.js +69 -0
  86. package/dist/packages/core/src/application/playback/TimeUpdates.js +31 -0
  87. package/dist/packages/core/src/application/playback/WallClock.js +46 -0
  88. package/dist/packages/core/src/application/playback/keyframeTimeAt.js +15 -0
  89. package/dist/packages/core/src/application/playback/probeDecoding.js +182 -0
  90. package/dist/packages/core/src/application/recording/frameTimesOf.js +21 -0
  91. package/dist/packages/core/src/application/recording/inspectLayout.js +21 -0
  92. package/dist/packages/core/src/application/recording/inspectRecording.js +125 -0
  93. package/dist/packages/core/src/application/recording/locateOtherLensFile.js +18 -0
  94. package/dist/packages/core/src/application/recording/motionOf.js +43 -0
  95. package/dist/packages/core/src/application/recording/readRecording.js +31 -0
  96. package/dist/packages/core/src/application/recording/readRecordingFiles.js +130 -0
  97. package/dist/packages/core/src/application/recording/readSampleTable.js +27 -0
  98. package/dist/packages/core/src/application/recording/timeRecording.js +57 -0
  99. package/dist/packages/core/src/application/stabilization/StabilizingFrameSink.js +33 -0
  100. package/dist/packages/core/src/domain/colour/DisplayConversion.js +137 -0
  101. package/dist/packages/core/src/domain/colour/TrackColour.js +38 -0
  102. package/dist/packages/core/src/domain/colour/gainMatch.js +64 -0
  103. package/dist/packages/core/src/domain/colour/matrixCorrection.js +76 -0
  104. package/dist/packages/core/src/domain/container/KeyframeRule.js +7 -0
  105. package/dist/packages/core/src/domain/container/SampleTable.js +29 -0
  106. package/dist/packages/core/src/domain/container/TrackSampleTable.js +96 -0
  107. package/dist/packages/core/src/domain/container/presentationOrder.js +10 -0
  108. package/dist/packages/core/src/domain/download/DownloadPolicy.js +84 -0
  109. package/dist/packages/core/src/domain/download/isReadyToResume.js +27 -0
  110. package/dist/packages/core/src/domain/download/planDownloads.js +175 -0
  111. package/dist/packages/core/src/domain/download/trackNeeds.js +32 -0
  112. package/dist/packages/core/src/domain/format/boxes/BoxLayout.js +7 -0
  113. package/dist/packages/core/src/domain/format/boxes/boxConstants.js +16 -0
  114. package/dist/packages/core/src/domain/format/boxes/boxHeader.js +44 -0
  115. package/dist/packages/core/src/domain/format/boxes/scanBoxes.js +32 -0
  116. package/dist/packages/core/src/domain/format/calibration/CalibrationVersion.js +16 -0
  117. package/dist/packages/core/src/domain/format/calibration/layouts/CalibrationStringLayout.js +34 -0
  118. package/dist/packages/core/src/domain/format/calibration/layouts/LegacyCalibrationLayout.js +46 -0
  119. package/dist/packages/core/src/domain/format/calibration/layouts/MeiCalibrationLayout.js +121 -0
  120. package/dist/packages/core/src/domain/format/calibration/layouts/PolynomialCalibrationLayout.js +46 -0
  121. package/dist/packages/core/src/domain/format/calibration/offsetTokens.js +94 -0
  122. package/dist/packages/core/src/domain/format/calibration/parseOffsetString.js +77 -0
  123. package/dist/packages/core/src/domain/format/calibration/selectCalibration.js +59 -0
  124. package/dist/packages/core/src/domain/format/calibration/v6TermReading.js +20 -0
  125. package/dist/packages/core/src/domain/format/captureOrigin.js +34 -0
  126. package/dist/packages/core/src/domain/format/constants.js +35 -0
  127. package/dist/packages/core/src/domain/format/info/calibrationSources.js +27 -0
  128. package/dist/packages/core/src/domain/format/info/infoFields.js +116 -0
  129. package/dist/packages/core/src/domain/format/info/parseInfoRecord.js +107 -0
  130. package/dist/packages/core/src/domain/format/info/readInfoRecord.js +14 -0
  131. package/dist/packages/core/src/domain/format/layout/detectLensLayout.js +133 -0
  132. package/dist/packages/core/src/domain/format/mp4/hevcCodecString.js +161 -0
  133. package/dist/packages/core/src/domain/format/mp4/keyframeRules.js +81 -0
  134. package/dist/packages/core/src/domain/format/mp4/movieBoxes.js +52 -0
  135. package/dist/packages/core/src/domain/format/mp4/mp4BoxTypes.js +46 -0
  136. package/dist/packages/core/src/domain/format/mp4/mp4Layouts.js +183 -0
  137. package/dist/packages/core/src/domain/format/mp4/parseMovie.js +72 -0
  138. package/dist/packages/core/src/domain/format/mp4/readTable.js +31 -0
  139. package/dist/packages/core/src/domain/format/mp4/sampleLocations.js +76 -0
  140. package/dist/packages/core/src/domain/format/mp4/sampleTiming.js +120 -0
  141. package/dist/packages/core/src/domain/format/mp4/trackHeaders.js +88 -0
  142. package/dist/packages/core/src/domain/format/naming/RecordingFileName.js +70 -0
  143. package/dist/packages/core/src/domain/format/records/TrailerRecords.js +100 -0
  144. package/dist/packages/core/src/domain/format/records/exposure/parseExposureRecord.js +48 -0
  145. package/dist/packages/core/src/domain/format/records/gyro/FloatGyroSampleLayout.js +38 -0
  146. package/dist/packages/core/src/domain/format/records/gyro/RawGyroSampleLayout.js +55 -0
  147. package/dist/packages/core/src/domain/format/records/gyro/SampleColumns.js +89 -0
  148. package/dist/packages/core/src/domain/format/records/gyro/gyroLayouts.js +12 -0
  149. package/dist/packages/core/src/domain/format/records/gyro/parseGyroRecord.js +138 -0
  150. package/dist/packages/core/src/domain/format/records/trim/parseTrimRecord.js +24 -0
  151. package/dist/packages/core/src/domain/format/trailer/RecordHeader.js +23 -0
  152. package/dist/packages/core/src/domain/format/trailer/Trailer.js +23 -0
  153. package/dist/packages/core/src/domain/format/trailer/TrailerFooter.js +27 -0
  154. package/dist/packages/core/src/domain/format/trailer/locateRecords.js +80 -0
  155. package/dist/packages/core/src/domain/format/trailer/parseRecordIndex.js +28 -0
  156. package/dist/packages/core/src/domain/format/trailer/readTrailer.js +60 -0
  157. package/dist/packages/core/src/domain/motion/exposure/ExposureRecord.js +48 -0
  158. package/dist/packages/core/src/domain/motion/gyro/GyroTrack.js +70 -0
  159. package/dist/packages/core/src/domain/motion/gyro/medianStep.js +11 -0
  160. package/dist/packages/core/src/domain/motion/gyro/repairedTimeline.js +101 -0
  161. package/dist/packages/core/src/domain/motion/imu/ImuFrame.js +178 -0
  162. package/dist/packages/core/src/domain/motion/mounting/Mounting.js +131 -0
  163. package/dist/packages/core/src/domain/motion/orientation/OrientationTrack.js +142 -0
  164. package/dist/packages/core/src/domain/motion/orientation/estimateGyroBias.js +72 -0
  165. package/dist/packages/core/src/domain/motion/orientation/gravity.js +97 -0
  166. package/dist/packages/core/src/domain/motion/stabilization/Stabilizer.js +13 -0
  167. package/dist/packages/core/src/domain/motion/stabilization/stabilizers.js +86 -0
  168. package/dist/packages/core/src/domain/motion/timing/CaptureClock.js +41 -0
  169. package/dist/packages/core/src/domain/motion/timing/FrameTimes.js +85 -0
  170. package/dist/packages/core/src/domain/motion/timing/frameTimeSources.js +58 -0
  171. package/dist/packages/core/src/domain/motion/timing/resolveFrameTimes.js +68 -0
  172. package/dist/packages/core/src/domain/optics/EquidistantModel.js +34 -0
  173. package/dist/packages/core/src/domain/optics/MeiDistortion.js +27 -0
  174. package/dist/packages/core/src/domain/optics/MeiModel.js +27 -0
  175. package/dist/packages/core/src/domain/optics/PolynomialModel.js +39 -0
  176. package/dist/packages/core/src/domain/optics/lensPose.js +49 -0
  177. package/dist/packages/core/src/domain/optics/opticsConstants.js +5 -0
  178. package/dist/packages/core/src/domain/optics/scaledProjection.js +30 -0
  179. package/dist/packages/core/src/domain/playback/PlayerState.js +83 -0
  180. package/dist/packages/core/src/domain/rendition/RenditionSpan.js +70 -0
  181. package/dist/packages/core/src/domain/stitching/LensLayout.js +21 -0
  182. package/dist/packages/core/src/domain/stitching/StitchingSetup.js +87 -0
  183. package/dist/packages/core/src/domain/stitching/seamRing.js +4 -0
  184. package/dist/packages/core/src/domain/view/Framing.js +37 -0
  185. package/dist/packages/core/src/domain/view/Picture.js +12 -0
  186. package/dist/packages/core/src/domain/view/PictureQuality.js +26 -0
  187. package/dist/packages/core/src/domain/view/ViewMode.js +9 -0
  188. package/dist/packages/core/src/domain/view/ViewState.js +54 -0
  189. package/dist/packages/core/src/domain/view/lensTilesView.js +64 -0
  190. package/dist/packages/core/src/domain/view/magnification.js +103 -0
  191. package/dist/packages/core/src/domain/view/motionLookView.js +100 -0
  192. package/dist/packages/core/src/domain/view/normalView.js +37 -0
  193. package/dist/packages/core/src/domain/view/panoramaView.js +95 -0
  194. package/dist/packages/core/src/domain/view/rectilinear.js +53 -0
  195. package/dist/packages/core/src/domain/view/screenLayout.js +129 -0
  196. package/dist/packages/core/src/domain/view/screenLook.js +74 -0
  197. package/dist/packages/core/src/domain/view/viewGestures.js +104 -0
  198. package/dist/packages/core/src/domain/view/viewModes.js +31 -0
  199. package/dist/packages/core/src/ports/FramePair.js +6 -0
  200. package/dist/packages/core/src/shared/async/Deferred.js +42 -0
  201. package/dist/packages/core/src/shared/async/RunStop.js +40 -0
  202. package/dist/packages/core/src/shared/async/iteration.js +24 -0
  203. package/dist/packages/core/src/shared/binary/ByteRange.js +50 -0
  204. package/dist/packages/core/src/shared/binary/ByteRangeSet.js +85 -0
  205. package/dist/packages/core/src/shared/binary/ByteReader.js +104 -0
  206. package/dist/packages/core/src/shared/binary/concatenated.js +15 -0
  207. package/dist/packages/core/src/shared/errors/GyroViewError.js +140 -0
  208. package/dist/packages/core/src/shared/errors/reportLater.js +11 -0
  209. package/dist/packages/core/src/shared/events/Outbox.js +68 -0
  210. package/dist/packages/core/src/shared/events/TypedEmitter.js +55 -0
  211. package/dist/packages/core/src/shared/keysOf.js +10 -0
  212. package/dist/packages/core/src/shared/lazy.js +11 -0
  213. package/dist/packages/core/src/shared/mapRecord.js +11 -0
  214. package/dist/packages/core/src/shared/math/Matrix3.js +121 -0
  215. package/dist/packages/core/src/shared/math/Quaternion.js +133 -0
  216. package/dist/packages/core/src/shared/math/Vector3.js +58 -0
  217. package/dist/packages/core/src/shared/math/clamp.js +9 -0
  218. package/dist/packages/core/src/shared/math/countAtOrBelow.js +31 -0
  219. package/dist/packages/core/src/shared/math/minimum.js +17 -0
  220. package/dist/packages/core/src/shared/protobuf/ProtobufMessage.js +143 -0
  221. package/dist/packages/core/src/shared/protobuf/wireFormat.js +16 -0
  222. package/dist/packages/core/src/shared/text/urlPath.js +31 -0
  223. package/dist/packages/core/src/shared/text/utf8.js +12 -0
  224. package/dist/packages/core/src/shared/units/angle.js +22 -0
  225. package/dist/packages/core/src/shared/units/time.js +13 -0
  226. package/dist/packages/player/src/PlayerSource.js +14 -0
  227. package/dist/packages/player/src/browserPlayer.js +20 -0
  228. package/dist/packages/player/src/choices.js +24 -0
  229. package/dist/packages/player/src/composition/AnimationFrameDraws.js +38 -0
  230. package/dist/packages/player/src/composition/BrowserAttitudeSensor.js +191 -0
  231. package/dist/packages/player/src/composition/Disposables.js +31 -0
  232. package/dist/packages/player/src/composition/DrawingBufferFit.js +119 -0
  233. package/dist/packages/player/src/composition/animationFrames.js +9 -0
  234. package/dist/packages/player/src/composition/attitudeSensor.js +18 -0
  235. package/dist/packages/player/src/composition/browserPorts.js +80 -0
  236. package/dist/packages/player/src/composition/buildPipeline.js +186 -0
  237. package/dist/packages/player/src/composition/ensureDecodable.js +62 -0
  238. package/dist/packages/player/src/composition/openInputs.js +120 -0
  239. package/dist/packages/player/src/composition/openRecording.js +41 -0
  240. package/dist/packages/player/src/composition/readInputs.js +25 -0
  241. package/dist/packages/player/src/composition/renditionFrames.js +160 -0
  242. package/dist/packages/player/src/controls/ChoiceMenu.js +125 -0
  243. package/dist/packages/player/src/controls/FullscreenButton.js +29 -0
  244. package/dist/packages/player/src/controls/MotionLookButton.js +34 -0
  245. package/dist/packages/player/src/controls/PictureMenus.js +60 -0
  246. package/dist/packages/player/src/controls/SeekBar.js +126 -0
  247. package/dist/packages/player/src/controls/SoundControls.js +43 -0
  248. package/dist/packages/player/src/controls/TransportButtons.js +28 -0
  249. package/dist/packages/player/src/controls/ViewGestures.js +135 -0
  250. package/dist/packages/player/src/controls/Wording.js +79 -0
  251. package/dist/packages/player/src/controls/controlParts.js +38 -0
  252. package/dist/packages/player/src/controls/controls.js +4 -0
  253. package/dist/packages/player/src/controls/controlsBar.js +33 -0
  254. package/dist/packages/player/src/controls/controlsMarkup.js +100 -0
  255. package/dist/packages/player/src/controls/customControls.js +43 -0
  256. package/dist/packages/player/src/controls/formatTime.js +19 -0
  257. package/dist/packages/player/src/controls/icons.js +66 -0
  258. package/dist/packages/player/src/controls/keyboard.js +120 -0
  259. package/dist/packages/player/src/controls/messages.js +130 -0
  260. package/dist/packages/player/src/controls/nativeFullscreen.js +27 -0
  261. package/dist/packages/player/src/controls/parseMarkup.js +30 -0
  262. package/dist/packages/player/src/controls/resetViewButton.js +11 -0
  263. package/dist/packages/player/src/controls/sliderFill.js +15 -0
  264. package/dist/packages/player/src/element/ElementLoads.js +130 -0
  265. package/dist/packages/player/src/element/FullscreenToggle.js +93 -0
  266. package/dist/packages/player/src/element/GyroViewElement.js +358 -0
  267. package/dist/packages/player/src/element/IdleWatcher.js +71 -0
  268. package/dist/packages/player/src/element/PlayerCanvas.js +72 -0
  269. package/dist/packages/player/src/element/TypedEventElement.js +22 -0
  270. package/dist/packages/player/src/element/accessibleRegion.js +19 -0
  271. package/dist/packages/player/src/element/attributeNames.js +62 -0
  272. package/dist/packages/player/src/element/attributes.js +123 -0
  273. package/dist/packages/player/src/element/defineGyroView.js +20 -0
  274. package/dist/packages/player/src/element/earlyProperties.js +35 -0
  275. package/dist/packages/player/src/element/elementProperties.js +34 -0
  276. package/dist/packages/player/src/element/elementSource.js +39 -0
  277. package/dist/packages/player/src/element/fetchProperty.js +48 -0
  278. package/dist/packages/player/src/element/liveSettings.js +137 -0
  279. package/dist/packages/player/src/element/playbackAttributes.js +52 -0
  280. package/dist/packages/player/src/element/playerEventMirror.js +33 -0
  281. package/dist/packages/player/src/element/reflectedProperties.js +96 -0
  282. package/dist/packages/player/src/element/styles.js +4 -0
  283. package/dist/packages/player/src/element/template.js +46 -0
  284. package/dist/packages/player/src/inspectRecording.js +21 -0
  285. package/dist/packages/player/src/player/FrameLoop.js +35 -0
  286. package/dist/packages/player/src/player/MotionLook.js +150 -0
  287. package/dist/packages/player/src/player/PictureSettings.js +59 -0
  288. package/dist/packages/player/src/player/PlaybackStarts.js +38 -0
  289. package/dist/packages/player/src/player/Player.js +379 -0
  290. package/dist/packages/player/src/player/PlayerEvents.js +28 -0
  291. package/dist/packages/player/src/player/PlayerPhase.js +38 -0
  292. package/dist/packages/player/src/player/PlayerSound.js +60 -0
  293. package/dist/packages/player/src/player/PlayerView.js +143 -0
  294. package/dist/packages/player/src/player/SessionRelay.js +74 -0
  295. package/dist/packages/player/src/player/StatusAnnouncer.js +29 -0
  296. package/dist/packages/player/src/player/ensureFinite.js +26 -0
  297. package/dist/packages/player/src/player/loadRecording.js +47 -0
  298. package/dist/packages/player/src/player/transportEvents.js +30 -0
  299. package/dist/packages/player/src/player/viewAngles.js +17 -0
  300. package/dist/packages/player/src/rendition.js +52 -0
  301. package/dist/standalone.js +5633 -0
  302. package/package.json +70 -3
@@ -0,0 +1,23 @@
1
+ import { GyroViewError, hasErrorCode } from "../../../core/src/shared/errors/GyroViewError.js";
2
+ //#region ../../packages/adapters/fetch/src/passingFailures.ts
3
+ /**
4
+ * The failures on the way, which asking again may cure; any other fails the read at once. They
5
+ * are `source-unreadable` errors like any other, so a caller that gets one after the retries
6
+ * cannot tell, and need not: only the retry loop asks.
7
+ */
8
+ var passingFailures = /* @__PURE__ */ new WeakSet();
9
+ function passing(failure) {
10
+ passingFailures.add(failure);
11
+ return failure;
12
+ }
13
+ function isPassing(error) {
14
+ return error instanceof GyroViewError && passingFailures.has(error);
15
+ }
16
+ /**
17
+ * A request that did not get through for want of a network is worth another try.
18
+ */
19
+ function passingIfUnreachable(error) {
20
+ return hasErrorCode(error, "source-unreadable") && error instanceof Error ? passing(new GyroViewError("source-unreadable", error.message, { cause: error.cause })) : error;
21
+ }
22
+ //#endregion
23
+ export { isPassing, passing, passingIfUnreachable };
@@ -0,0 +1,16 @@
1
+ import { GyroViewError } from "../../../core/src/shared/errors/GyroViewError.js";
2
+ import { passing } from "./passingFailures.js";
3
+ //#region ../../packages/adapters/fetch/src/rangeFailures.ts
4
+ /**
5
+ * A body a dropped connection broke off after the headers: the most common way a network fails
6
+ * during long playback, so it is `source-unreadable` as a refused request is, not a bug or a bad
7
+ * file, and worth another try.
8
+ */
9
+ function brokenOff(url, range, cause) {
10
+ return passing(new GyroViewError("source-unreadable", `${url} broke off the ${range.length}-byte range at ${range.offset}`, { cause }));
11
+ }
12
+ function truncated(url, received, range) {
13
+ return new GyroViewError("source-truncated", `${url} returned ${received} bytes for a ${range.length}-byte range at ${range.offset}`);
14
+ }
15
+ //#endregion
16
+ export { brokenOff, truncated };
@@ -0,0 +1,37 @@
1
+ import { contentRangeOf } from "./contentRange.js";
2
+ //#region ../../packages/adapters/fetch/src/recordingVersion.ts
3
+ var HTTP_OK = 200;
4
+ var WEAK_ETAG_PREFIX = /^W\//u;
5
+ function versionOf(response) {
6
+ const etag = response.headers.get("etag");
7
+ const lastModified = response.headers.get("last-modified");
8
+ const size = sizeOf(response);
9
+ return {
10
+ ...etag !== null && { etag },
11
+ ...lastModified !== null && { lastModified },
12
+ ...size !== void 0 && { size }
13
+ };
14
+ }
15
+ /**
16
+ * Whether two answers are of one version of the recording, by the ETag where both tell one,
17
+ * else by the Last-Modified and the size; what either does not tell is taken for the same, so
18
+ * a server that tells nothing is never taken for one that changed its file.
19
+ */
20
+ function isSameVersion(known, seen) {
21
+ return known.etag !== void 0 && seen.etag !== void 0 ? opaqueTagOf(known.etag) === opaqueTagOf(seen.etag) : isSameWhereTold(known.lastModified, seen.lastModified) && isSameWhereTold(known.size, seen.size);
22
+ }
23
+ /**
24
+ * The tag without its weakness mark: a CDN may weaken a strong ETag it passes on.
25
+ */
26
+ function opaqueTagOf(etag) {
27
+ return etag.replace(WEAK_ETAG_PREFIX, "");
28
+ }
29
+ function isSameWhereTold(known, seen) {
30
+ return known === void 0 || seen === void 0 || known === seen;
31
+ }
32
+ function sizeOf(response) {
33
+ const size = response.status === HTTP_OK ? Number(response.headers.get("content-length") ?? NaN) : contentRangeOf(response)?.total;
34
+ return size !== void 0 && Number.isSafeInteger(size) && size > 0 ? size : void 0;
35
+ }
36
+ //#endregion
37
+ export { isSameVersion, versionOf };
@@ -0,0 +1,162 @@
1
+ import { GyroViewError, ensureInvariant } from "../../../core/src/shared/errors/GyroViewError.js";
2
+ import { SegmentChannel } from "./SegmentChannel.js";
3
+ import { EncodedAudioPacketSource, EncodedPacket, Mp4OutputFormat, NullTarget, Output } from "mediabunny";
4
+ //#region ../../packages/adapters/mediabunny/src/MediabunnyAudioPackager.ts
5
+ /**
6
+ * Seconds of audio per media segment: short enough that a seek has sound quickly, long enough
7
+ * that appends stay cheap.
8
+ */
9
+ var FRAGMENT_DURATION_SECONDS = 1;
10
+ /**
11
+ * Media segments that may wait for the consumer before re-packaging pauses.
12
+ */
13
+ var SEGMENTS_AHEAD = 2;
14
+ /**
15
+ * The codec strings of the audio the cameras record, AAC (`mp4a.40.2` for AAC-LC), and mediabunny's
16
+ * name for it. Other codecs are not re-packaged: the picture then plays on a silent clock.
17
+ */
18
+ var AAC_CODEC_STRING_PREFIX = "mp4a.40.";
19
+ var AAC = "aac";
20
+ /**
21
+ * AudioPackager over mediabunny: the samples re-packaged, unchanged, into fragmented MP4.
22
+ * Segments are assembled from the muxer's box callbacks rather than taken from its byte stream:
23
+ * that yields whole segments and leaves out the `mfra` index the muxer appends at the end, which
24
+ * Media Source Extensions do not accept. Fragmented output keeps the track's own timestamps, so
25
+ * segments started mid-track land at their true time.
26
+ */
27
+ var MediabunnyAudioPackager = class {
28
+ segmentsOf(samples, configuration) {
29
+ const codec = muxedCodecOf(configuration);
30
+ return {
31
+ mimeType: `audio/mp4; codecs="${configuration.codec}"`,
32
+ duration: samples.duration,
33
+ segmentsFrom: (from) => ({ [Symbol.asyncIterator]: () => remux({
34
+ samples,
35
+ configuration,
36
+ codec
37
+ }, from) })
38
+ };
39
+ }
40
+ };
41
+ function muxedCodecOf(configuration) {
42
+ if (configuration.codec.startsWith(AAC_CODEC_STRING_PREFIX)) return AAC;
43
+ throw new GyroViewError("codec-unsupported", `audio in ${configuration.codec} cannot be re-packaged for playback`);
44
+ }
45
+ /**
46
+ * Starts re-packaging from `from` into a channel and hands out its consumer's side. When the
47
+ * consumer leaves, the samples are let go of at once, even while one is awaited, and the muxer
48
+ * once the producer has noticed.
49
+ */
50
+ function remux(parts, from) {
51
+ const channel = new SegmentChannel(SEGMENTS_AHEAD);
52
+ const output = new Output({
53
+ format: fragmentedMp4Into(channel),
54
+ target: new NullTarget()
55
+ });
56
+ const source = new EncodedAudioPacketSource(parts.codec);
57
+ output.addAudioTrack(source);
58
+ const samples = parts.samples.samplesFrom(from)[Symbol.asyncIterator]();
59
+ const production = produce({
60
+ samples,
61
+ configuration: parts.configuration,
62
+ output,
63
+ source,
64
+ channel
65
+ });
66
+ return channel.segments(() => {
67
+ samples.return?.();
68
+ releaseAfter(production, output);
69
+ });
70
+ }
71
+ /**
72
+ * Frees the muxer once the producer has noticed the closed channel, without making a consumer
73
+ * that left early (a seek) wait for a sample still in flight.
74
+ */
75
+ async function releaseAfter(production, output) {
76
+ await production;
77
+ if (output.state === "finalized") return;
78
+ try {
79
+ await output.cancel();
80
+ } catch {}
81
+ }
82
+ /**
83
+ * Feeds samples to the muxer at the consumer's pace; every failure ends up in the channel.
84
+ */
85
+ async function produce(run) {
86
+ try {
87
+ await run.output.start();
88
+ let meta = { decoderConfig: decoderConfigOf(run.configuration) };
89
+ for (let next = await run.samples.next(); next.done !== true; next = await run.samples.next()) {
90
+ await run.channel.waitForRoom();
91
+ if (run.channel.isClosed) return;
92
+ await run.source.add(packetOf(next.value), meta);
93
+ meta = void 0;
94
+ }
95
+ if (run.channel.isClosed) return;
96
+ await run.output.finalize();
97
+ run.channel.close();
98
+ } catch (error) {
99
+ run.channel.fail(error);
100
+ }
101
+ }
102
+ function packetOf(sample) {
103
+ return new EncodedPacket(sample.data, "key", sample.timestamp, sample.duration);
104
+ }
105
+ function decoderConfigOf(configuration) {
106
+ return {
107
+ codec: configuration.codec,
108
+ sampleRate: configuration.sampleRate,
109
+ numberOfChannels: configuration.numberOfChannels,
110
+ ...configuration.description && { description: configuration.description }
111
+ };
112
+ }
113
+ /**
114
+ * The muxer's boxes handed on as whole segments: the initialization segment (`ftyp` and `moov`)
115
+ * and each media segment (`moof` and its `mdat`). A consumer that stops between two segments, as
116
+ * a seek does, then never leaves a source buffer's parser inside one, where Chromium reads the
117
+ * next segments' bytes as the samples of the `moof` it holds and fails to decode them.
118
+ */
119
+ function fragmentedMp4Into(channel) {
120
+ const segment = new SegmentAssembly(channel);
121
+ return new Mp4OutputFormat({
122
+ fastStart: "fragmented",
123
+ minimumFragmentDuration: FRAGMENT_DURATION_SECONDS,
124
+ onFtyp: (data) => {
125
+ segment.begin(data);
126
+ },
127
+ onMoov: (data) => {
128
+ segment.end(data);
129
+ },
130
+ onMoof: (data) => {
131
+ segment.begin(data);
132
+ },
133
+ onMdat: (data) => {
134
+ segment.end(data);
135
+ }
136
+ });
137
+ }
138
+ /**
139
+ * A segment's first box held until the box that ends it arrives, then both pushed as one.
140
+ */
141
+ var SegmentAssembly = class {
142
+ channel;
143
+ opening;
144
+ constructor(channel) {
145
+ this.channel = channel;
146
+ }
147
+ begin(box) {
148
+ ensureInvariant(this.opening === void 0, "a segment began before the last one ended");
149
+ this.opening = new Uint8Array(box);
150
+ }
151
+ end(box) {
152
+ const { opening } = this;
153
+ ensureInvariant(opening !== void 0, "a segment ended that never began");
154
+ const whole = new Uint8Array(opening.byteLength + box.byteLength);
155
+ whole.set(opening);
156
+ whole.set(box, opening.byteLength);
157
+ this.opening = void 0;
158
+ this.channel.push(whole);
159
+ }
160
+ };
161
+ //#endregion
162
+ export { MediabunnyAudioPackager };
@@ -0,0 +1,93 @@
1
+ import { GyroViewError, isAbortError } from "../../../core/src/shared/errors/GyroViewError.js";
2
+ import { audioConfigurationOf, codecStringOf, videoConfigurationOf } from "./decoderConfigurations.js";
3
+ import { trackColourOf } from "./trackColour.js";
4
+ import { BufferSource, Input, MP4, QTFF } from "mediabunny";
5
+ //#region ../../packages/adapters/mediabunny/src/MediabunnyCodecReader.ts
6
+ /**
7
+ * The movie bytes are an ISO BMFF file's type and movie boxes, whatever its brand: with only
8
+ * these two formats named, a page's bundle leaves out mediabunny's other demuxers, a third of
9
+ * its weight.
10
+ */
11
+ var MOVIE_FORMATS = [MP4, QTFF];
12
+ /**
13
+ * CodecReader over mediabunny: opens the file type and movie boxes as a file of their own, in
14
+ * memory, and tells each track's decoder configuration. mediabunny reads a sample only for a
15
+ * video codec without its configuration box; the samples are not there, so that track is
16
+ * refused as the file's failing.
17
+ */
18
+ var MediabunnyCodecReader = class {
19
+ async read(movieBytes) {
20
+ const input = new Input({
21
+ formats: MOVIE_FORMATS,
22
+ source: new BufferSource(movieBytes)
23
+ });
24
+ try {
25
+ const [videoTracks, audioTracks] = await Promise.all([input.getVideoTracks(), input.getAudioTracks()]);
26
+ return {
27
+ video: await Promise.all(videoTracks.map((track, index) => videoCodecOf(track, index))),
28
+ audio: (await Promise.all(audioTracks.map((track) => audioCodecOf(track)))).flat()
29
+ };
30
+ } catch (error) {
31
+ throw failureOf(error);
32
+ } finally {
33
+ input.dispose();
34
+ }
35
+ }
36
+ };
37
+ async function videoCodecOf(track, trackIndex) {
38
+ const [config, codedWidth, codedHeight] = await Promise.all([
39
+ configurationOf(track, trackIndex),
40
+ track.getCodedWidth(),
41
+ track.getCodedHeight()
42
+ ]);
43
+ const description = {
44
+ trackIndex,
45
+ codedWidth,
46
+ codedHeight,
47
+ codec: await codecStringOf(track, config),
48
+ colour: trackColourOf(config.colorSpace)
49
+ };
50
+ return {
51
+ trackId: track.id,
52
+ description,
53
+ configuration: videoConfigurationOf(config, description)
54
+ };
55
+ }
56
+ /**
57
+ * The configuration of a codec that carries it in the movie box. A sample entry without one, or
58
+ * with one mediabunny cannot read, fails as the file's: no browser could configure a decoder from
59
+ * it, and the movie bytes hold no sample to find it in.
60
+ */
61
+ async function configurationOf(track, trackIndex) {
62
+ let config;
63
+ try {
64
+ config = await track.getDecoderConfig();
65
+ } catch (error) {
66
+ throw noConfiguration(trackIndex, { cause: error });
67
+ }
68
+ if (config === null) throw noConfiguration(trackIndex);
69
+ return config;
70
+ }
71
+ function noConfiguration(trackIndex, options) {
72
+ return new GyroViewError("unsupported-container", `video track ${trackIndex} has no decoder configuration in its sample entry`, options);
73
+ }
74
+ /**
75
+ * An audio track mediabunny cannot configure is left out: the picture then plays without sound
76
+ * rather than not at all.
77
+ */
78
+ async function audioCodecOf(track) {
79
+ const config = await track.getDecoderConfig();
80
+ return config === null ? [] : [{
81
+ trackId: track.id,
82
+ configuration: audioConfigurationOf(config)
83
+ }];
84
+ }
85
+ /**
86
+ * A caller's abort and the core's own failures pass as they are; anything else mediabunny
87
+ * throws means the bytes are no movie it can read.
88
+ */
89
+ function failureOf(error) {
90
+ return isAbortError(error) || error instanceof GyroViewError ? error : new GyroViewError("unsupported-container", "the movie box is not a readable movie", { cause: error });
91
+ }
92
+ //#endregion
93
+ export { MediabunnyCodecReader };
@@ -0,0 +1,135 @@
1
+ import { GyroViewError, ensureInvariant } from "../../../core/src/shared/errors/GyroViewError.js";
2
+ import { ITERATION_END } from "../../../core/src/shared/async/iteration.js";
3
+ //#region ../../packages/adapters/mediabunny/src/SegmentChannel.ts
4
+ /**
5
+ * Hands segments from the muxer's synchronous callbacks to one asynchronous consumer, with a
6
+ * bound on how many may wait unconsumed so re-packaging never runs far ahead of playback.
7
+ * Closing from either side ends the exchange; a producer failure reaches the consumer as a
8
+ * thrown error once the segments before it are drained. A second concurrent consumer is a
9
+ * programming error.
10
+ */
11
+ var SegmentChannel = class {
12
+ capacity;
13
+ queue = [];
14
+ roomWaiters = [];
15
+ takeWaiter;
16
+ isClosedNow = false;
17
+ failure;
18
+ constructor(capacity) {
19
+ this.capacity = capacity;
20
+ }
21
+ get isClosed() {
22
+ return this.isClosedNow;
23
+ }
24
+ push(segment) {
25
+ if (this.isClosedNow) return;
26
+ this.queue.push(segment);
27
+ this.wakeTaker();
28
+ }
29
+ /**
30
+ * Resolves once fewer than `capacity` segments wait, or at once when the channel is closed.
31
+ */
32
+ waitForRoom() {
33
+ return this.queue.length < this.capacity || this.isClosedNow ? Promise.resolve() : new Promise((resolve) => {
34
+ this.roomWaiters.push(resolve);
35
+ });
36
+ }
37
+ close() {
38
+ this.isClosedNow = true;
39
+ this.wakeTaker();
40
+ this.wakeRoomWaiters();
41
+ }
42
+ fail(error) {
43
+ this.failure ??= error instanceof Error ? error : new GyroViewError("decode", "audio re-packaging failed", { cause: error });
44
+ this.close();
45
+ }
46
+ /**
47
+ * The consumer's side: the segments in order until the channel is closed and drained, then
48
+ * the producer's failure if it had one. Returning closes the channel at once, even while a
49
+ * segment is awaited, which then comes as the end. `onEnd` hears once of the end, however it
50
+ * came: the producer's resources may go.
51
+ */
52
+ segments(onEnd = doNothing) {
53
+ return new SegmentReading({
54
+ take: () => this.take(),
55
+ close: () => {
56
+ this.close();
57
+ },
58
+ onEnd
59
+ });
60
+ }
61
+ /**
62
+ * The next segment; undefined once closed and drained; the producer's failure, if it had one.
63
+ */
64
+ async take() {
65
+ while (this.queue.length === 0 && !this.isClosedNow) await this.nextPush();
66
+ const next = this.queue.shift();
67
+ if (next) {
68
+ this.wakeRoomWaiters();
69
+ return next;
70
+ }
71
+ if (this.failure) throw this.failure;
72
+ }
73
+ nextPush() {
74
+ ensureInvariant(this.takeWaiter === void 0, "a segment channel has one consumer");
75
+ return new Promise((resolve) => {
76
+ this.takeWaiter = resolve;
77
+ });
78
+ }
79
+ wakeTaker() {
80
+ const waiter = this.takeWaiter;
81
+ this.takeWaiter = void 0;
82
+ waiter?.();
83
+ }
84
+ wakeRoomWaiters() {
85
+ if (this.queue.length >= this.capacity && !this.isClosedNow) return;
86
+ const waiters = this.roomWaiters;
87
+ this.roomWaiters = [];
88
+ for (const resolve of waiters) resolve();
89
+ }
90
+ };
91
+ /**
92
+ * Iterates a channel's segments. A class, not a generator: a generator's return waits behind the
93
+ * segment it awaits, and the producer would re-package another fragment for nobody.
94
+ */
95
+ var SegmentReading = class {
96
+ parts;
97
+ hasEnded = false;
98
+ constructor(parts) {
99
+ this.parts = parts;
100
+ }
101
+ async next() {
102
+ if (this.hasEnded) return ITERATION_END;
103
+ try {
104
+ const segment = await this.parts.take();
105
+ return segment === void 0 || this.wasEnded() ? this.end() : {
106
+ done: false,
107
+ value: segment
108
+ };
109
+ } catch (error) {
110
+ this.end();
111
+ throw error;
112
+ }
113
+ }
114
+ return() {
115
+ this.parts.close();
116
+ return Promise.resolve(this.end());
117
+ }
118
+ [Symbol.asyncIterator]() {
119
+ return this;
120
+ }
121
+ /**
122
+ * Asked afresh after the wait: the consumer may have returned meanwhile.
123
+ */
124
+ wasEnded() {
125
+ return this.hasEnded;
126
+ }
127
+ end() {
128
+ if (!this.hasEnded) this.parts.onEnd();
129
+ this.hasEnded = true;
130
+ return ITERATION_END;
131
+ }
132
+ };
133
+ function doNothing() {}
134
+ //#endregion
135
+ export { SegmentChannel };
@@ -0,0 +1,12 @@
1
+ //#region ../../packages/adapters/mediabunny/src/bufferSources.ts
2
+ /**
3
+ * A copy of a buffer source as a plain Uint8Array. Decoder descriptions are small; the copy keeps
4
+ * them independent of mediabunny's own buffers and never on shared memory. SharedArrayBuffer is
5
+ * not named, since browsers define it only under cross-origin isolation.
6
+ */
7
+ function copyOfBytes(source) {
8
+ const view = ArrayBuffer.isView(source) ? new Uint8Array(source.buffer, source.byteOffset, source.byteLength) : new Uint8Array(source);
9
+ return Uint8Array.from(view);
10
+ }
11
+ //#endregion
12
+ export { copyOfBytes };
@@ -0,0 +1,43 @@
1
+ import { hevcCodecStringOf } from "../../../core/src/domain/format/mp4/hevcCodecString.js";
2
+ import { copyOfBytes } from "./bufferSources.js";
3
+ //#region ../../packages/adapters/mediabunny/src/decoderConfigurations.ts
4
+ /**
5
+ * The sample entry types an HEVC track's codec string begins with (ISO/IEC 14496-15 §8.4.1,
6
+ * Annex E.3). An encrypted track's entry, `encv`, names its protection instead.
7
+ */
8
+ var HEVC_SAMPLE_ENTRY_TYPES = /* @__PURE__ */ new Set(["hvc1", "hev1"]);
9
+ /**
10
+ * A video track's codec string: mediabunny's, but for an HEVC track, whose codec mediabunny
11
+ * names from the configuration's header alone, the core's, which reads a blank header's SPS.
12
+ */
13
+ async function codecStringOf(track, config) {
14
+ const [codec, sampleEntryType] = await Promise.all([track.getCodec(), track.getInternalCodecId()]);
15
+ return codec === "hevc" && typeof sampleEntryType === "string" && HEVC_SAMPLE_ENTRY_TYPES.has(sampleEntryType) && config.description !== void 0 ? hevcCodecStringOf(sampleEntryType, copyOfBytes(config.description)) : config.codec;
16
+ }
17
+ /**
18
+ * A WebCodecs video decoder configuration in the core's terms; the codec string and the colour
19
+ * come from the track's description, the coded size from the track where the configuration
20
+ * leaves it out.
21
+ */
22
+ function videoConfigurationOf(config, description) {
23
+ return {
24
+ codec: description.codec,
25
+ codedWidth: config.codedWidth ?? description.codedWidth,
26
+ codedHeight: config.codedHeight ?? description.codedHeight,
27
+ description: config.description === void 0 ? void 0 : copyOfBytes(config.description),
28
+ colour: description.colour
29
+ };
30
+ }
31
+ /**
32
+ * A WebCodecs audio decoder configuration in the core's terms.
33
+ */
34
+ function audioConfigurationOf(config) {
35
+ return {
36
+ codec: config.codec,
37
+ sampleRate: config.sampleRate,
38
+ numberOfChannels: config.numberOfChannels,
39
+ description: config.description === void 0 ? void 0 : copyOfBytes(config.description)
40
+ };
41
+ }
42
+ //#endregion
43
+ export { audioConfigurationOf, codecStringOf, videoConfigurationOf };
@@ -0,0 +1,20 @@
1
+ import { COLOUR_PRIMARIES, MATRIX_COEFFICIENTS, TRANSFER_CHARACTERISTICS, namedOrUnspecified } from "../../../core/src/domain/colour/TrackColour.js";
2
+ //#region ../../packages/adapters/mediabunny/src/trackColour.ts
3
+ /**
4
+ * A track's colour in the core's terms, from the colour space mediabunny reads off its sample
5
+ * entry or, without a `colr` box, its SPS: a value the core does not name is unspecified.
6
+ */
7
+ function trackColourOf(colorSpace) {
8
+ return {
9
+ primaries: namedOrUnspecified(COLOUR_PRIMARIES, colorSpace?.primaries),
10
+ transfer: namedOrUnspecified(TRANSFER_CHARACTERISTICS, colorSpace?.transfer),
11
+ matrix: namedOrUnspecified(MATRIX_COEFFICIENTS, colorSpace?.matrix),
12
+ range: rangeOf(colorSpace?.fullRange)
13
+ };
14
+ }
15
+ function rangeOf(fullRange) {
16
+ if (fullRange === true) return "full";
17
+ return fullRange === false ? "limited" : "unspecified";
18
+ }
19
+ //#endregion
20
+ export { trackColourOf };
@@ -0,0 +1,138 @@
1
+ import { GyroViewError, isAbortError, messageOf } from "../../../core/src/shared/errors/GyroViewError.js";
2
+ import { seconds } from "../../../core/src/shared/units/time.js";
3
+ import { attachMediaSource, isMediaSourceTypeSupported, mediaSourceConstructor } from "./mediaSourceSupport.js";
4
+ import { SourceBufferFeeder } from "./SourceBufferFeeder.js";
5
+ //#region ../../packages/adapters/mse-audio/src/MediaSourceAudioClock.ts
6
+ /**
7
+ * PlaybackClock over an audio element fed through Media Source Extensions with the recording's
8
+ * own audio track, so the picture follows the sound and volume and mute are the element's.
9
+ * The element is borrowed from the host; disposing detaches the media source from it.
10
+ * See ADR 0007.
11
+ */
12
+ var MediaSourceAudioClock = class MediaSourceAudioClock {
13
+ element;
14
+ feeder;
15
+ attached;
16
+ /**
17
+ * The end the clock stands at since a seek there, the element left where it was.
18
+ */
19
+ standingEnd;
20
+ constructor(element, feeder, attached) {
21
+ this.element = element;
22
+ this.feeder = feeder;
23
+ this.attached = attached;
24
+ }
25
+ static isSupported(source) {
26
+ return isMediaSourceTypeSupported(source.mimeType);
27
+ }
28
+ /**
29
+ * Attaches a media source to the element and starts buffering from the beginning.
30
+ */
31
+ static async open(element, source) {
32
+ const mediaSourceClass = mediaSourceConstructor();
33
+ if (!mediaSourceClass?.isTypeSupported(source.mimeType)) throw new GyroViewError("codec-unsupported", `${source.mimeType} cannot play through Media Source Extensions here`);
34
+ const attached = await attachMediaSource(element, mediaSourceClass);
35
+ try {
36
+ const sourceBuffer = attached.mediaSource.addSourceBuffer(source.mimeType);
37
+ attached.mediaSource.duration = source.duration;
38
+ const feeder = new SourceBufferFeeder({
39
+ element,
40
+ mediaSource: attached.mediaSource,
41
+ sourceBuffer,
42
+ source
43
+ });
44
+ feeder.restartFrom(seconds(0));
45
+ return new MediaSourceAudioClock(element, feeder, attached);
46
+ } catch (error) {
47
+ attached.detach();
48
+ throw asClockFailure(error);
49
+ }
50
+ }
51
+ get currentTime() {
52
+ return this.standingEnd ?? seconds(this.element.currentTime);
53
+ }
54
+ /**
55
+ * Whoever paused the element (the session, media keys, an audio interruption): `play()` clears
56
+ * `paused` at once, so a start in flight counts as running.
57
+ */
58
+ get isRunning() {
59
+ return !this.element.paused;
60
+ }
61
+ /**
62
+ * Standing at the end since a seek there, or the element `ended`: it played to its end.
63
+ */
64
+ get hasEnded() {
65
+ return this.standingEnd !== void 0 || this.element.ended;
66
+ }
67
+ /**
68
+ * What the feeder met, or the element's own error: sound that buffered but would not decode,
69
+ * which stalls the element without the feeder ever hearing of it.
70
+ */
71
+ get failure() {
72
+ return this.feeder.failure ?? failureOfElement(this.element);
73
+ }
74
+ /**
75
+ * Resolves once playback has started. A `pause` that interrupts the start is not an error;
76
+ * the autoplay policy refusing to start is reported as `playback-blocked`. A clock at its end
77
+ * stays there: `play()` would play the element from the beginning, or from where a seek to the
78
+ * end left it, under the last picture.
79
+ */
80
+ async start() {
81
+ if (this.hasEnded) return;
82
+ try {
83
+ await this.element.play();
84
+ } catch (error) {
85
+ if (isAbortError(error)) return;
86
+ const isBlocked = isNamed(error, "NotAllowedError");
87
+ throw new GyroViewError(isBlocked ? "playback-blocked" : "decode", isBlocked ? "the browser refused to start audio playback; a user gesture is needed" : "audio playback failed to start", { cause: error });
88
+ }
89
+ }
90
+ pause() {
91
+ this.element.pause();
92
+ }
93
+ /**
94
+ * A seek to the end stands the clock there and leaves the element paused where it was: an
95
+ * element at its end has nothing left to play, and engines differ right at the end. WebKit on
96
+ * Linux, under load, fails an element whose seek to the end of its sound is still pending when
97
+ * the stream ends there (media error 4); macOS WebKit loses a seek just short of the end.
98
+ */
99
+ seek(time) {
100
+ const end = this.attached.mediaSource.duration;
101
+ if (time >= end) {
102
+ this.standAtEnd(seconds(end));
103
+ return;
104
+ }
105
+ this.standingEnd = void 0;
106
+ this.element.currentTime = time;
107
+ this.feeder.restartFrom(time);
108
+ }
109
+ dispose() {
110
+ this.feeder.dispose();
111
+ this.element.pause();
112
+ this.attached.detach();
113
+ }
114
+ standAtEnd(end) {
115
+ this.element.pause();
116
+ this.standingEnd = end;
117
+ }
118
+ };
119
+ function isNamed(error, name) {
120
+ return error instanceof Error && error.name === name;
121
+ }
122
+ function failureOfElement(element) {
123
+ const { error } = element;
124
+ if (error === null) return void 0;
125
+ const message = `the audio element failed (media error ${error.code})`;
126
+ return new GyroViewError("decode", message, { cause: error });
127
+ }
128
+ /**
129
+ * The media source's own exceptions cross the port as typed failures: a type it will not buffer
130
+ * is `codec-unsupported`, anything else `decode`.
131
+ */
132
+ function asClockFailure(error) {
133
+ if (error instanceof GyroViewError) return error;
134
+ const isUnsupported = isNamed(error, "NotSupportedError");
135
+ return new GyroViewError(isUnsupported ? "codec-unsupported" : "decode", `the audio element refused the recording's sound: ${messageOf(error)}`, { cause: error });
136
+ }
137
+ //#endregion
138
+ export { MediaSourceAudioClock };