UNPKG

rx-player

Version:
132 lines (122 loc) 3.92 kB
/** * Copyright 2015 CANAL+ Group * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import type { IMediaSource, ISourceBuffer, ISourceBufferList, } from "../../compat/browser_compatibility_types"; import { onRemoveSourceBuffers, onSourceOpen, onSourceBufferUpdate, } from "../../compat/event_listeners"; import log from "../../log"; import type { CancellationSignal } from "../../utils/task_canceller"; import TaskCanceller from "../../utils/task_canceller"; /** * Get "updating" SourceBuffers from a SourceBufferList. * @param {SourceBufferList} sourceBuffers * @returns {Array.<SourceBuffer>} */ function getUpdatingSourceBuffers(sourceBuffers: ISourceBufferList): ISourceBuffer[] { const updatingSourceBuffers: ISourceBuffer[] = []; for (let i = 0; i < sourceBuffers.length; i++) { const SourceBuffer = sourceBuffers[i]; if (SourceBuffer.updating) { updatingSourceBuffers.push(SourceBuffer); } } return updatingSourceBuffers; } /** * Trigger the `endOfStream` method of a MediaSource. * * If the MediaSource is ended/closed, do not call this method. * If SourceBuffers are updating, wait for them to be updated before closing * it. * @param {MediaSource} mediaSource * @param {Object} cancelSignal */ export default function triggerEndOfStream( mediaSource: IMediaSource, cancelSignal: CancellationSignal, ): void { log.debug("Init: Trying to call endOfStream"); if (mediaSource.readyState !== "open") { log.debug("Init: MediaSource not open, cancel endOfStream"); return; } const { sourceBuffers } = mediaSource; const updatingSourceBuffers = getUpdatingSourceBuffers(sourceBuffers); if (updatingSourceBuffers.length === 0) { log.info("Init: Triggering end of stream"); try { mediaSource.endOfStream(); } catch (err) { log.error( "Unable to call endOfStream", err instanceof Error ? err : new Error("Unknown error"), ); } return; } log.debug("Init: Waiting SourceBuffers to be updated before calling endOfStream."); const innerCanceller = new TaskCanceller(); innerCanceller.linkToSignal(cancelSignal); for (const sourceBuffer of updatingSourceBuffers) { onSourceBufferUpdate( sourceBuffer, () => { innerCanceller.cancel(); triggerEndOfStream(mediaSource, cancelSignal); }, innerCanceller.signal, ); } onRemoveSourceBuffers( sourceBuffers, () => { innerCanceller.cancel(); triggerEndOfStream(mediaSource, cancelSignal); }, innerCanceller.signal, ); } /** * Trigger the `endOfStream` method of a MediaSource each times it opens. * @see triggerEndOfStream * @param {MediaSource} mediaSource * @param {Object} cancelSignal */ export function maintainEndOfStream( mediaSource: IMediaSource, cancelSignal: CancellationSignal, ): void { let endOfStreamCanceller = new TaskCanceller(); endOfStreamCanceller.linkToSignal(cancelSignal); onSourceOpen( mediaSource, () => { log.debug("Init: MediaSource re-opened while end-of-stream is active"); endOfStreamCanceller.cancel(); endOfStreamCanceller = new TaskCanceller(); endOfStreamCanceller.linkToSignal(cancelSignal); triggerEndOfStream(mediaSource, endOfStreamCanceller.signal); }, cancelSignal, ); triggerEndOfStream(mediaSource, endOfStreamCanceller.signal); }