import Decimal from 'decimal.js'; import { AudioLoadedEvent, AudioPeakProcessorMessageEvent, AudioSwitchedEvent, AudioUpdatedEvent, HelpMenuGroup, MainAudioChangeEvent, MainAudioInputSoloMuteEvent, OmpAudioTrack, OmpAudioTrackCreateType, OmpNamedEvent, OmpNamedEventEventName, SidecarAudioChangeEvent, SidecarAudioCreateEvent, SidecarAudioInputSoloMuteEvent, SidecarAudioPeakProcessorMessageEvent, SidecarAudioRemoveEvent, SidecarAudiosChangeEvent, SidecarAudioVideoCurrentTimeBufferingEvent, SidecarAudioVolumeChangeEvent, SubtitlesCreateEvent, SubtitlesEvent, SubtitlesLoadedEvent, SubtitlesVttTrack, SyncTickEvent, ThumnbailVttUrlChangedEvent, VideoBufferingEvent, VideoDurationEvent, VideoEndedEvent, VideoErrorEvent, VideoFullscreenChangeEvent, VideoHelpMenuChangeEvent, VideoLoadedEvent, VideoLoadingEvent, VideoPlaybackRateEvent, VideoPlayEvent, VideoSafeZoneChangeEvent, VideoSeekedEvent, VideoSeekingEvent, VideoTimeChangeEvent, VideoWindowPlaybackStateChangeEvent, VolumeChangeEvent } from '../types'; import { BehaviorSubject, Observable, Subject } from 'rxjs'; import Hls from 'hls.js'; import { VideoControllerApi } from './video-controller-api'; import { AudioEffectBundle, AudioMeterStandard, BufferedTimespan, VideoKeyframe, VideoKeyframeOptions, MediaElementPlaybackState, OmpAudioRouterState, OmpAudioRoutingConnection, OmpAudioRoutingInputType, OmpMainAudioInputSoloMuteState, OmpMainAudioState, OmpSidecarAudioInputSoloMuteState, OmpSidecarAudioState, Video, VideoLoadOptions, VideoLoadOptionsInternal, VideoProtocol, VideoSafeZone, VideoWindowPlaybackState } from './model'; import { VideoDomControllerApi } from './video-dom-controller-api'; import { VideoLoader } from './video-loader'; import { OmpHlsConfig } from './video-hls-loader'; import { OmpAudioRouter } from './audio-router'; import { OmpAudioPeakProcessor } from './audio-peak-processor'; import { OmpAudioEffectFactory, OmpAudioEffectFilter, OmpAudioEffectParam, OmpAudioEffectsGraph, OmpAudioEffectsGraphDef } from '../audio'; import { MediaElementPlayback } from './media-element-playback'; import { SidecarAudioApi } from '../api/sidecar-audio-api'; import { OmpAudioEffectsGraphConnection, OmpAudioEffectsSlot } from '../audio/model'; export interface VideoControllerConfig { frameDurationSpillOverCorrection: number; audioPlayMode: 'multiple' | 'single'; hlsConfig: Partial; } export declare const VIDEO_CONTROLLER_CONFIG_DEFAULT: VideoControllerConfig; interface VideoFrameCallbackData { now: DOMHighResTimeStamp; metadata: VideoFrameCallbackMetadata; } export type SeekDirection = 'bw' | 'fw' | 'o'; export declare class VideoController implements VideoControllerApi { static readonly videoVolumeDefault: number; static readonly videoPlaybackRateDefault: number; static readonly videoMutedDefault: boolean; readonly onSyncTick$: Subject; readonly onVideoLoaded$: BehaviorSubject; readonly onVideoLoading$: Subject; readonly onAudioLoaded$: BehaviorSubject; readonly onAudioSwitched$: Subject; readonly onAudioUpdated$: Subject; readonly onSubtitlesLoaded$: BehaviorSubject; readonly onSubtitlesCreate$: Subject; readonly onSubtitlesRemove$: Subject; readonly onSubtitlesShow$: Subject; readonly onSubtitlesHide$: Subject; readonly onPlay$: Subject; readonly onPause$: Subject; readonly onVideoTimeChange$: Subject; readonly onSeeking$: Subject; readonly onSeeked$: Subject; readonly onBuffering$: Subject; readonly onEnded$: Subject; readonly onVideoError$: Subject; readonly onVolumeChange$: Subject; readonly onFullscreenChange$: Subject; readonly onVideoSafeZoneChange$: Subject; readonly onVideoWindowPlaybackStateChange$: Subject; readonly onHelpMenuChange$: Subject; readonly onPlaybackState$: Subject; readonly onPlaybackRateChange$: Subject; readonly onDurationChange$: Subject; readonly onThumbnailVttUrlChanged$: Subject; readonly onMainAudioChange$: BehaviorSubject; readonly onMainAudioPeakProcessorMessage$: Subject; readonly onMainAudioInputSoloMute$: BehaviorSubject; readonly onSidecarAudioCreate$: Subject; readonly onSidecarAudioLoaded$: Subject; readonly onSidecarAudioRemove$: Subject; readonly onSidecarAudioChange$: Subject; readonly onSidecarAudioVolumeChange$: Subject; readonly onSidecarAudioPeakProcessorMessage$: Subject; readonly onSidecarAudioInputSoloMute$: Subject; readonly onSidecarAudiosChange$: Subject; readonly onSidecarAudioVideoCurrentTimeBuffering$: Subject; readonly onAudioOutputVolumeChange$: Subject; readonly onActiveNamedEventStreamsChange$: Subject; readonly onNamedEvent$: Subject; protected readonly _config: VideoControllerConfig; protected readonly _videoDomController: VideoDomControllerApi; /** * Stream of data provided by videoElement.requestVideoFrameCallback() * @protected */ protected readonly _videoFrameCallback$: Subject; protected _videoLoader?: VideoLoader; protected _video?: Video; protected _videoLoadOptions?: VideoLoadOptions; protected _mediaElementPlayback?: MediaElementPlayback; protected _syncFrameNudgeTime: number; protected _syncFineFrameTolerancePercent: number; protected _syncLoopMaxIterations: number; protected _videoFrameCallbackHandle?: number; protected _videoStalledCheckIntervalMs: number; protected _videoStalledCheckLastCurrentTime?: number; protected _videoPausedSeekBufferingThresholdMs: number; protected _activeNamedEventStreams: OmpNamedEventEventName[]; protected _subtitlesTracks: Map; protected _activeSubtitlesTrack?: SubtitlesVttTrack; protected _audioTracks: Map; /** * Created in constructor * @protected */ protected _audioContext: AudioContext; protected _audioOutputNode: GainNode; protected _audioOutputMuted: boolean; protected _audioOutputVolume: number; protected _mediaElementAudioSourceNode?: MediaElementAudioSourceNode; /** * Created in constructor * @protected */ protected _mainAudioNode?: AudioNode; protected _mainAudioRouter?: OmpAudioRouter; protected _mainAudioPeakProcessor?: OmpAudioPeakProcessor; /** * Tracks main audio active state depending on {@link VideoControllerConfig.audioPlayMode}. If value is false, main audio is muted * @protected */ protected _mainAudioActive: boolean; protected _sidecarAudios: Map; /** * Audio node where all sidecar audios merge * @protected */ protected _sidecarAudiosOutputNode: GainNode; /** * Contains sidecar audio id's for sidecar audios that are buffering video current time (and are not ready for playback) * @protected */ protected _sidecarAudiosVideoCurrentTimeBuffering: Set; /** * Stores last video playback state {@link _mediaElementPlayback} before {@link _mediaElementPlayback.waitingSyncedMedia} changes to true * Used for restoring playback after {@link _mediaElementPlayback.waitingSyncedMedia} changes to false * @protected */ protected _waitingSyncedMediaLastPlaybackState: MediaElementPlaybackState | undefined; /** * Time synchronization worklet * @protected */ protected _syncWorklet?: AudioWorkletNode; protected _syncWorkletSource?: MediaElementAudioSourceNode; protected _blackMp4Url: string; protected _lastMainVolumeChangeEvent?: VolumeChangeEvent; /** * Volume tracking for Safari * @protected */ protected _lastProvidedMainVolumeHlsLoaderSafari?: number; /** * Mute tracking for Safari * @protected */ protected _lastProvidedMainMutedHlsLoaderSafari?: boolean; protected _thumbnailVttUrl?: string; protected _helpMenuGroups: HelpMenuGroup[]; /** * Source slot audio effects */ protected _sourceSlot: OmpAudioEffectsSlot; protected _sourceSlotEffectsGraph?: OmpAudioEffectsGraph; protected _isSourceSlotEffectAttaching: boolean; protected _destinationSlot: OmpAudioEffectsSlot; protected _destinationSlotEffectsGraph?: OmpAudioEffectsGraph; protected _isDestinationSlotEffectAttaching: boolean; /** * Circut breaker for all loaded video events * @protected */ protected _videoEventBreaker$: Subject; /** * Cancels previous unfinished seek operation if ie. new seek is requested * @protected */ protected _seekBreaker$: Subject; /** * Cancels previous unfinished pause operation * @protected */ protected _pausingBreaker$: Subject; /** * Cancels monitoring for AudioContext.resume() * @protected */ protected _audioContextResumeBreaker$: Subject; protected _destroyed$: Subject; constructor(config: Partial, videoDomController: VideoDomControllerApi); private isVideoHlsLoaderInSafari; /** * For DRM'd videos Firefox doesn't allow tampering with audio source before setting up keys inside